본문 바로가기
Programming/Spring

자바 코드를 이용한 설정

by TinKerBellBass 2017. 8. 19.
728x90
반응형

참고도서

초보 웹 개발자를 위한 스프링4 프로그래밍 입문
국내도서
저자 : 최범균
출판 : 가메출판사 2015.03.02
상세보기



1. @Configuration / @Bean

(1) 자바 기반 스프링 설정파일 설정

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
37
38
39
package spring;
 
// @Configuration -> 스프링 설정으로 사용되는 클래스라는 것을 알림 
@Configuration
public class JavaConfig{
 
    // @Bean -> 스프링 컨테이너가 생성할 빈 객체라는 것을 알림 
    // [@Bean] -> <bean [memberDao, 메소드명] -> id="memberDao"
    // [MemberDao, 메소드 반환 객체] -> class="spring.MemberDao" />
    // spring.MemberDao 클래스로부터 memberDao라는 이름의 인스턴스 객체를 생성 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        // memberDao() 메소드를 호출하고, 메소드로부터 의존 객체를 리턴받아 주입함
        // [MemberRegisterService(memberDao()), 생성자] -> <constructor-arg
        // [memberDao(), 메소드명] -> ref="memberDao" />
// MemberRegisterService 클래스에는 MemberDao 객체를 매개변수로 받는 생성자가 있어야 한다.
// private MemberDao memberDao;
// public MemberRegisterService(MemberDao memberDao){this.memberDao=memberDao;}
        return new MemberRegisterService(memberDao());
    }
 
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
 
    @Bean
    public MemberInfoPrinter infoPrinter(){
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
        // [infoPrinter.setMemberDao(memberDao());] setter -> <property 
        // [setMemberDao, setter 메소드명] -> name="memberDao"
        // [memberDao(), 주입할 객체를 생성하는 메소드명] -> ref="memberDao" />
        infoPrinter.setMemberDao(memberDao());
        infoPrinter.setPrinter(printer());
        return infoPrinter;
    }
}

cs


(2) 자바 설정 파일을 가지고 스프링 컨테이너 생성


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main{
 
    public static void main(String[] args){
        // XML 기반 설정 -> GenericXmlApplicationContext 클래스 사용
        // 자바 기반 설정 -> AnnotationConfigApplicationContext 사용
        // JavaConfig.class -> JavaConfig 클래스를 설정 파일로 사용
        ApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
 
        // "memberRegSvc" -> 자바 설정 파일의 메소드명
        // MemberRegisterService.class -> 빈 객체를 생성할 때 사용할 
        MemberRegisterService regSvc = ctx.getBean("memberRegSvc", MemberRegisterService.class);
    }
}
cs


(3) 자바 기반 설정의 동작 방식


생성자 MemberRegisterService(memberDao( )); 에서 호출하는 memberDao( ) 메소드가 반환하는 MemberDao 객체와

setter 메소드 infoPrinter.setMemberDao(memberDao( )); 에서 호출하는 memberDao( ) 메소드가 반환하는 MemberDao 객체는

같은 객체이다.


자바 기반 설정에서도 XML 설정과 마찬가지로 빈 객체는 기본적으로 싱글톤 범위를 가진다.

싱글톤 범위의 빈 객체를 만들기 위해 스프링은 설정 클래스를 상속받는 클래스를 만들고 새로운 객체를 생성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 자바 기반 설정 클래스를 상속받아 스프링이 만드는 클래스
 
public class SpringExtConfig extends JavaConfig{
 
    private MemberDao memberDaoBean;
 
    @Bean
    public MemberDao memberDao(){
        // memberDaoBean 이 null -> 처음 생성될 때
        // super.memberDao(); -> 상속하고 있는 자바 기반 설정 클래스로부터
        // MemberDao 객체를 생성해서 memberDaoBean 필드에 담는다
        if(memberDaoBean == null){
            memberDaoBean = super.memberDao();
        }
        // memberDaoBean 필드에 MemberDao 객체가 담겨 있으면 
        // 새로운 MemberDao 객체를 만들지 않고 기존에 생성되어 있는 객체를 반환
        // 즉 늘 같은 MemeberDao 객체가 반환됨 -> 
        return memberDaoBean;
    }
}
cs

  

스프링은 @Configuration 설정 클래스를 상속받아 새로운 클래스를 만들기 위해 CGLIB 이라는 기술을 사용하는데,

CGLIB 가 클래스를 상속받아 새로운 클래스를 생성할 수 있으려면 두 가지 조건을 충족해야 한다.

① 클래스가 final 이어사는 안 된다.

② 파라미터(매개변수)가 없는 기본 생성자를 제공해야 한다.

그러므로 @Configuration 어노테이션을 적용한 자바 설정 클래스도 두 조건을 충족해야 한다.


3. 자바 기반 설정에서의 자동 주입

자바 기반 설정에서는 자동주입 @Autoriwed 어노테이션을 사용하기 위해 
<context:annotation-config/> 설정을 추가할 필요가 없다.

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
37
38
39
40
41
public class MemberInfoPrinter{
 
    private MemberDao memDao;
    private MemberPrinter printer;
 
    // MemberDao 타입의 빈 객체를 찾아서 setMemberDao() 메소드의 매개변수에 자동 주입
    @Autowired
    public void setMemberDao(MemberDao memberDao){
        this.memDao = memberDao;
    }
 
    @Autowired
    public void setPrinter(MemberPrinter printer){
        this.printer = printer;
    }
}
 
 
public class JavaConfig{
 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
 
    @Bean
    public MemberInfoPrinter infoPrinter(){
        // MemberInfoPrinter 객체가 생성될 때, 
        // MemberInfoPrinter 클래스의 @Autowired 가 붙은 곳에서 자동 주입이 일어난다
        // 자동 주입에 의해 MemberInfoPrinter 객체는 MemberDao, MemberPrinter 객체를 필드로 가지고 생성된다. 
        // 자동 주입이 발생하기 때문에,
        // infoPrinter.setMemberDao(memberDao()), infoPrinter.setPrinter(printer()) 설정은 필요 없다.
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
        return infoPrinter;
    }
}
cs



주의해야할 점은 XML 기반 설정에서 @Autowired 어노테이션은 생성자, 필드, 메소드에서 사용 가능했다.

그러나 자바 기반 설정에서는 @Autowired 어노테이션이 붙은 필드, 메소드에는 자동 주입이 발생하지만

생성자에는 @Autowired  어노테이션을  붙여도 자동주입이 발생하지 않는다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean
public MemberRegisterService memberRegSvc(){
    // 자바 기반 설정 클래스에서 생성자를 이용해서 객체를 생성
    // 여기서 MemberDao 객체를 주입해야 하기 때문에 
    // MemberRegisterService 클래스의 생성자에서 자동 주입을 설정해도
    // 자동 주입된 MemberRegisterService 객체를 얻을 수 없다.
    // 즉, MemberRegisterService 클래스의 생성자에 @Autowired 어노테이션을 붙이고
    // return new MemberRegisterService(); 처럼 사용할 수 없다.
    return new MemberRegisterService(memberDao());
}
 
// XML 설정과 달리 자바 설정을 사용할 때는 스프링 컨테이너가 객체를 생성할 때
// 사용할 생성자를 결정할 수 없고, 따라서 생성자를 통한 의존 객체 자동 주입을
// 적용할 수 없는 것이다.
// XML 설정은 객체를 생성할 때 해당 클래스를 찾아가기 때문에 생성자를 통한
// 자동 주입이 가능하다.

cs



자동 주입은 @Autowired 어노테이션을 쓰지 않고 

@Configuration 클래스의 @Bean 메소드 파라미터를 통해서도 주입할 수 있다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class JavaConfig{
 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
 
    // 스프링 컨테이너느 infoPrinter 메소드에 설정되어 있는
    // MemberDao, MemberPrinter 타입 객체를 찾아서 자동 주입한다.
    @Bean
    public MemberInfoPrinter infoPrinter(MemberDao memDao, MemberPrinter memPrt){
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter();        
        infoPrinter.setMemberDao(memDao);
        infoPrinter.setPrinter(memPrt);
        return infoPrinter;
    }
}
cs


4. 두 개 이상의 클래스를 사용한 설정

(1) @Configuration 어노테이션이 붙은 클래스에서의 @Autowired 어노테이션 사용

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
37
38
39
@Configuration
public class ConfigPart1{
 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        return new MemberRegisterService(memberDao());
    }
}
 
 
@Configuration
public class ConfigPart2{
    
    // @Configuration 이 붙은 클래스에도 자동 주입을 사용할 수 있다.
    // ConfigPart2 클래스의 infoPrinter 메소드에 MemberDao 객체가 필요하지만
    // ConfigPart2 클래스에는 MemberDao 객체를 생성하는 코드가 없고, ConfigPart1 에 있다.
    // ConfigPart1 클래스에서 생성된 MemberDao 객체를 자동 주입해서 받아서
    // ConfigPart2 클래스의 infoPrinter 메소드에서 사용하고 있다.
    @Autoriwed
    private MemberDao memberDao;
    
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
 
    @Bean
    public MemberInfoPrinter infoPrinter(){
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter();        
        infoPrinter.setMemberDao(memberDao);
        infoPrinter.setPrinter(printer());
        return infoPrinter;
    }
}
cs



(2) @Configuration 클래스 주입 받아 의존 설정


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
37
38
39
40
41
42
43
44
45
46
@Configuration
public class ConfigPart1{
 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        return new MemberRegisterService(memberDao());
    }
}
 
 
@Configuration
public class ConfigPart2{
    
    // 또 다른 스프링 설정 파일인 ConfigPart1 객체를 통째로 자동 주입 받을 수 있다.     
    @Autoriwed
    private ConfigPart1 configPart1;
    
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
 
    @Bean
    public MemberInfoPrinter infoPrinter(){
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter(); 
        // 자동 주입된 ConfigPart1 객체를 통해서, ConfigPart1에 생성된 memberDao 객체를 가져온다       
        infoPrinter.setMemberDao(configPart1.memberDao);
        infoPrinter.setPrinter(printer());
        return infoPrinter;
    }
}
 
 
// 두 개 이상인 자바 기반 설정 파일 사용하기
public class MainTwoConfs{
 
    public static void main(String[] args){
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext(ConfigPart1.class, ConfigPart2.class);
    }
}
cs



(3) @Import 어노테이션 사용


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
37
38
39
40
41
42
43
44
45
46
47
48
49
@Configuration
public class ConfigPartSub{
    
    @Autoriwed
    private MemberDao memberDao;
    
    @Bean
    public MemberPrinter printer(){
        return new MemberPrinter();
    }
    @Bean
    public MemberInfoPrinter infoPrinter(){
        MemberInfoPrinter infoPrinter = new MemberInfoPrinter();                
        infoPrinter.setMemberDao(memberDao);
        infoPrinter.setPrinter(printer());
        return infoPrinter;
    }
}
 
 
// @Import 어노테이션을 사용해서 또 다른 설정 파일인 ConfigPartSub 클래스도
// 자바 기반 설정 파일로 사용하겠다고 알린다
// @Import(ConfigPartSub1.class, ConfigPartSub2.class) 처럼 여러 개 지정 가능
@Configuration
@Import(ConfigPartSub.class)
public class ConfigPartMain{
 
    @Bean
    public MemberDao memberDao(){
        return new MemberDao();
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        return new MemberRegisterService(memberDao());
    }
}
 
 
// 두 개 이상인 자바 기반 설정 파일 사용하기
public class MainTwoConfs{
 
    public static void main(String[] args){
        // ConfigPartMain.class 만 설정 파일로 지정해도 
        // @Import(ConfigPartSub.class) 어노테이션에 의해 ConfigPartSub 도 설정 된다.
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext(ConfigPartMain.class);
    }
}
cs


5. 자바 기반 설정과 XML 기반 설정의 혼합

(1) 자바 설정에서 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
34
35
36
37
38
39
<!-- XML 기반 설정 파일, sub-conf.xml -->
<bean id="memberDao" class="spring.MemberDao"/>
 
<bean id="infoPrinter" class="spring.MemberInfoPrinter">
    <property name="memberDao" ref="memberDao"/>
    <property name="printer" ref="memberPrinter"/>
</bean>
 
 
// 자바 기반 설정 파일
// XML 설정 파일을 임포트 할 때는 @ImportResource 어노테이션을 사용하면 된다
@Configuration
@ImportResource("classpath:sub-conf.xml")
public class JavaMainConf{
 
    @Autowired
    private MemberDao memberDao;    
 
    @Bean
    public MemberPrinter memberPrinter(){
        return new MemberPrinter();        
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        return new MemberRegisterService(memberDao);
    }
}
 
 
// 설정 파일 사용하기
public class MainTwoConfs{
 
    public static void main(String[] args){
        
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext(JavaMainConf.class);
    }
}
cs



(2) 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
34
35
36
37
38
39
40
41
42
43
44
<!-- XML 기반 설정 파일, main-conf.xml -->
<!-- XML 설정을 메인으로 사용할 때는 자바 설정 파일의 빈을 사용하기 위해 --> 
<!-- <context:annotation-config/> 을 설정해야 한다. -->
<context:annotation-config/>
 
<!-- @Configuration 이 붙은 JavaSubConf 클래스의 객체를 만들기 위해 빈 설정 --> 
<bean class="config.JavaSubConf"/>
 
<bean id="memberDao" class="spring.MemberDao"/>
 
<bean id="infoPrinter" class="spring.MemberInfoPrinter">
    <property name="memberDao" ref="memberDao"/>
    <property name="printer" ref="memberPrinter"/>
</bean>
 
 
// 자바 기반 설정 파일
@Configuration
public class JavaSubConf{
 
    @Autowired
    private MemberDao memberDao;    
 
    @Bean
    public MemberPrinter memberPrinter(){
        return new MemberPrinter();        
    }
 
    @Bean
    public MemberRegisterService memberRegSvc(){
        return new MemberRegisterService(memberDao);
    }
}
 
 
// 설정 파일 사용하기
public class MainTwoConfs{
 
    public static void main(String[] args){
        
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext("classpath:main-conf.xml");
    }
}
cs


728x90
반응형

'Programming > Spring' 카테고리의 다른 글

AOP 기초  (0) 2017.08.19
Bean 라이프 사이클과 범위  (0) 2017.08.19
의존 자동 주입  (0) 2017.08.18
Spring DI  (0) 2017.08.18
Maven / Spring 기본  (0) 2017.08.18

댓글