[Web] Spring Framework DI xml 파일로 설정하기

스프링 프레임워크를 이용하여 DI를 직접 사용해보자!

먼저 이클립스에서 Maven 프로젝트를 만든다. 아키타입은 quick type이었나 1.1로 설정해줬다.


위와 같은 폴더를 구성해준다.
메이븐 프로젝트를 만들면 기본으로 선택되는 jdk 버전이 1.5 낮은 버전으로 선택된다. 따라서 1.8 버전으로 바꿔준다.
pom.xml 파일에서 dependencies 태그 밑에 아래 코드를 추가해준다.
<build>
     <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
cs

파일을 저장하고 프로젝트를 업데이트 후 properties 메뉴에서 jdk 버전을 확인했을 때 1.8로 보인다면 설정이 잘 된것이다.

디렉토리에서 src/test/java 하위에 AppTest.java는 java unit test를 제공하는 파일이다. 우클릭후 run as에서 junit을 선택했을 때 초록 바가 아래에 나오면 정상적으로 실행된다는 뜻이다.

스프링을 사용하기 위해서 라이브러리 추가를 해야한다. 다시 pom.xml로 들어가서 properties 태그 안에 아래 코드를 추가한다.
<sping.version>4.3.26.RELEASE</sping.version>
cs
properties 태그 내에 넣는 내용들은 dependency 태그에서 사용해야 할 내용을 상수처럼 사용하기 위해 미리 선언한다고 생각하면 된다.
스프링 라이브러리 버전이 굉장히 많은데, 구글에 maeven spring context라고 검색하면 제일 위에 maven repository 사이트가 뜬다.
https://mvnrepository.com/artifact/org.springframework/spring-context
이 사이트로 들어가면 라이브러리 버전이 굉장히 많이 뜬다. 원하는 버전을 선택하면 dependency에 추가해야 할 코드가 나온다. 이것을 복사해서 붙여넣으면 된다.
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
cs
원래 코드를 붙여넣으면 version 부분에 버전이 명시되어있다. 이 값을 상수로 사용하기 위해 properties에 미리 선언해둔것인데, 이 부분이 아니더라도 나중에 spring 버전을 써둔 부분이 있고 이것을 수정해야 하는 상황이 있을 수 있기 때문에 상수로 지정해두고 수정을 편하게 하기위해 이렇게 사용한다.
파일을 저장하고 maven dependencies 를 눌러보면 spring 라이브러리들이 자동으로 불러와진 것을 볼 수 있다.



다음으로 src/main 경로에 resources 라는 폴더를 생성하고 '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="userBean" class="kr.or.connect.diexam01.UserBean"></bean>
</beans>
cs

xml 파일의 파일명은 다르게 해도 되지만 주로 applicationContext 라는 파일명을 주로 사용하기 때문에 이렇게 해주는게 좋다.
bean 태그에 사용할 객체들을 적어주면 된다. 이 xml파일이 불리면 여기 선언된 bean들은 모두 메모리에 올라가게 된다. 이제 이 파일을 이용해 bean을 불러오는 클래스를 생성한다.

'ApplicationContextExam01.java' 클래스
public class ApplicationContextExam01 {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        System.out.println("초기화 완료");
        UserBean userBean = (UserBean) ac.getBean("userBean");
        userBean.setName("soyoug");
        System.out.println(userBean.getName());
        UserBean userBean2 = (UserBean) ac.getBean("userBean");
        if (userBean == userBean2)
            System.out.println("same");
        // singleton 패턴을 사용하기 때문에 getBean으로 계속 새로운 객체를 만드는 게 아니라
        // 하나 만든 bean을 계속 사용하는 것이다.
        //
    }
}
cs

ApplicationContext 객체를 생성하는 메서드는 여러가지가 있고 이번에 쓴 것은 ClassPathXmlApplicationContext이다. main아래 resources 폴더에 xml파일을 넣어놓으면 프로젝트가 기본경로로 인식한다.

Spring 컨테이너가 관리하는 객체만을 bean 이라고 부른다. 개발자가 스스로 new 를 사용하여 생성한 객체는 bean이라고 할 수 없다. Spring은 bean을 생성할 때 기본적으로 singleton으로 생성한다.
싱글톤이란 메모리에 하나만 생성한다는 뜻이고 따라서 위의 예제를 실행해 보면 userBean과 userBean2가 같은 객체라고 출력된다.
싱글톤객체를 여러명이 사용할 경우 데이터가 원치않은 방향으로 변조되어 본래의 의미를 잃어버리게 되어 문제가 발생할 수 있으므로 필요에 따라 xml 파일에 bean 태그를 입력할 때 scope속성을 prototype으로 지정해두면 getBean 메소드를 통해 객체를 요청 할 때마다 새로운 객체를 생성/반환 하게 된다.
getBean() 은 무조건 Object를 반환하기 때문에 필요에 따라 형변환을 써주면 된다. 여기서는 (UserBean)을 사용!

다음은 xml 파일을 이용해 DI를 설정해본다.

Car , Engine 클래스가 있다고 가정하자.
'Engine.java'
public class Engine {
    public Engine() {
        System.out.println("Engine생성자");
    }
    public void exec() {
        System.out.println("엔진 동작합니다");
    }
}
cs
'Car.java'
public class Car {
    private Engine v8;
    public Car() {
        System.out.println("Car 생성자");
    }
    public void setEngine(Engine e) {
        this.v8 = e;
    }
    public void run() {
        System.out.println("엔진을 이용하여 달립니다.");
        v8.exec();
    }
    public static void main(String[] args) {
        // di 안 쓰는 경우
//        Engine e = new Engine();
//        Car c = new Car();
//        c.setEngine(e);
//        c.run();
    }
}
cs
주석으로 들어가있지만 스프링의 DI를 사용하지 않는 경우 개발자ㅏ가 직접 new로 객체를 생성해야 한다. 이런 동작을 그대로 di를 사용하여 구현해본다.
이전에 만든 resources 폴더의 applicationContext.xml에 bean을 추가한다.
    <bean id="e" class="kr.or.connect.diexam01.Engine"></bean>
    <bean id="c" class="kr.or.connect.diexam01.Car">
        <property name="engine" ref="e"></property>
    </bean>
cs

property는 보통 getter/setter로 사용된다. 위에서 만든 클래스 정의에서 car 클래스는 생성자로 Engine객체를 받는다. 따라서 spring의 bean 선언부에서도 이것을 명시해줘야 한다. Car 에 있던 setEngine(Engine e) {}메서드에서 set 뒤의 Engine부분을 소문자로 해서 써주고 위에 선언한 Engine bean의 id e를 쓰면 된다.
즉 아래 코드와 같은 내용이다.
Engine e = new Engine();
Car c = new Car();
c.setEngine(e);
cs

참고로 property name에서 Engine을 써줘도 동작하지만 ENGINE은 동작하지 않는다고 한다. property는 getter/setter에만 사용가능하고 Engine으로도 동작은 하지만 보편적으로 사용되는 규칙에 따라 써주는게 좋다.

테스트 해볼 새로운 클래스 ApplicationContextExam02.java.를 만든다.
public class ApplicationContextExam02 {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Car car = (Car) ac.getBean("c"); // 등록했던 bean아이디
        // engine 탑재한 car 객체가 만들어진것
        car.run();
    }
}
cs

실행해보면 이전에 사용자가 new 연산자로 만들어서 실행했을 때와 같은 출력결과가 나온다.



No comments:

Powered by Blogger.