Spring Setter DI

Setter Injection


  이전 예제는 messageRender객체는 messageProvider를 property로 갖는 구조였다. 이를 위해서 main클래스는 messageRender객체를 획득하고,messageProvider객체를 획득하여 messageRender에 messageProvider를 setting하여 주었다. Setter DI를 이용하면 보다 간편하게 이를 처리할 수 있다. main에서는 별도로 messageProvider를 생성하지 않아도 된다. Spring에서 messageRender객체를 생성할 때 property인 messageProvider를 자동으로 생성하여 주입하여준다. 때문에 별도의 messageProvider생성에 대한 소스코드는 불필요 함으로 의존성을 감소와 동시에 소스코드를 간결하게 작성할 수 있다. 



적용방법(xml) : 1번과 2번 둘 중 하나를 선택하여 적용하면 된다. 

1) <bean>태그 하위에 <property>를 지정
1
2
3
4
5
    <bean id="messageRender" name="" class"com.ljs.message.render.DefaultMessageRender">
        <property name="messageProvider">
            <ref bean="messageProviderBean"/>
        </property>
    </bean>
cs

2) <bean>태그에  p:propertyName-ref="beanID"를 추가(Spring 2.5 이상)
1
2
    <bean id="messageRender" name="" class"com.ljs.message.render.DefaultMessageRender"
        p:messageProvider-ref="messageProviderBean"/>


적용방법(Annotation) : @Autowired 혹은 @Resource(name="propertyName")

1) bean으로 관리 될 class에 @Service

1
2
3
@Service("messageProvider")
public class DefaultMessageProvider implements IMessageProvider {
...
cs


2) bean을 갖게 될 class setter 메소드에 @Autowired

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service("messageRender")
public class DefaultMessageRender implements IMessageRender {
 
    private IMessageProvider messageProvider;
    
    ...
    @Autowired
    @Override
    public void setMessageProvider(IMessageProvider provider) {
        this.messageProvider = provider;
    }
    ...
}
cs


    변수에 직접 @Autowired 하는 경우 setter 메소드도 정의할 필요가 없다.

1
2
3
4
5
6
7
8
@Service("messageRender")
public class DefaultMessageRender implements IMessageRender {
 
    @Autowired
    private IMessageProvider messageProvider;
    
...
}
cs


    혹은 @Resource

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service("messageRender")
public class DefaultMessageRender implements IMessageRender {
 
    private IMessageProvider messageProvider;
    
    ...
    @Resource(name="messageProvider")
    @Override
    public void setMessageProvider(IMessageProvider provider) {
        this.messageProvider = provider;
    }
    ...
}
cs

소스코드는 이전예제와 동일하기 때문에 달라지는 부분만 설명.



1. Spring XML 방식 Setter Injection



[main class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.ljs.message;
 
import org.springframework.context.support.GenericXmlApplicationContext;
 
import com.ljs.message.render.IMessageRender;
 
public class AppCtxTestMain {
 
    public static void main(String[] args) {
        
        // ApplicationContext 부트스트랩
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:META-INF/spring/app-context-xml.xml");
        ctx.refresh();
        // ApplicationContext로 부터 bean 획득
        IMessageRender      render = (IMessageRender) ctx.getBean("messageRender");
        
        /*
        IMessageProvider provider = (IMessageProvider) ctx.getBean("messageProvider");
        render.setMessageProvider(provider);
        */
        
        render.render();
        
    }
}
cs

Setter대상이 되는 DI 타겟 객체는 더이상 직접 생성할 필요가 없기 때문에 주석처리 하였다

class diaram을 보면 messageProvider와 의존성이 없어졌음을 알 수 있다.

 

[app-context-xml.xml]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8"?>
    
 
    <!-- ApplicationContext에서 관리 할 bean 정의 -->    
    <bean id="messageProviderBean" name="" class"com.ljs.message.provider.DefaultMessageProvider"/>
 
    <!-- 아래 두 가지 방법 중 1개 적용  -->    
    <!-- preperty 태그이용 --> 
    <bean id="messageRender" name="" class"com.ljs.message.render.DefaultMessageRender">
        <property name="messageProvider">
            <ref bean="messageProviderBean"/>
        </property>
    </bean>
 
    <!-- p 스키마 이용  
    <bean id="messageRender" name="" class= "com.ljs.message.render.DefaultMessageRender"
        p:messageProvider-ref="messageProviderBean"/>
     -->
    
</beans>
 
cs

bean태그 하위에 property태그를 삽입하여 messageProvider라는 property는 messageProviderBean이라는 id로 생성된 bean을 주입할 것을 명시하였다.

아래에 있는 p스키마를 이용하는 방법도 동일한 방법이다. 대신 p스키마 이용은 상단 네임스페이스에  xmlns:p 를 정의하여 주고 2.5버젼 이상에서 사용가능 하다. 



2. Spring Annotation 방식 Setter Injection


[app-context-annotation.xml]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
<?xml version="1.0" encoding="UTF-8"?>
    
    
    <!--스프링이 코드기반에서 의존성 요구조건을 스캔하게끔 세팅-->    
    <context:annotation-config/>
    
    <!--스프링이 코드에서 지정된 패키지(및 하위)아래에 있는 주입 가능한 빈을 모두 스캔하도록 세팅-->
    <context:component-scan base-package="com.ljs.message"/>
    
</beans>
 
cs

(변경사항 없음)

스프링이 스캔하여 bean을 관리할 component pakage를 지정하는 설정.


[class DefaultMessageProvider]

1
2
3
4
5
6
7
8
9
10
11
package com.ljs.message.provider;
 
import org.springframework.stereotype.Service;
 
@Service("messageProvider")
public class DefaultMessageProvider implements IMessageProvider {
    @Override
    public String getMessage() {
        return "Hell World!";
    }
}
cs


(변경사항 없음)

현재 클래스가 Sping에서 "messageProvider" 라는 id로 관리될 것을 명시하고,



[class DefaultMessageRender]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.ljs.message.render;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.ljs.message.provider.IMessageProvider;
 
@Service("messageRender")
public class DefaultMessageRender implements IMessageRender {
 
    private IMessageProvider messageProvider;
    
    @Override
    public void render() {
        if(messageProvider==null) {
            throw new RuntimeException("messageProvider can't be null");
        }
        
        else {
            System.out.print(messageProvider.getMessage());
        }
 
    }
 
    @Autowired
    @Override
    public void setMessageProvider(IMessageProvider provider) {
        this.messageProvider = provider;
    }
    
 
    @Override
    public IMessageProvider getMessageProvider() {
        return messageProvider;
    }
}
cs

(25라인 어노테이션 추가)

위에 정의한 bean을 has a로 가지고 있는 클래스 세터에 @Autowired 키워드를 추가하면 자동으로 객체를 생성하여 주입해 준다. 


[main class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.ljs.message;
 
import org.springframework.context.support.GenericXmlApplicationContext;
 
import com.ljs.message.provider.IMessageProvider;
import com.ljs.message.render.IMessageRender;
 
public class AppCtxTestMain {
 
    public static void main(String[] args) {
        
        // ApplicationContext 부트스트랩
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:META-INF/spring/app-context-annotation.xml");
        ctx.refresh();
        
        // ApplicationContext로 부터 bean 획득
        IMessageRender      render = (IMessageRender) ctx.getBean("messageRender");
        /*
        IMessageProvider provider = (IMessageProvider) ctx.getBean("messageProvider");
        render.setMessageProvider(provider);
        */
        render.render();
 
    }
}
cs



* 참고사항 


  • @Autowired는 setter 메소드에 붙여 @Service로 등록된 bean을 자동으로 injection처리
  • @Autowired를 property 선언에 바로 붙이는 경우 별도의 setter를 생성할 필요 없음
  • @Autowired대신에 @Resource(name="beanID")를 통해서 injection 가능. 
  • @Resource는 jSE와 JEE플랫폼 모두에서 사용할 수 있는 공통 자바 어노테이션을 정의하는 JSR-259표준 어노테이션 중 하나. @Autowired와 달리 미세한 DI조건을 제어할 수 있는 name 파라메터를 지원한다. 
  • @Resource를 사용하기 위해서는 jsr250.jar 파일을 lib에 추가하여야 한다.


다운로드


이 글을 공유하기

댓글

Email by JB FACTORY