1. Bean 등록 메타정보 구성 전략



1. XML 설정 단독 사용


- 모든 Bean을 명시적으로 XML에 등록하는 방법


- 생성되는 모든 Bean을 XML에서 확인할 수 있다는 장점이 있으나 Bean의 개수가 많아지면

XML 파일을 관리하기 번거로울 수 있다.


- 여러 개발자가 같은 설정파일을 공유해서 개발하다 보면 설정파일을 동시에 수정하다가 충돌이

일어나는 경우도 적지 않다.


- DI에 필요한 적절한 setter메서드 또는 constructor가 코드 내에 만드시 존재해야 한다.



1.1 XML 단독 사용방식을 사용한 코드


1. 인터페이스 Printer.java


1
2
3
4
5
package di.xml;
 
public interface Printer {
    public void print(String message);
}
cs



2. 인터페이스 구현 클래스1 StringPrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
package di.xml;
 
public class StringPrinter implements Printer {
    private StringBuffer buffer = new StringBuffer();
 
    public void print(String message) {
        this.buffer.append(message);
    }
 
    public String toString() {
        return this.buffer.toString();
    }
}
cs


3. 인터페이스 구현클래스2 ConsolePrinter.java


1
2
3
4
5
6
7
package di.xml;
 
public class ConsolePrinter implements Printer {
    public void print(String message) {
        System.out.println(message);
    }
}
cs


4. 모델 Hello.java


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
package di.xml;
 
import java.util.List;
 
public class Hello {
    String name;
    Printer printer;
    List<String> names;
 
    public Hello() {
        System.out.println("Hello Default Constructor Called..");
    }
 
    public Hello(String name, Printer printer) {
        this.name = name;
        this.printer = printer;
    }
 
    public List<String> getNames() {
        return this.names;
    }
 
    public void setNames(List<String> list) {
        this.names = list;
    }
 
    public void setName(String name) {
        System.out.println("setName() called " + name);
        this.name = name;
    }
 
    public void setPrinter(Printer printer) {
        System.out.println("setPrinter() called " + printer.getClass().getName());
        this.printer = printer;
    }
 
    public String sayHello() {
        return "Hello " + name;
    }
 
    public void print() {
        this.printer.print(sayHello());
    }
}
cs



5. DI를 위한 bean.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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
    <!-- StringPrinter 클래스를 bean으로 등록 -->
    <bean id="stringPrinter" class="di.xml.StringPrinter"/>
    <!-- Console.Printer 클래스를 bean으로 등록 -->
    <bean id="consolePrinter" class="di.xml.ConsolePrinter"/>
    
    <!-- setter injection -->
    <!-- Hello 클래스를 bean으로 등록 -->
    <bean id="helloBean" class="di.xml.Hello" scope="singleton">
        <property name="name" value="상현"/>
        <property name="printer" ref="stringPrinter"/>
    </bean>
    
    <!-- constructor injection -->
    <bean id="helloConstructor" class="di.xml.Hello">
        <!-- constructor injection  -->
        <constructor-arg index="0" value="생성자" />
        <constructor-arg index="1" ref="consolePrinter" />
    </bean>
</beans>
cs


6. 검증에 필요한 jUnit 사용 Test 클래스 HelloBeanTest.java


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
package di.xml.test;
 
import org.junit.Assert;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
 
import di.xml.Hello;
import di.xml.Printer;
 
public class HelloBeanTest {
    @Test
    public void hellobean() {
        // 1. Spring Container 생성
        BeanFactory factory = 
                new GenericXmlApplicationContext("config/beans.xml");
        // 2. Bean 을 요청
        Hello helloBean = (Hello)factory.getBean("helloBean");
        Hello helloBean2 = factory.getBean("helloBean",Hello.class);
        
        // 주소 비교
        Assert.assertSame(helloBean, helloBean2);
        assertSame(helloBean, helloBean2);
        
        // 값 비교
        // name변수 값이 잘 주입되었는지 확인 가능`
        assertEquals("Hello 상현", helloBean.sayHello());
        
        // printer 변수 잘 주입 되었는지 확인
        helloBean.print();
        Printer printer = factory.getBean("stringPrinter", Printer.class);
        assertEquals("Hello 상현", printer.toString());
    }
}
cs


결과 : 







2. 어노테이션과 XML 설정 혼용해서 사용


- Bean으로 사용될 클래스에 특별한 어노테이션(Annotation)을 부여해주면 이런 클래스를 자동으로 찾아서 Bean으로 등록한다.


- @Component 어노테이션이 선언된 클래스를 자동으로 찾아서 Bean으로 등록해주는 방식을 

빈 스캐닝(Bean Scanning)을 통한 자동인식 Bean 등록기능이라고 한다.


- 어노테이션을 부여하고 자동 스캔으로 Bean을 등록 하면 XML문서 생성과 관리에 따른 수고를 덜어주고

개발속도를 향상 시킬수 있다.


- 애플리케이션에 등록될 Bean이 어떤것들이 있고, 의존관계가 어떻게 되는지를 한눈에 파악할수 없다는 단점이 있다.



2.1 어노테이션과 XML 혼용방식을 사용한 코드



1. 인터페이스 Printer.java


1
2
3
4
5
package di.annotation;
 
public interface Printer {
    public void print(String message);
}
cs


2. 인터페이스 구현 클래스1 StringPrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package di.annotation;
 
import org.springframework.stereotype.Component;
 
@Component
public class StringPrinter implements Printer {
    private StringBuffer buffer = new StringBuffer();
 
    public void print(String message) {
        this.buffer.append(message);
    }
 
    public String toString() {
        return this.buffer.toString();
    }
}
cs


3. 인터페이스 구현클래스2 ConsolePrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package di.annotation;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/*
 * @Component 의 default 값은 consolePrinter
 */
@Component("consolePrinter")
@Scope("singleton")
public class ConsolePrinter implements Printer {
    public void print(String message) {
        System.out.println(message);
    }
}
cs


4. 기본생성자와 setter메소드를 뺀 모델 Hello.java


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
50
51
52
53
54
55
56
57
package di.annotation;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
@Component("helloA")
public class Hello {
    String name;
    Printer printer;
    List<String> names;
 
    public Hello() {
        System.out.println("Hello Default Constructor Called..");
    }
 
//    public Hello(String name, Printer printer) {
//        this.name = name;
//        this.printer = printer;
//    }
    
    // 생성자 어노테이션
    @Autowired
    public Hello(@Value("어노테이션"String name, @Qualifier("consolePrinter") Printer printer) {
        this.name = name;
        this.printer = printer;
    }
 
    public List<String> getNames() {
        return this.names;
    }
 
    public void setNames(List<String> list) {
        this.names = list;
    }
 
//    public void setName(String name) {
//        System.out.println("setName() called " + name);
//        this.name = name;
//    }
//
//    public void setPrinter(Printer printer) {
//        System.out.println("setPrinter() called " + printer.getClass().getName());
//        this.printer = printer;
//    }
 
    public String sayHello() {
        return "Hello " + name;
    }
 
    public void print() {
        this.printer.print(sayHello());
    }
}
cs


5. DI를 위한 annot.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 
    <context:component-scan base-package="di.annotation" />
 
</beans>
cs



6. 검증에 필요한 jUnit 사용 Test 클래스 HelloBeanTest.java


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
package di.annotation.test;
 
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import di.annotation.Hello;
import di.annotation.Printer;
 
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:config/annot.xml")
public class HelloAnnotationTest {
    @Autowired
    Hello hello;
    
    @Autowired
    @Qualifier("stringPrinter")
    Printer printer;
    
    @Test 
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
    }
    
}
cs


결과







3. 어노테이션 설정 단독 사용


- @Configuration 어노테이션과 @Bean 어노테이션을 이용해서 스프링 컨테이너에 새로운 빈 객체를 제공할 수 있다.

- Spring 3.0 부터는 어노테이션을 이용한 Bean의 등록과 Bean 들 간의 연결설정을 자바코드 내부에 하므로

XML을 전혀 사용하지 않는다.



3.1 XML 안쓰는 방법 전략 - 1



1. @Bean어노테이션을 사용한 HelloJavaConfig.java


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 di.xml.config;
 
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import di.xml.ConsolePrinter;
import di.xml.Hello;
import di.xml.Printer;
import di.xml.StringPrinter;
 
 
//전략 3-1 xml 안쓰는 방법
 
@Configuration
public class HelloJavaConfig {
    
    @Bean
    public Hello hello() {
        Hello hello = new Hello();
        hello.setName("Java컨피그");
        hello.setPrinter(printer());
        return hello;
    }
    
    @Bean
    @Qualifier("stringPrinter")
    public Printer printer() {
        Printer printer = new StringPrinter();
        return printer;
    }
    
    @Bean
    @Qualifier("consolePrinter")
    public Printer cPrinter() {
        Printer printer = new ConsolePrinter();
        return printer;
    }
}
cs


2. AnnotationConfigContextLoader를 사용한 HelloJavaConfigTest.java


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
package di.xml.test;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
import di.xml.Hello;
import di.xml.Printer;
import di.xml.config.HelloJavaConfig;
 
// 전략 3의 1번째 방법
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=HelloJavaConfig.class, loader=AnnotationConfigContextLoader.class)
public class HelloJavaConfigTest {
    @Autowired
    Hello hello;
    
    @Autowired
    @Qualifier("stringPrinter")
    Printer printer;
    
    @Test
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
        System.out.println(printer.toString());
    }
}
cs



결과





3.2 XML 안쓰는 방법 전략 - 2



1. @ComponentScan을 사용한 HelloJavaConfig2.java


1
2
3
4
5
6
7
8
9
10
package di.annotation.config;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan(basePackages= {"di.annotation"})
public class HelloJavaConfig2 {
    
}
cs




2. AnnotationConfigContextLoader를 사용한 HelloJavaConfigTest2.java


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
package di.annotation.test;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
import di.annotation.Hello;
import di.annotation.config.HelloJavaConfig2;
 
 
// 전략 3의 2번째 방법
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=HelloJavaConfig2.class, loader=AnnotationConfigContextLoader.class)
public class HelloJavaConfig2Test {
    
    @Autowired
    Hello hello;
    
    @Test
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
    }
}
cs



결과





Bean 등록 전략 테스트 코드 :


MySpringJunit.zip




+ Recent posts