ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Framework 6.2 문서 읽고 이해하기 ... IOC Container (4)
    개발하면서/타인글보면서 2025. 3. 5. 08:05
    반응형

    Lazy 빈 인스턴스화 

    기본적으로 ApplicationContext는 초기화될 때 모든 빌은 eager 하게 생성하고 구성하도록 구현되어 있다.

    일반적으로 eager 한 생성은 괜찮은 방법인데 왜냐하면 실행 후 몇 시간 또는 며칠 뒤가 아니라 즉시 발견할 수 있기 때문이다.

    eager 한 생성이 필요하지 않은 경우 lazy 하게 만들 수 있는데 ApplicationContext가 초기화될 때가 아니라
    요청할 때 빈을 생성한다.

    lazy 빈을 설정하는 방법은 @Lazy annotation 또는 XML에 <bean />에 lazy-init 속성으로 제어할 수 있다.

    <bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
    
    <bean name="notLazy" class="com.something.AnotherBean"/>

     

    하지만 eager 한 빈이 lazy 한 빈의 의존관계가 있다면 ApplicationContext는 빈 생성을 위해 lazy 한 빈을 시작할 때 생성한다.

     

    메서드 주입

    컨테이너의 대부분의 빈은 싱글톤이다.

    싱글톤인 빈은 다른 싱글톤 빈 또는 non-싱글톤 빈과 협업을 할 수 있는데

    싱글톤 빈이 non-싱글톤 빈과 협업하려고 할 때 서로 다른 빈의 생명주기로 문제가 생긴다.

     

    싱글톤 빈 A가 non-싱글톤 Bygw 사용한다고 가정했을 때

    컨테이너는 A를 최초 한 번만 생성하므로 속성 설정은 딱 한 번만 할 수 있다.

    그리고 A에게 매번 새로운 인스턴스인 B를 제공할 수도 없다.

     

    해결책은 IoC를 포기하는 것이다.

    ApplicationContextAware 인터페이스를 구현하고 getBean("B")를 호출하는 방식으로
    A가 필요할 때마다 매번 B 인스턴스를 컨테이너에 요청하는 방식이다.

     

    Customizing the Nature of a Bean

    Method Injection

     

    메서드 주입 검색

    메서드 주입 검색은 컨테이너가 관리하는 빈에서 메서드를 오버라이드하고 
    다른 이름의 빈을 반환하는 기능이다.

    Spring Framework는 CGLIB 라이브러리가 생성한 bytecode를 이용해서
    메서도 오버라이드한 하위 클래스를 동적으로 생성하는 방식으로 메서드 주입을 구현했다.

    동적 하위 클래스 생성방식을 사용하기 위해서는 class와 오버라이드한 메서드 모두 final이면 안된다.
    해당 클래스를 유닛테스트 하려면 abstract를 stub 해줘야 한다. (구현해줘야 한다.)
    마지막으로 메서드 주입 검색은 factory 메서드와 같이 동작하지 않으면
    특히 configuration 클래스의 @Bean 메서드와 함께 동작하지 않는다.
    왜냐하면 컨테이너가 인스턴스 생성을(앞에서 말한 B) 담당하지 않아, 하위 클래스를 만들 수 없기 때문이다.

     

    package fiona.apple;
    
    // no more Spring imports!
    
    public abstract class CommandManager {
    
    	public Object process(Object commandState) {
    		// grab a new instance of the appropriate Command interface
    		Command command = createCommand();
    		// set the state on the (hopefully brand new) Command instance
    		command.setState(commandState);
    		return command.execute();
    	}
    
    	// okay... but where is the implementation of this method?
    	protected abstract Command createCommand();
    }

     

    <!-- a stateful bean deployed as a prototype (non-singleton) -->
    <bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    	<!-- inject dependencies here as required -->
    </bean>
    
    <!-- commandManager uses myCommand prototype bean -->
    <bean id="commandManager" class="fiona.apple.CommandManager">
    	<lookup-method name="createCommand" bean="myCommand"/>
    </bean>

     

    또는 abstract 메서드에 @Lookup annotation을 이용하는 방법도 있다.

     

    빈 Scope

    빈 정의를 만들 때 XML이나 Annotation 등의 방법으로 실제 인스턴스를 만드는 레시피를 적는다.

    이 레시피라는 개념은 중요한데 Java class처럼 하나의 레시피로 많은 인스턴스를 만든다는 걸 의미하기 때문이다.

     

    다양한 의존성이나 설정값을 제어하는 것 외에도 빈 정의의 Scope(범위)도 제어할 수 있다.

    Scope은 굉장히 강력하고 유연한데 Java class에서 Scope을 선택하는 게 아니라 설정으로 선택할 수 있다.

     

    빈은 여러 Scope 중 하나를 선택할 수 있다.

    Spring Framework는 총 6개의 Scope을 지원하는데 그중 4개는 web-aware ApplicationContext을 사용할 때만 가능하다.

    6개 외에도 사용자가 직접 자신만의 Scope을 만들 수도 있다.

    Scope Description
    singleton (Default) Spring IoC 컨테이너마다 한개의 빈 정의는 한개의 인스턴스로 Scope을 지정한다.
    prototype 한개의 빈 정의를 임의 개수의 인스턴스로 Scope을 지정한다.
    request 한개의 빈 정의를 한개의 HTTP 요청 라이프 사이클에 적용한다.
    각 HTTP 요청은 하나의 빈 정의에서 생성된 인스턴스를 가지고 있다.
    (web-are ApplicationContext)
    session 한개의 빈 정의를 HTTP 세션 라이프사이클에 적용한다.
    (web-are ApplicationContext)
    application 한개의 빈 정의를 ServletContext 라이프사이클에 적용한다.
    (web-are ApplicationContext)
    websocket 한개의 빈 정의를 WebSocket 라이프사이클에 적용한다.
    (web-are ApplicationContext)

     

    Singleton Scope

    singleton 빈의 인스턴스는 단 하나만 관리되며, 빈 정의에 있는 ID와 동일한 모든 요청은 특정 빈의 인스턴스를 반환한다.

    해당 인스턴스는 singleton 빈 캐시에 저장되고, 해당 빈 이름의 요청이 있을 때마다 캐시에 있는 객체를 반환한다.

    Spring의 singleton 빈 개념은 GoF책에 나온 singleton 패턴과는 다르다.

     

    GoF의 singleton은 Java Class를 하드코딩해서 Scope을 지정하고
    ClassLoader당 하나의 인스턴스만 생성되고 관리되도록 한다.


    Spring의 singleton은 컨테이너와 빈 단위로 잘 설명이 된다.
    하나의 Spring 컨테이너에서 특정 클래스의 하나의 빈을 정의했다면 Spring 컨테이너는 빈 정의에 의해 하나의 인스턴스만 생성한다.

     

    Prototype Scope

    non-singleton인 prototype은 해당빈에 요청이 올 때마다 빈 정의에 따라 새로운 인스턴스를 만들어 반환한다.

    원칙적으로 stateful 빈은 prototype으로 만들고 stateless 빈은 singleton으로 만든다.

    다른 Scope과는 다르게 prototype은 Spring이 온전하게 lifecycle을 관리하지 않는다.

    컨테이너는 프로토타입 객체를 인스턴스화하여 클라이언트에 전달까지만 하고 더 이상 관여하지 않는다.

     

    초기화 lifecycle 콜백 메서드는 모든 Scope의 객체들이 호출되지만

    해제 lifecyle 콜백 메서드의 경우 prototype Scope의 객체는 호출되지 않아서

    클라이언트 코드에서 직접 객체를 정리하고 리소스를 해제해야 한다.

    또는 해제가 필요한 bean들을 참조하는 custom 빈을 만드는 방법도 있다.

    Customizing the Nature of a Bean

     

    반응형

    댓글

Designed by Tistory.