티스토리 뷰

SPRING/정리

프로토타입(prototype) 빈

란텔 2016. 8. 19. 17:49

기본적으로 스프링에서 빈을 등록하면 싱글톤으로 만들어진다. 애플리케이션 컨텍스트 마다 빈은 한개씩만 만들어진다는 얘기다.

사용자의 요청이 있을 때마다 매번 관련 있는 빈을 새로 생성하는 것은 비효율적이기 때문이다.


싱글톤 빈은 의존성 주입(DI)을 하든지 ApplicationContext를 이용해서 빈을 불어와도 매번 같은 객체를 반환한다. 그런데 때로는 빈을 싱글톤이 아닌 하나의 빈으로 여러개의 객체를 만들어 사용해야 할 때가 있다.

그럴 때 프로토 타입 빈을 사용하는데 프로토타입 빈은 컨테이너에게 빈을 요청할 때마다 매번 새로운 객체를 생성하여 반환해준다.


싱글톤빈은 다음과 같이 애노테이션으로 설정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
@Scope("prototype")
public class UserInfo {
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
cs


빈 등록 방법인 @Bean과 함께 설정 할 수도 있다.

1
2
3
4
5
6
7
8
9
10
@Configuration("config")
public class ConfigurationBeanFactory {
    
    @Bean
    @Scope("prototype")
    public UserInfo UserInfo(){
        return new UserInfo();
    }
    
}
cs



컨텍스트 xml에서는 다음과 같이 설정

1
<bean class="dev.wedding.kr.test.UserInfo" scope="prototype"></bean>
cs



이렇게 하면 ApplicationContext타입을 이용하여 getBean메서드로 해당 빈을 가져올 때마다 매번 새로운 인스턴스가 생성되어 반환된다.

주의할 점 @Resource나 @Autowired, 수정자, 생성자 등을 이용해 의존관계 주입을 통해 직접 프로토타입 빈을 가져오려고 하면 싱글톤 빈처럼 동작하기 때문에 그런 방식을 사용해서는 안된다.


서로 다른 Contoller1과 Controller2에 DI(애노테이션 필드, 생성자, 수정자, 메서드)를 이용한 방식을 프로토타입 빈에 대하여 의존성 주입을 한다면 각 빈마다 새로 생성된 프로토타입 빈 객체가 반환되지만 Controller1에서만 매번 새로운 객체를 반환 받기를 원한다면 프로토타입 빈에 대하여 DI방식을 사용하면 안된다.

ApplicationContext타입의 getBean을 사용해야한다.




이제 위 코드처럼 정말로 매번 컨테이너에 getBean으로 빈을 요청할 때마다 다른 객체를 반환하는지 테스트 해보겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Autowired
ApplicationContext context;
 
 
@RequestMapping(value="/test3")
    public String test3(HttpServletRequest req, HttpServletResponse res){
        
        UserInfo info1 = (UserInfo)context.getBean(UserInfo.class);
        UserInfo info2 = (UserInfo)context.getBean(UserInfo.class);
        
        info1.setName("홍길동");
        System.out.println(info1.getName());
        System.out.println(info1.hashCode());
 
        System.out.println(info2.getName());
        System.out.println(info2.hashCode());
 
        
        return "test2";
    }
cs

ApplicationContext를 DI받고 getBean을 사용해서 컨테이너에 UserInfo타입의 호출을 두번 하였다.


결과는 다음과 같다.

홍길동

1676772747

null

91659248 

두 객체의 해시코드 값이 다르고, info1의 변경이 info2의 변경에 영향을 주지 않기 때문에 두 개의 UserInfo타입 객체가 서로다른 인스턴스를 가지고 있음을 알 수 있다.



만약 프로토타입 설정을 하지 않았다면 싱글톤 빈이 되기 때문에 다음과 같은 결과를 얻을 것이다.

홍길동

1577842472

홍길동

1577842472 



앞서 본 것처럼 스프링 프로토타입 빈을 사용하려면 ApplicationContext객체를 이용해서 getBean메서드로 컨테이너에 빈을 요청하는 방식으로 사용해야 한다고 했다.

가장 단순하고 사용하기도 별로 어렵지 않은 방식이지만 스프링의 컨테이너와 관련된 코드가 서비스 코드안에 위치하는 것이 스프링의 장점인 '기술이나 환경에 종속되지 않는 방식으로의 개발'과는 맞지 않기 때문에 다른 방식으로 프로토타입 빈을 사용할 수 있는 방법이 필요할 수 있다.


그래서 스프링은 ApplicationContext 같은 타입을 코드에서 사용해야 할 경우를 위해 그 외의 다양한 방식을 제공하고 있다.


  • ObjectFactory, ObjectFactoryCreatingFactoryBean 사용
  • ServiceLocatorFactoryBean 사용
  • Provider<T>

위 세가지 중에서 Provider 인터페이스에 대하여 알아본다. 이 방식이 제일 간단한 방법이다.
Provider는 코드내에 @Inject, @Autowired, @Resource 중의 하나를 이용해 DI되도록 지정해주기만 하면 스프링이 자동으로 Provider를 구현한 객체를 생성하여 주입해준다.

또한 Provider는 javax.inject 패키지 안에 포함된 javaEE 6표준 인터페이스이기 때문에 스프링 API를 사용하는 앞서 두 가지 방법보다 호환성이 좋다.

어쨋든 이렇게 Provider타입의 객체 A를 DI받고 프로토타입 빈을 A의 get메서드를 이용해 가져올 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Inject Provider<UserInfo> provider;
 
 
@RequestMapping(value="/test3")
public String test3(HttpServletRequest req, HttpServletResponse res){
        
        UserInfo info1 = provider.get();
        UserInfo info2 = provider.get();
        
        info1.setName("홍길동");
        System.out.println(info1.getName());
        System.out.println(info1.hashCode());
 
        System.out.println(info2.getName());
        System.out.println(info2.hashCode());
 
        return "test2";
}
cs
빈을 반환 할 때는 get()메서드를 이용한다.
Provider는 제네릭스 타입 변수를 지정하므로 선언시에 임의의 타입 T를 지정해 두면 나중에 꺼내 쓸 때 다시 타입 T로 형변환할 필요가 없다.



마지막으로 프로토타입 빈은 스프링 컨테이너가 초기에 빈의 생성 시에만 관여를한다. 하지만 컨테이너에서 일단 어떤 빈에 의존성 주입이 된 이후에는 더이상 스프링 컨테이너가 그 주입된 프로토타입 빈을 관리하지 않는다.

한번 만들어진 프로토타입 빈 객체는 더이상 컨테이너로부터 같은 빈을 가져올 방법이 없다.

컨테이너 타입을 이용해서 getBean메서드를 호출여 프로토타입 빈을 요청했다면, 그 요청한 코드로 인한 참조가 유지되는 만큼 프로토타입 빈이 유지될 것이다.


Comments
최근에 올라온 글
최근에 달린 댓글
TAG
more
Total
Today
Yesterday