Spring

[Spring] 스프링 DI를 이용한 객체 생성(2)

재담 2022. 2. 9. 00:10

이전 글 : https://jaedam.tistory.com/5

 

[Spring] 스프링 DI를 이용한 객체 생성(1)

DI란? DI는 Dependency Injection의 줄임말로서 의존성 주입이라고도 부른다. 스프링은 기본적으로 DI를 기반으로 동작하기 때문에 DI에 대한 이해가 필수이다. 여기서 말하는 의존(Dependency)이란 한 클래

jaedam.tistory.com

앞서 DI의 개념과 스프링 컨테이너 및 빈 객체를 설정하는 방식을 간략하게 살펴보았다.

이번 글에서는 스프링 컨테이너의 종류와 XML 파일의 각 태그에 대해서 살펴보자.

 

스프링 컨테이너 종류

스프링은 BeanFactory와 ApplicationContext의 두 가지 타입의 컨테이너를 제공한다. 이 중에서 BeanFactory 계열은 단순히 컨테이너에서 객체를 생성하고 DI를 처리해주는 기능만을 제공하기 때문에 거의 사용하지 않는다. 반면 ApplicationContext 계열은 트랜잭션 처리, 자바 코드 기반 스프링 설정, 어노테이션 빈 설정, 웹 개발, 메시지 처리 등 다양한 부가 기능을 제공하기 때문에 ApplicationContext 계열을 주로 사용한다.

 

다음은 실제로 사용되는 구현 클래스들이다.

  • GenericXmlApplicationContext : XML 파일을 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
  • AnnotationConfigApplicationContext : 자바 코드를 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
  • GenericGroovyApplicationContext : 그루비 언어로 작성된 설정 정보로 사용하는 스프링 컨테이너. 독립형 애플리케이션을 개발할 때 사용
  • XmlWebApplicationContext : XML 파일을 설정 정보로 사용하는 스프링 컨테이너. 웹 애플리케이션을 개발할 때 사용
  • AnnotationConfigWebApplicationContext : 자바 코드를 설정 정보로 사용하는 스프링 컨테이너. 웹 애플리케이션을 개발할 때 사용

이들 중 WebApplicationContext로 끝나는 두 개의 클래스는 코드에서 직접 사용할 일은 없으며, web.xml과 같은 웹 애플리케이션 설정 파일에서 간접적으로 사용하게 된다.

 

XML을 이용한 DI 설정

<bean> 태그 : 생성할 객체 지정

<bean id="sampleProject" class="[패키지경로].Project"></bean>

주요 속성은 id와 class인데, class 속성은 패키지 경로를 포함한 완전 클래스 이름이어야 한다. id 속성 값은 <bean> 스프링 빈 객체의 고유한 이름으로 사용한다.

AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
Project project = ctx.getBean("sampleProject", Project.class);

위 코드에서 getBean 메서드로 빈 객체를 구할 때에 사용되는 것이 id 속성이다. 만약 id 속성을 지정하지 않으면 

[패키지경로].Project#0과 같은 임의의 이름을 생성한다.

 

<constructor-arg> 태그 : 생성자 방식 설정

public class User {

    private String id;
    private String password;
    
    public User(String id, String password) {
        this.id = id;
        this.password = password;
    }
    
    // 이하 생략
    ...
}
<bean id="user" class="[패키지경로].User">
   <constructor-arg value="jaedam" />
   <constructor-arg value="qwer" />
</bean>

User 객체를 스프링 빈으로 설정하려면 생성자에 전달할 값을 설정해야 되는데 이때 사용되는 태그가 <constructor-arg> 태그이다. <constructor-arg> 태그는 생성자의 파라미터 개수만큼 지정해야 하고, <constructor-arg> 태그의 순서가 곧 전달될 파라미터의 순서가 된다. 즉 다음과 같이 객체를 생성하는 것과 비슷하다. (실제로는 자바의 리플렉션이라는 기능을 이용해서 생성한다.)

new User("jaedam", "qwer");

value 속성 대신 ref 속성을 사용할 수도 있다. ref 속성은 다른 빈 객체의 이름을 사용한다. 여기서 말하는 이름이란 위에서 설명한 <bean> 태그의 id 속성이다.

<bean id="userRepository" class="[패키지경로].UserRepository">
...
</bean>

<bean id="pwChangeSvc" class="[패키지경로].PasswordChangeService">
   <constructor-arg><ref bean="userRepository"/></constructor-arg>
</bean>

 

<property> 태그 : 프로퍼티 방식 설정

<bean id="mvnBuildRunner" class="[패키지경로].MavenBuildRunner">
   <property name="mavenPath">
      <value>c:\maven-3.8.4</value>
   </property>
</bean>

name 속성을 이용해서 프로퍼티 이름을 지정한다. <value> 태그나 value 속성, <ref> 태그나 ref 속성을 이용해서 값을 설정할 수 있다. <property> 태그를 사용하면 setPropertyName() 형식의 메서드를 이용해서 값을 설정한다. 위 설정은 다음과 같이 set 메서드를 이용한다. 이때 프로퍼티 이름의 첫 글자를 대문자로 변환한 이름을 사용해서 set 메서드를 선택한다.

setMavenPath("c:\maven-3.8.4");

 

<list>, <map>, <set> 태그 : List, Map, Set 타입의 컬렉션 설정

각각 <list>, <map>, <set> 태그를 사용한다. 먼저 <list> 태그를 보자.

<bean id="user1" class="[패키지경로].User">
   ...
</bean>

<bean id="user2" class="[패키지경로].User">
   ...
</bean>

<bean id="userRepository" class="[패키지경로].UserRepository">
   <property name="users">
      <list>
         <ref bean="user1" />
         <ref bean="user2" />
      </list>
   </property>
</bean>

위 설정은 users 프로퍼티에 원소로 user1 빈과 user2 빈 객체를 담은 List를 전달하도록 설정하고 있다. 즉, 다음 코드와 유사하다.

List<User> refs = new ArrayList<>();
refs.add(user1);
refs.add(user2);
userRepository.setUsers(refs);

리스트로 전달할 목록이 객체가 아니라 Integer나 String과 같은 타입이라면 <value> 태그를 사용해서 값 목록을 전달할 수도 있다.

 

다음은 <map> 태그를 보자.

<bean id="sensor1" class="[패키지경로].Sensor">
...
</bean>

<bean id="sensor2" class="[패키지경로].Sensor">
...
</bean>

<bean id="monitor" class="[패키지경로].Monitor">
   <property name="sensorMap">
      <map>
         <entry>
            <key>
               <value>frontDoor</value>
            </key>
            <ref bean="sensor1" />
         </entry>
         <entry key="backDoor" value-ref="sensor2" />
      </map>
   </property>
</bean>

<map> 태그는 <entry> 태그를 이용해서 (키, 값) 쌍 목록을 전달한다. 위 설정을 보면, 첫 번째 <entry> 태그는 키로 "frontDoor"를 사용하고, 값으로 sensor1 빈 객체를 사용한다. 두 번째 <entry> 태그는 키로 "backDoor"를 사용하고, 값으로는 sensor2 빈 객체를 사용한다. 두 번째 <entry> 태그는 value-ref 속성을 사용했는데, 이는 값으로 빈 객체를 사용한다는 의미이다.

 

다음은 <set> 태그를 보자.

<bean id="sensor2" class="[패키지경로].Sensor">
   <property name="agentCodes">
      <set>
         <value>200</value>
         <value>300</value>
      </set>
   </property>
</bean>

Set 타입의 프로퍼티를 설정하는 방법은 List 타입과 유사하다. 그냥 <list> 태그 대신, <set> 태그를 사용하면 된다.

 

<props>, <prop> 태그 : Properties 타입 값 설정

(키, 값) 쌍이 필요할 때 Map을 사용하지만, (키, 값) 쌍의 목록이 설정 값의 목록을 의미하는 경우에는 java.util.Properties를 사용하는 경우가 더 많다. Properties는 주로 다음과 같은 외부 설정 파일을 읽어올 때 사용된다.

# 서버 관련 설정
servers.list=10.20.30.40:9001, 10.20.30.40:9002
servers.timeout=3000

Sensor 클래스가 Properties 타입의 프로퍼티를 갖고 있다고 하자.

public class Sensor {
   private Properties additionalInfo;

   public void setAdditionalInfo(Properties additionalInfo) {
      this.additionalInfo = additionalInfo;
   }
   
   // 이하 생략
   ...
}

이때, additionalInfo 프로퍼티에 Properties 타입의 객체를 값으로 전달하고 싶다면, 아래 설정처럼 <props>, <prop> 태그를 이용하면 된다.

<bean id="sensor1" class="[패키지경로].Sensor">
   <property name="additionalInfo">
      <props>
         <prop key="threshold">1500</prop>
         <prop key="retry">3</prop>
      </props>
   </property>
</bean>

<prop> 태그의 key 속성은 Properties 객체의 프로퍼티 이름이며, <prop> 태그의 몸체 값은 해당 프로퍼티의 값이 된다. 즉, 위 설정은 다음과 같은 결과를 만들어낸다.

Properties prop = new Properties();
prop.setProperty("threshold", "1500");
prop.setProperty("retry", "3");
sensor1.setAdditionalInfo(prop);

다음과 같이 간결한 방법으로 Properties 타입의 프로퍼티를 설정할 수도 있다.

bean id="sensor2" class="[패키지경로].Sensor">
   <property name="additionalInfo">
      <value>
         threshold = 3000
         retry = 5
      </value>
   </property>
</bean>

 

다음글 : https://jaedam.tistory.com/9

 

[Spring] 스프링 DI를 이용한 객체 생성(3)

이전 글 : https://jaedam.tistory.com/7 [Spring] 스프링 DI를 이용한 객체 생성(2) 이전 글 : https://jaedam.tistory.com/5 [Spring] 스프링 DI를 이용한 객체 생성(1) DI란? DI는 Dependency Injection의 줄임..

jaedam.tistory.com


Reference

  • 웹 개발자를 위한 Spring 4.0 프로그래밍 (최범균 저)