스프링 DI

메이븐 아키타입 생성

화면에서 ↵는 다른 입력없이 엔터키만 누르라는 표시다. 엔터키만 누르면 디폴트 값이 선택된다.

C:\ Command Prompt
mvn archetype:generate

Choose a number or apply filter 
    (format: [groupId:]artifactId, case sensitive contains): 2005: ↵

Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8: ↵
Define value for property 'groupId': : net.java_school
Define value for property 'artifactId': : bank
Define value for property 'version':  1.0-SNAPSHOT: : ↵
Define value for property 'package':  net.java_school: : ↵
Confirm properties configuration:
groupId: net.java_school
artifactId: bank
version: 1.0-SNAPSHOT
package: net.java_school
 Y: : ↵

Choose a number or apply filter 에서 엔터키만 누르면 maven-archetype-quickstart 아키타입이 선택된다.
Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 에서도 엔터키만 눌러 가장 최신 버전을 선택한다.
화면에서 번호나 버전이 다를 수 있지만 상관없다.

테이블 생성 및 소스 코드 복사

자바은행 예제 테이블을 그대로 사용한다.
만약 테이블이 없다면 scott 계정으로 접속한 다음 테이블을 생성한다.

create table bankaccount (
  accountno varchar2(50),
  owner varchar2(20) not null,
  balance number,
  kind varchar2(10),
  constraint PK_BANKACCOUNT primary key(accountno),
  constraint CK_BANKACCOUNT_NORMAL 
    CHECK (balance >= CASE WHEN kind='NORMAL' THEN 0 END),
  constraint CK_BANKACCOUNT_KIND CHECK (kind in ('NORMAL', 'MINUS'))
);  
create table transaction (
  transactiondate timestamp,
  kind varchar2(10),
  amount number,
  balance number,
  accountno varchar2(50),
  constraint FK_TRANSACTION FOREIGN KEY(accountno)
    REFERENCES bankaccount(accountno)
);

입금이나 출금시 거래 테이블에 데이터를 인서트하는 트리거를 생성한다.

create or replace trigger bank_trigger
after insert or update of balance on bankaccount
for each row
begin
  if :new.balance > :old.balance then
    insert into transaction 
    values 
    (
      systimestamp,
      'DEPOSIT',
      :new.balance - :old.balance,
      :new.balance,
      :old.accountno
    );
  end if;
  if :new.balance < :old.balance then
    insert into transaction 
    values 
    (
      systimestamp,
      'WITHDRAW',
      :old.balance - :new.balance,
      :new.balance,
      :old.accountno
    );
  end if;
end;
/

https://github.com/kimjonghoon/JavaBank 자바 소스를 복사하여 프로젝트 루트 디렉터리 아래에 붙여넣는다.

src
└── main
    └── java
        └── net
            └── java_school
                └── bank
                    ├── Account.java
                    ├── Bank.java
                    ├── BankDao.java
                    ├── BankUi.java
                    ├── MyBank.java
                    ├── MyBankDao.java
                    └── Transaction.java

pom.xml 편집

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.java_school</groupId>
  <artifactId>bank</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>bank</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <spring.version>6.1.5</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.4.5</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6 -->
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.4</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>bank</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

빌드

C:\ Command Prompt
mvn clean compile

실행

C:\ Command Prompt
mvn exec:java -Dexec.mainClass=net.java_school.bank.BankUi

자바은행 예제를 스프링 예제로 변경

자바 소스에서 다음 부분을 수정한다.

Bank.java
public void setDao(BankDao dao);//추가
ShinahanBank.java
//private BankDao dao = new MyBankDao();

private BankDao dao;//추가

public void setDao(BankDao dao) {
  this.dao = dao;
}
BankUi.java
//..중간 생략..

import java.io.PrintStream;
import org.springframework.context.support.ClassPathXmlApplicationContext;

//..중간 생략..

//private Bank bank = new MyBank();
private Bank bank;

public void setBank(Bank bank) {
  this.bank = bank;
}

private PrintStream stream;

public void setStream(PrintStream stream) {
  this.stream = stream;
}

/* 
코드에서 System.out.println()을 stream.println(),
System.out.println()을 stream.println()으로 수정한다.
*/

//..중간 생략..

public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  BankUi ui = ctx.getBean(BankUi.class);
  ui.startWork();
  ctx.close();
}

src/main/resources 폴더를 만들고, 로깅의 logback.xml 파일을 복사해 resource 폴더에 붙여넣는다.
다음 applicationContext.xml 파일도 resource 폴더에 생성한다.

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bankUi" class="net.java_school.bank.BankUi">
        <property name="stream" value="#{T(System).out}" />
        <property name="bank" ref="myBank" />
    </bean>
    
    <bean id="myBank" class="net.java_school.bank.MyBank">
        <property name="dao" ref="myBankDao" />
    </bean>

    <bean id="myBankDao" class="net.java_school.bank.MyBankDao">
    </bean>
</beans>
src
└── main
    └── resources
        ├── logback.xml
        └── applicationContext.xml

컴파일

C:\ Command Prompt
mvn clean compile

실행

C:\ Command Prompt
mvn exec:java -Dexec.mainClass=net.java_school.bank.BankUi

이클립스 작업환경 구축

이클립스를 시작한다.(워크스페이스는 어디든 상관없다)
Project Explorer 뷰에서 마우스 오른쪽 버튼을 사용하여 컨텍스트 메뉴를 보이게 한다.
Import 메뉴를 사용해 자바은행 예제를 이클립스로 임포트한다.
컨텍스트 메뉴에서 Import
이클립스에서 메이븐 프로젝트 Import
이클립스와 pom.xml을 동기화한다.
Package Explorer에서 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼으로 컨텍스트 메뉴를 연다.
Maven, Update Project Configuration을 차례로 선택한다.

이후 진행하면서 pom.xml이 바뀌면 같은 방법으로 이클립스와 동기화한다.

JavaConfig

스프링이 발전하면서 빈 설정을 XML 파일이 아닌 자바 클래스로도 할 수 있게 되었다.
빈 설정 클래스는 @Configuration과 @Bean 어노테이션을 사용해 작성한다.
빈 설정 클래스에서 @Bean 어노테이션이 붙은 메소드 이름이 빈 객체가 된다.

applicationContext.xml 파일과 같은 내용의 빈 설정 클래스를 작성한다.

BankConfig.java
package net.java_school.bank;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BankConfig {
	
  @Bean
  public BankDao myBankDao() {
    return new MyBankDao();
  }
	
  @Bean
  public Bank myBank() {
    Bank bank = new MyBank();
    bank.setDao(myBankDao());
    return bank;
  }
	
  @Bean
  public BankUi bankUi() {
    BankUi ui = new BankUi();
    ui.setBank(myBank());
    ui.setStream(System.out);
    return ui;
  }
}

BankUi 클래스의 메인 메소드를 다음과 같이 수정한다.

BankUi.java
//import문 추가
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

//..중간 생략..

public static void main(String[] args) {
  //ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class);
  BankUi ui = ctx.getBean(BankUi.class);
  ui.startWork();
  ctx.close();
}

최종 소스: https://github.com/kimjonghoon/di

참고