[Spring] BeanFactory와 Autowiring의 이해

JUNYOUNG·2024년 3월 20일
0
post-thumbnail

지난 포스팅에서 Autowired 의 생명주기를 공부하면서 AutowireCapableBeanFactory 구조에 대해서 궁금해졌다. 다행히 인텔리제이에서 다이어그램을 제공해줘서 한 눈에 파악하기는 어렵지 않았다.

  • 초록실선: extend interface
  • 초록점선: implement
  • 파란실선: extend class


BeanFactory: 시작점

BeanFactory 인터페이스는 Spring 컨테이너의 가장 기본적인 형태입니다.
Bean 객체의 생성, 관리, 의존성 주입 등의 핵심적인 작업을 담당합니다.
개발자는 getBean 메서드를 사용하여 컨테이너로부터 Bean 인스턴스를 검색할 수 있고, @Autowired 어노테이션을 통한 의존성 주입도 이 인터페이스를 기반으로 합니다.

예제

1. Bean 정의

Main.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
        obj.getMessage();
    }
}
2. Configure Bean

HelloWorld.java

public class HelloWorld {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public void getMessage() {
        System.out.println("Your Message : " + message);
    }
}
3. BeanFactory를 사용하여 Bean 관리

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloWorld" class="HelloWorld">
        <property name="message" value="Hello Spring Framework!"/>
    </bean>

</beans>

AutowireCapableBeanFactory: 의존성 자동 연결

AutowireCapableBeanFactory 인터페이스는 자동 와이어링(autowiring) 기능을 추가합니다. 이는 Bean 간의 의존성을 Spring이 자동으로 연결해 주는 매커니즘을 의미합니다. @Autowired 어노테이션은 이 기능을 활용하여 선언된 필드나 메서드에 필요한 Bean을 자동으로 주입합니다.

주요 기능 및 사용법

  • Autowiring Modes: AutowireCapableBeanFactory 인터페이스는 AUTOWIRE_BY_NAME, AUTOWIRE_BY_TYPE, AUTOWIRE_CONSTRUCTORAUTOWIRE_NO를 포함하여 Autowiring Modes에 대한 여러 상수를 정의합니다.
    이 상수는 빈 속성이 이름, 유형, 생성자를 통해 또는 자동 연결 없이 자동 연결되어야 하는 방법을 나타냅니다.
  • Autowiring Bean 속성: autowireBeanProperties 메소드를 사용하면 주어진 Bean 인스턴스의 Bean 속성을 이름이나 유형별로 autowiring 할 수 있습니다.
    이 메소드는 annotation 기반 주입과 같은 인스턴스화 후 콜백을 적용하기 위해 AUTOWIRE_NO와 함께 호출될 수도 있습니다. 그러나 표준 BeanPostProcessors 콜백을 적용하거나 Bean의 추가 초기화를 수행하지 않습니다.

예제

AutowireCapableBeanFactory 인터페이스는 일반적인 애플리케이션 코드에서 일반적으로 사용되지 않지만,
기존 Bean 인스턴스를 수동으로 연결하고 채워야 하는 특정 시나리오에서 액세스하고 활용할 수 있습니다.
다음은 애플리케이션 컨텍스트 내에서 이 인터페이스에 액세스하고 사용하는 방법에 대한 개념적 예입니다.

import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;

public class MyBeanProcessor {
    private ApplicationContext applicationContext;

    // 생성자를 통해 스프링 애플리케이션 컨텍스트를 주입받음
    public MyBeanProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    // 외부에서 생성된 MyBean 객체의 의존성을 자동으로 주입하는 메서드
    public void processBean(MyBean myBean) {
        // 애플리케이션 컨텍스트로부터 AutowireCapableBeanFactory 인스턴스를 얻음
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();

        // MyBean 인스턴스의 프로퍼티에 대해 타입 기반으로 자동 와이어링을 수행
        beanFactory.autowireBeanProperties(myBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
        
        // 필요한 추가 처리...
    }
}

이 예에서 MyBeanProcessor는 Bean 인스턴스(MyBean)를 처리하는 사용자 정의 클래스입니다. AutowireCapableBeanFactory를 사용하여 유형별로 Bean 속성을 자동 연결합니다.
이 접근 방식은 Spring의 IoC 컨테이너 23에서 관리되지 않는 Bean을 수동으로 연결해야 하는 시나리오에서 유용합니다.

결론
AutowireCapableBeanFactory 인터페이스는 Bean 속성을 자동 연결하기 위한 고급 기능을 제공하며 특히 다른 프레임워크와의 통합 시나리오에 유용합니다. 일반적으로 애플리케이션 코드에서는 사용되지 않지만 필요할 때 기존 Bean 인스턴스를 수동으로 연결하고 채우는 강력한 방법을 제공합니다.
참고: Interface AutowireCaplbleBeanFactory

HierarchicalBeanFactory: 구조적인 계층성

HierarchicalBeanFactory 인터페이스는 부모-자식 관계를 가진 Bean 팩토리를 지원합니다. 이는 다른 Bean 팩토리와의 관계를 정립하여 계층적으로 Bean을 관리할 수 있는 기능을 제공합니다.
서로 다른 레이어를 명확하게 분리하여 각 레이어가 필요한 Bean에만 액세스할 수 있도록 하려는 복잡한 애플
리케이션에서 특히 유용합니다

import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.context.ApplicationContext;

public class MyApplication {
    public static void main(String[] args) {
        // Assuming parentContext and childContext are ApplicationContext instances
        ApplicationContext parentContext = ...; // Parent context (business layer)
        ApplicationContext childContext = ...; // Child context (presentation layer)

        // Set the parent context for the child context
        ((HierarchicalBeanFactory) childContext).setParentBeanFactory(parentContext);

        // Now, beans in childContext can access beans defined in parentContext
    }
}

이 예에서 parentContext는 비즈니스 계층을 나타내고 childContext는 프레젠테이션 계층을 나타냅니다.
childContext의 상위 Bean 팩토리를 parentContext로 설정하면 두 컨텍스트 사이에 계층적 관계가 설정됩니다.
이를 통해 하위 컨텍스트의 Bean이 상위 컨텍스트에 정의된 Bean에 액세스할 수 있으며 관심사 분리 원칙을 준수합니다.
스택오버플로우참고:why-did-juergen-hoeller-create-hierarchicalbeanfactory

SingletonBeanRegistry: Singleton의 보존

SingletonBeanRegistry는 Singleton Bean의 라이프사이클을 관리합니다.
Singleton 패턴은 특정 클래스의 인스턴스가 단 하나만 존재하도록 보장하는 디자인 패턴입니다.
이 인터페이스는 그러한 Singleton 인스턴스의 생성과 관리, 조회 기능을 정의합니다.

import org.springframework.beans.factory.config.SingletonBeanRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SingletonBeanDefinitionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        
        // Create an instance of the bean
        UserFactory userFactory = new DefaultUserFactory();
        
        // Obtain the SingletonBeanRegistry from the ApplicationContext
        SingletonBeanRegistry beanFactory = context.getBeanFactory();
        
        // Register the bean instance as a singleton with the given name
        beanFactory.registerSingleton("userFactory", userFactory);
        
        // Refresh the context to initialize the beans
        context.refresh();

        // Retrieve the bean from the context
        UserFactory userFactoryBean = context.getBean("userFactory", UserFactory.class);
        System.out.println(userFactory == userFactoryBean); // Should print true
        
        context.close();
    }
}
  1. UserFactory 인스턴스가 생성됩니다.
  2. SingletonBeanRegistry는 AnnotationConfigApplicationContext에서 가져옵니다.
  3. UserFactory 인스턴스는 RegisterSingleton을 사용하여 "userFactory"라는 이름의 싱글톤 Bean으로 등록됩니다.
  4. Bean을 초기화하기 위해 컨텍스트가 새로 고쳐집니다.
  5. 등록된 Bean은 컨텍스트에서 검색되고 원본 인스턴스와 비교되어 동일한 인스턴스가 반환되는지 확인합니다.

이 접근 방식을 사용하면 Spring 컨테이너에 싱글톤 Bean을 수동으로 등록할 수 있습니다.
이는 Spring이 아닌 구성 요소와 통합해야 하는 시나리오나 Spring의 종속성 주입 기능을 사용하지 않는 레거시 코드로 작업할 때 유용할 수 있습니다

ConfigurableBeanFactory는 Bean 팩토리의 설정을 커스터마이징할 수 있는 다양한 메서드를 제공합니다.
이를 통해 Bean의 생명주기 이벤트, 스코프, 프로퍼티 소스 등을 세밀하게 조정할 수 있습니다.

주요 특징

  • 계층적 지원: HierarchicalBeanFactory에서 상속되어 하위 팩토리가 상위 팩토리에 정의된 Bean에 액세스할 수 있는 Bean 팩토리의 계층적 구조를 허용합니다.
  • 싱글톤 레지스트리: SingletonBeanRegistry를 상속하여 공유 싱글톤 Bean 인스턴스에 대한 레지스트리를 제공합니다.
  • Bean 구성: 상위 Bean 팩토리 설정, 싱글톤 Bean 등록 및 Bean 정의 구성과 같은 Bean 팩토리 구성을 위한 방법을 제공합니다.

예제

ConfigurableBeanFactory는 애플리케이션 코드에서 직접 사용되지 않지만 해당 역할을 이해하면 Spring의 IoC 컨테이너 작동 방식을 이해하는 데 도움이 될 수 있습니다. 다음은 ConfigurableBeanFactory를 구현하는 Bean 팩토리와 상호작용하는 방법에 대한 개념적 예입니다.

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanFactoryExample {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        ConfigurableBeanFactory beanFactory = context.getBeanFactory();

		//싱글톤 Bean 등록
		MyBean myBean = new MyBean();
        beanFactory.registerSingleton("myBean", myBean);

        // XML 구성에 정의된 Bean에 액세스
        MyBean beanFromContext = (MyBean) context.getBean("myBeanFromXml");

        // Use the beans...
    }
}

주로 프레임워크 자체 내에서 사용하기 위한 것이며 Bean 팩토리 구성 방법에 대한 특수한 액세스를 제공합니다

Alias: AliasRegistry, SimpleAliasRegistry

AliasRegistry: Alias으로 더 큰 유연성 제공

AliasRegistry 인터페이스는 Bean의 Alias을 관리합니다.
이를 통해 개발자는 하나의 Bean에 대해 여러 개의 이름을 사용할 수 있으며, 이 기능은 @Autowired와 같은 메커니즘에서 Bean을 더 유연하게 참조할 수 있도록 합니다.

SimpleAliasRegistry: 별칭의 단순화

SimpleAliasRegistryAliasRegistry의 간단한 구현체로, Bean에 별칭을 제공하는 기본적인 메커니즘을 담당합니다.

주요 메서드

  • registerAlias(String name, String alias): 특정 이름에 대한 별칭을 등록합니다. 이를 통해 여러 이름으로 Bean을 참조할 수 있습니다.
  • removeAlias(String alias): 레지스트리에서 지정된 별칭을 제거합니다.
  • hasAlias(String name, String alias): 주어진 이름에 특정 별칭이 등록되어 있는지 확인합니다.
  • isAlias(String name): 주어진 이름이 별칭으로 정의되어 있는지 확인합니다.
  • getAliases(String name): 정의된 경우 지정된 이름에 대한 별칭을 반환합니다.
  • canonicalName(String name): 원시 이름을 결정하고 별칭을 표준 이름으로 확인합니다.

예제

다음은 SimpleAliasRegistry를 사용하여 Bean 이름의 별칭을 등록하고 확인하는 방법을 보여주는 예입니다.

import org.springframework.core.SimpleAliasRegistry;

public class AliasRegistryExample {
    public static void main(String[] args) {
        SimpleAliasRegistry registry = new SimpleAliasRegistry();
        
        // Register aliases
        registry.registerAlias("beanName", "alias1");
        registry.registerAlias("alias1", "alias2");
        
        // Check if an alias is registered
        boolean hasAlias = registry.hasAlias("beanName", "alias1");
        System.out.println("Has alias: " + hasAlias); // Should print true
        
        // Resolve an alias to its canonical name
        String canonicalName = registry.canonicalName("alias2");
        System.out.println("Canonical name: " + canonicalName); // Should print "beanName"
        
        // Remove an alias
        registry.removeAlias("alias1");
        
        // Check if an alias is still registered
        hasAlias = registry.hasAlias("beanName", "alias1");
        System.out.println("Has alias after removal: " + hasAlias); // Should print false
    }
}

SimpleAliasRegistry는 "beanName"이라는 Bean에 대한 별칭을 등록하는 데 사용됩니다.
별칭이 등록되었는지 확인하고, 별칭을 정식 이름으로 확인하고, 레지스트리에서 별칭을 제거하는 방법을 보여줍니다.
이를 통해 여러 이름으로 Bean을 참조하고 이러한 별칭을 표준 이름으로 쉽게 확인할 수 있습니다.
참고:Class SimpleAliasRegisty

DefaultSingletonBeanRegistry: Singleton 관리의 기본

DefaultSingletonBeanRegistrySingletonBeanRegistry를 구현하고, Singleton Bean을 관리하는 기능을 제공합니다.
이 클래스는 Singleton 인스턴스의 생성, 캐시, 관리를 담당하며, 전체 Spring 컨테이너의 효율성과 성능에 기여합니다

주요 특징

  • Singleton Bean 캐시: Singleton Bean 인스턴스들을 캐싱하여, 동일한 Bean 요청에 대해 항상 동일한 인스턴스를 반환합니다.
  • Singleton Bean 등록 및 관리: 새로운 Singleton Bean을 등록하고, 등록된 Bean을 조회하거나 제거하는 기능을 제공합니다.
  • Singleton Bean의 생명주기 콜백 지원: InitializingBean, DisposableBean 인터페이스 및 @PostConstruct, @PreDestroy 어노테이션과 같은 생명주기 콜백을 처리합니다.

FactoryBeanRegistrySupport: 복잡한 Bean의 지원

AbstractBeanFactoryBeanFactory 인터페이스의 추상 구현체로, Spring IoC 컨테이너의 핵심 기능을 제공합니다. 이 클래스는 Bean의 조회와 관리, 타입 체크, 이벤트 발송 등 다양한 기능을 포함하고 있습니다. 또한, BeanFactory에서 정의된 기본 작업을 수행하는 데 필요한 기본적인 인프라를 제공합니다.

주요 기능

  • FactoryBean 인스턴스 관리: FactoryBean을 통해 생성된 Bean 인스턴스를 관리하고 캐싱합니다.
  • Bean 생성 과정 커스터마이징: 개발자가 Bean의 생성 과정을 커스터마이징할 수 있게 해주며, 복잡한 초기화 또는 의존성 설정이 필요한 경우 유용합니다.
  • Bean 객체의 지연 로딩: 필요할 때까지 Bean의 생성을 지연시키고, 요청이 들어왔을 때 FactoryBean을 통해 Bean 인스턴스를 생성합니다.

AbstractBeanFactory: BeanFactory 구현체

주요 특징

  • Bean 인스턴스 조회: getBean 메서드를 통해 Bean 이름, 타입, 생성 인자 등 다양한 방법으로 Bean 인스턴스를 조회할 수 있습니다.
  • Bean 생명주기 관리: Bean의 생성부터 소멸까지의 생명주기를 관리하며, 초기화 후 및 소멸 전 콜백 인터페이스(InitializingBean, DisposableBean)를 지원합니다.
  • Bean 후처리기 지원: BeanPostProcessor를 통해 Bean 인스턴스화 후 추가적인 처리를 할 수 있게 해주며, 이는 AOP 프록시나 어노테이션 처리 등 다양한 확장 기능의 기반이 됩니다.

AbstractAutowireCapableBeanFactory: Autowiring의 구현

AbstractAutowireCapableBeanFactoryAutowireCapableBeanFactory 인터페이스의 추상 구현체로, 자동 와이어링 기능의 실제 구현을 담당합니다. 이 클래스는 Bean의 자동 연결을 지원하며, 생성자 주입, 세터 주입, 필드 주입 등 다양한 방식의 의존성 주입을 처리할 수 있습니다.

주요 특징

  • 자동 의존성 주입(Autowiring): Bean 사이의 의존성을 자동으로 주입합니다. 이는 설정 파일이나 어노테이션을 통해 선언된 의존성 정보를 기반으로 합니다.
  • Bean 인스턴스화: 지정된 Bean 정의에 따라 Bean 인스턴스를 생성합니다. BeanFactory에서 정의된 기본적인 인스턴스화 메커니즘 외에도, 커스텀 생성자 아규먼트 해석 및 처리를 지원합니다.
  • Bean 생명주기 관리: InitializingBeanDisposableBean 인터페이스를 구현한 Bean에 대한 초기화 후 및 소멸 전 콜백을 지원합니다. 또한, JSR-250의 @PostConstruct@PreDestroy 어노테이션도 지원합니다.
  • Bean 후처리기 지원: BeanPostProcessor를 사용하여 Bean 인스턴스화 및 의존성 주입 과정 후에 추가적인 처리를 할 수 있습니다. 이를 통해 Bean 초기화 이후의 커스텀 로직을 실행할 수 있습니다.
  • 메서드 오버라이딩 지원: XML 설정 파일에서 정의된 lookup-method 및 replaced-method 설정을 통해 런타임에 Bean의 메서드를 오버라이딩할 수 있습니다.
profile
Onward, Always Upward - 기록은 성장의 증거

0개의 댓글