본문 바로가기

SPRING

스프링 빈 등록 방법

스프링에선 객체의 생성과 사용 및 제거 등의 작업을 애플리케이션 소스코드 대신 독립된 컨테이너가 담당한다. 

이것을 IoC(제어역전)라고 부르며, 스프링 컨테이너를 IoC컨테이너라고 부른다.



  • IoC컨테이너의 기본적인 역할

코드를 대신해서 애플리케이션을 구현하는 오브젝트를 생성하고 관리하는 것

 


xml문서, 자바코드, 애노테이션 같은 리소스를 통해서 BeanDefinition 인터페이스 타입으로 변환되어져 이 타입을 IoC컨테이너가 활용한다.

BeanDefinition에는 bean하나를 만드는데 필요한 여러 가지 정보가 들어있다.

 

bean 등록 방법은 빈에 필요한 메타정보를 작성해서 컨테이너에 설정하면 된다.

가장 직접적인 방법은 BeanDefinition타입의 인터페이스를 구현하는 클래스를 직접 생성하는 것이다. 하지만 스프링을 확장하거나 스프링의 내부 동작을 세밀히 알고자 하는 것이 아니라면 이런 방법을 사용할 필요가 없다.

 



  •  bean 등록 방법 1 (xml 설정파일에 직접 등록)
<bean id="person" class="패키지명.Person" />
 
 
 
<bean id="group" class="패키지명.Gourp" >
   <property name="(set을뺀 메서드명)" >
      <ref bean="person" />
        또는
      <bean class="패키지명.Person" />
   </property>
        또는
   <property name="(set을뺀 메서드명)" ref="person" />
</bean>
cs

 

 


모든 빈을 일일이 컨테이너에 선언해 주는 방식이 귀찮고 관리하기 버거울 수 있다. 그래서 스프링에서는 클래스에 특정 애노테이션을 부여하고, 이 애노테이션을 부여한 클래스를 찾아서 자동으로 빈 등록을 해주는 방식이 있으며, 이런 방식을 ‘빈 스캐닝’ 이라 하고, 이런 작업을 담당하는 객체를 ‘빈 스캐너’라고 한다.

 

 

스프링의 빈 스캐너는 지정된 패키지 하위에 있는 모든 패키지를 대상으로 필터를 적용해서 빈 등록을 위한 클래스들을 찾는다. 이 필터에 적용되는 애노테이션을 stereotype 애노테이션 이라고 한다.

@Component, @Service, @Controller, @Repository, @Configuration 등등... 여러가지가 있다.


@Controller는 컨트롤러 클래스 계층에 @Service는 서비스 클래스 계층에, @Repository는 데이터 액세스 계층 즉, 코드와 데이터베이스간에 직접 연결되는 부분에서 사용한다. 그 외에 특정한 계층으로 분류하기 쉽지 않은 경우에는 @Component를 사용하는 것이 바람직하다.



  •  빈 등록 방법 2 (빈 스캐너가 스캔해서 스프링 컨테이너에 빈으로 등록될 클래스)
//@Component
//@Repository
//@Service
@Configuration("hello")
public class HelloVenus {
    private String name;
    
    public HelloVenus(){
        this("Venus!");
    }
    
    public HelloVenus(String name){
        this.name = name;
    }
    
    public String getName(){
        return name;
    }
    
}
cs

다음과 같이 스테레오타입 애노테이션을 사용하면 빈 스캔의 대상이 된다. 빈 스캐너는 기본적으로 클래스 이름을 빈의 아이디로 사용한다. 정확히는 클래스 이름의 첫 글자만 소문자로 바꾼 것을 사용한다.

위에서는 애노테이션 뒤에 괄호안에 빈의 이름을 명시해서 hello로 사용하고 있지만, 만약 명시하지 않았다면 위에서 말한대로 기본적으로 빈의 이름은 앞 글자만 소문자로 변경되어 helloVenus가 된다.




- 컨트롤러에서 빈을 가져올 수 있는지 테스트

    @RequestMapping(value="testScan")
    public String testScan(HttpServletRequest req){
        
        AnnotationConfigApplicationContext contxt = new AnnotationConfigApplicationContext("dev.wedding.kr.test");
        HelloVenus hv = (HelloVenus)contxt.getBean("hello");
        req.setAttribute("value", hv.getName());
        
        return "test";
    }
cs

AnnotationConfigApplicationContext클래스는 빈을 스캔할 수 있는 '빈 스캐너'의 역할을 한다.

실제 개발에서는 잘 쓰이지 않고 테스트시에 쓰인다고 한다.




위 처럼 AnnotationConfigApplicationContext을 직접 사용하지 않고 Spring 컨테이너 xml 설정파일 안에 스테레오 타입을 사용하는 클래스를 스캔해주는 '빈 스캐너'를 등록할 수 있다.

<context:component-scan base-package="dev.wedding.kr.test" />    
cs

다음과 같은 태그를 넣어 주기만 하면 dev.wedding.kr.test패키지 하위에 존재하는 빈 스캔 대상(스테레오 타입 내오테이션 클래스)을 빈 으로 등록해준다.



- 컨트롤러에서 테스트

    @Resource(name="hello")
    private HelloVenus hv;
    
    
    @RequestMapping(value="testScan")
    public String testScan(HttpServletRequest req){
        
        //AnnotationConfigApplicationContext contxt = new AnnotationConfigApplicationContext("dev.wedding.kr.test");
        //HelloVenus hv = (HelloVenus)contxt.getBean("helloVenus");
        req.setAttribute("value", hv.getName());
        
        return "test";
    }
cs





  • 빈 등록 방법 3 (자바 코드로 bean 등록하기)

스프링에서는 xml 설정파일이 아닌 자바코드를 통해 인스턴스를 생성하면서 의존성을 주입하는 방식으로 만들어진 객체를 빈으로 사용할 수 있는 방법을 제공한다.

방법은 클래스 레벨에서는 @Configuration을 붙이고, 메서드 레벨에서는 @Bean애노테이션을 붙이면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class ConfigurationBeanFactory {
    
    @Bean
    public CarInfoProvider kiaCar(){
        return new KiaCar();
    }
    
    @Bean
    public CarInfoProvider hyundaiCar(){
        return new HyundaiCar();
    }
    
}
cs

@Bean이 붙은 메서드명이 각각의 bean의 이름이 된다. 리턴되는 객체를 스프링 컨테이버가 빈으로 활용한다.



그럼 테스트 해보겠다.

의존성을 지키기 위해서 인터페이스를 활용해보겠다.



- KiaCar와 HyundaiCar를 구현하는 인터페이스

1
2
3
public interface CarInfoProvider{
    public void getPrintCarInfo();
}
cs


- CarInfoProvider의 구현체 (HyundaiCar생략)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class KiaCar implements CarInfoProvider {
    private ArrayList<String> modelName;
 
    public KiaCar() {
        modelName = new ArrayList<String>();
        modelName.add("k3");
        modelName.add("k5");
        modelName.add("k7");
        modelName.add("스포티지");
        modelName.add("카니발");
        modelName.add("카렌스");
        modelName.add("쏘렌토");
    }
 
    public void getPrintCarInfo() {
        for (String n : modelName) {
            System.out.print(n + ",");
        }
    }
 
}
cs



- 테스트할 컨트롤러 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Resource(name="kiaCar")
private CarInfoProvider kia;
    
@Autowired
ConfigurationBeanFactory factory; 
    
 @RequestMapping(value="beanFactoryTest")
 public String beanFactoryTest(HttpServletRequest req){
        
    kia.getPrintCarInfo();
        
    CarInfoProvider info1 = factory.kiaCar();
    CarInfoProvider info2 = factory.kiaCar();
    System.out.println("info1의 해시코드>>>>>" + info1.hashCode());
    System.out.println("info2의 해시코드>>>>>" + info2.hashCode());
        
    CarInfoProvider info3 = factory.hyundaiCar();
    CarInfoProvider info4 = factory.hyundaiCar();
    System.out.println("info3의 해시코드>>>>>" + info3.hashCode());
    System.out.println("info4의 해시코드>>>>>" + info4.hashCode());
        
    return "test";
 }
cs

@bean메서드에서 스프링 컨테이너가 메서드명을 bean의 이름으로 삼는다고 했다. 그렇기 때문에 1번 줄에서 의존관계에 있는 bean을 가져오기 위해 "kiaCar"라는 이름의 빈을 가져오도록 명시했다.


그리고 스프링은 @Bean이 붙은 메서드를 이용해서 bean을 만들 때, 싱글톤 빈이라면 한 개의 객체만 생성이되서 더이상 새로운 객체가 만들어지지 않도록 짜여져 있다.

즉, 위 코드의 12,13번째를 보면 새로운 인스턴스를 생성하는 kiaCar()라는 메서드가 있는데 이 메서드가 @Bean메서드라서 메서드를 반복적으로 실행했더라도 처음 만들어진 객체가 동일하게 계속 리턴된다. 



@Bean이 붙은 메서드가 기본적으로 싱글톤 빈이 되기 위해서는 꼭 @Configuration이 클래스 계층에 선언되어 있어야 한다.

만약 @Configuration이 없다면 싱글톤이 되지 않는다.

위 테스트 코드의 bean등록 클래스인 ConfigurationBeanFactory에서 @Configuration을 지우고, 다음과 같이 스프링 xml 설정파일에서 ConfigurationBeanFactory을 등록한다.

1
<bean id="factory" class="dev.wedding.kr.test.ConfigurationBeanFactory" />
cs

이와 같이 xml에 빈으로 등록하면 ConfigurationBeanFactory내부에 있는 @Bean메서드도 빈으로 자동 등록된다.

하지만 다시 테스트 컨트롤러 코드를 실행하면 각 객체의 해시코드는 다음과 같은 결과로 콘솔창에 보여준다,


싱글톤 빈이라면 info1과 info2가 같아야하고, info3와 info4가 같아야한다. 하지만 다르다. 그렇다는 말은 @Configuration과 @bean을 함께 사용하지 않으면 해당 빈은 싱글 톤 빈이 되지 못하고 매번 새로운 객체를 생성한다는 것이다.



출처: http://nkcnow.tistory.com/229 [CHOONIE'S PROGRAMMING NOTE]