java-school logo

Spring DI(종속객체 주입)

아래 글은 워크스페이스를 C:\java로 정하고 진행했다.

명령 프롬프트에서 메이븐 프로젝트 생성

명령 프롬프트로 C:\java로 이동한 후 다음 명령을 실행한다. (화면에서 ↵는 엔터키를 누르라는 표시다. 입력하지 않고 엔터키를 누르면 디폴트 값이 선택된다)

C:\ Command Prompt
C:\java>mvn archetype:generate

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

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
Choose a number: 6: ↵
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 계정으로 SQL*PLUS에 접속한 다음 테이블을 생성한다.

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)
);

scott 계정으로 SQL*PLUS에 접속한 상태에서, 입금이나 출금할 때 거래 테이블에 데이터를 인서트 하는 트리거를 만든다.

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;
/

자바은행에서 작성한 소스를 복사하여 다음 위치에 붙여넣는다.

C:\java\bank
   └── src
        └── main
             └── java
                  └── net
                       └── java_school
                               └── bank
                                        - Account.java
                                        - Bank.java
                                        - BankDao.java
                                        - BankUi.java
                                        - ShinhanBank.java
                                        - ShinhanBankDao.java
                                        - Transaction.java

오라클 JDBC 드라이버를 로컬 저장소에 설치하기

오라클 JDBC 드라이버는 메이븐 저장소에서 제공하지 않는다. 따라서 로컬에 설치된 오라클의 JDBC 드라이버 파일을 다음과 같이 로컬 저장소에 설치한 뒤 pom.xml에 의존성 설정해야 한다.

로컬 저장소에 오라클 JDBC 드라이버를 설치하는 방법하려면, 자신의 시스템에서 ojdbc6.jar 파일이 있는 디렉토리로 이동한 후, 명령 프롬프트에서 아래를 실행한다.

mvn install:install-file -Dfile=ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.2.0 -Dpackaging=jar

로컬 저장소에 저장된 정보대로 pom.xml에 다음과 같이 의존성을 추가한다.

<dependency>
	<groupId>com.oracle</groupId>
	<artifactId>ojdbc6</artifactId>
	<version>11.2.0.2.0</version>
</dependency>

pom.xml 파일을 아래와 같이 편집한다.

pom.xml
<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>
  <packaging>jar</packaging>

  <name>bank</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.3.9.RELEASE</spring.version>
    <jdk.version>1.8</jdk.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.2.0</version>
    </dependency>
  </dependencies>
  
  <build>
    <finalName>bank</finalName>
      <pluginManagement>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
              <source>${jdk.version}</source>
              <target>${jdk.version}</target>
              <compilerArgument></compilerArgument>
              <encoding>UTF-8</encoding>
            </configuration>
          </plugin>
        </plugins>
      </pluginManagement>
  </build>
  
</project>

메이븐 프로젝트로 성공적으로 변경했는지 빌드하고 실행해 본다.

C:\ Command Prompt
C:\java\bank>mvn clean compile

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

자바 소스 수정

자바 은행 예제를 스프링 예제로 변경해 보자. 자바 소스에서 다음 부분을 수정한다.

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

//추가
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 ShinhanBank();
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.print()을 stream.print()으로 수정한다.
*/

//..중간 생략..


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 파일을 아래 위치에 생성한다. applicationContext.xml 파일도 같은 위치에 생성한다.

C:\java\bank
   └── src
        └── main
             └── resources
                           - logback.xml
                           - applicationContext.xml
                     

appliactionContext.xml 파일을 다음과 같이 편집한다.

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="shinhanBank" />
    </bean>
    
    <bean id="shinhanBank" class="net.java_school.bank.ShinhanBank">
        <property name="dao" ref="shinhanBankDao" />
    </bean>

    <bean id="shinhanBankDao" class="net.java_school.bank.ShinhanBankDao">
    </bean>

</beans>

컴파일과 실행

C:\ Command Prompt
C:\java\bank>mvn clean compile

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

이클립스 작업환경 구축

이클립스를 시작한다. 워크스페이스는 어디든 상관없다. Project Explorer 뷰에서 마우스 오른쪽 버튼을 사용하여 컨텍스트 메뉴를 보이게 한다. Import를 사용하여 spring-bbs 프로젝트를 이클립스로 불러온다.
컨텍스트 메뉴에서 Import
이클립스에서 메이븐 프로젝트 Import
이클립스와 pom.xml을 동기화한다. Package Explorer에서 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼으로 컨텍스트 메뉴를 연다. Maven - Update Project Configuration을 차례로 선택한다. 이후 진행하면서 pom.xml이 바뀌면 같은 방법으로 이클립스와 동기화를 해주어야 한다.

JavaConfig 설정

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

빈 설정 클래스 테스트를 위해 applicationContext.xml에서 모든 설정을 주석 처리한다.

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="shinhanBank" />
    </bean>
    
    <bean id="shinhanBank" class="net.java_school.bank.ShinhanBank">
        <property name="dao" ref="shinhanBankDao" />
    </bean>

    <bean id="shinhanBankDao" class="net.java_school.bank.ShinhanBankDao">
    </bean>
-->
</beans>

다음과 같이 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 shinhanBankDao() {
		return new ShinhanBankDao();
	}
	
	@Bean
	public Bank shinhanBank() {
		Bank bank = new ShinhanBank();
		bank.setDao(shinhanBankDao());
		return bank;
	}
	
	@Bean
	public BankUi bankUi() {
		BankUi ui = new BankUi();
		ui.setBank(shinhanBank());
		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();
}

최종 소스

예제 다운로드