Annotation-based Container Configuration
• 설명: 이 방법은 주로 클래스나 메서드에 다양한 스프링 어노테이션을 사용하여 빈(bean)을 정의하고 구성하는 방식입니다. 주로 @Component, @Service, @Repository, @Controller와 같은 어노테이션을 사용해 클래스가 스프링 컨테이너에서 관리되는 빈임을 명시합니다.
• 예시: @Component로 클래스에 어노테이션을 붙이면 스프링이 자동으로 해당 클래스를 빈으로 등록합니다.
• 장점: 설정이 간단하고, 기존 코드에 최소한의 변경으로 스프링과 통합할 수 있습니다. 주로 “자동 빈 등록”이라고 불리며, 많은 설정을 자동으로 처리합니다.
• 단점: 세밀한 제어가 어렵고, 컴파일 시점에 설정을 확인할 수 없다는 점에서 디버깅이 복잡할 수 있습니다.
Java-based Container Configuration
• 설명: 이 방법은 @Configuration 어노테이션을 붙인 클래스에서 직접 자바 코드를 사용해 빈을 정의하고 구성하는 방식입니다. 이 클래스는 스프링 컨테이너가 사용하는 “설정 파일” 역할을 합니다.
차이점 요약
• 설정 방식: Annotation-based는 클래스에 직접 어노테이션을 사용하고, Java-based는 설정 클래스를 만들어 자바 코드로 구성합니다.
• 유연성: Java-based 설정이 더 유연하고, 타입 안전성을 보장하며, 복잡한 설정이 가능합니다.
• 자동화 수준: Annotation-based 설정은 자동화된 구성이 많아, 간단한 설정에는 편리하지만, 세밀한 제어에는 Java-based가 유리합니다.
이 두 방식은 종종 함께 사용되며, 스프링 프로젝트에서는 필요한 수준의 유연성과 제어에 따라 선택적으로 활용할 수 있습니다.
어노테이션 기반 컨테이너 구성은 스프링에서 전통적인 XML 기반의 설정 대신 어노테이션을 사용하여 빈(bean)과 그 의존성을 정의하고 구성하는 방법을 말합니다. 이 접근 방식은 코드가 간결하고 이해하기 쉽게 만들어 주며, 스프링 애플리케이션을 더 쉽게 관리할 수 있게 해줍니다.
@Configuration으로 어노테이션 처리되지 않은 클래스 내에서 @Bean 메소드가 선언되거나 @Configuration(proxyBeanMethods=false)로 선언된 경우, 이러한 메소드들은 "라이트" 모드로 처리된다고 합니다. 이러한 시나리오에서는 @Bean 메소드가 특별한 런타임 처리가 없는 일반적인 팩토리 메소드 메커니즘으로 동작합니다(즉, CGLIB 서브클래스를 생성하지 않음). 따라서 이러한 메소드에 대한 커스텀 자바 호출은 컨테이너에 의해 인터셉트되지 않으며, 주어진 빈에 대해 기존의 싱글톤(또는 스코프된) 인스턴스를 재사용하는 대신 매번 새로운 인스턴스를 생성하게 됩니다.
앞서 언급했듯이 AnnotationConfigApplicationContext는 @Configuration 클래스에서만 작동하는 데 국한되지 않습니다. 다음 예제에서 보듯이 @Component 또는 JSR-330 주석이 달린 클래스는 생성자에 입력으로 제공될 수 있습니다.
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
@Autowired
register() 메서드
@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig {
// ...
}
앞의 예에서 com.acme 패키지는 @Component 어노테이션이 달린 클래스를 찾기 위해 스캔되고, 해당 클래스는 컨테이너 내에서 Spring 빈 정의로 등록됩니다. AnnotationConfigApplicationContext는 다음 예에서 보여지는 것처럼 동일한 컴포넌트 스캔 기능을 허용하기 위해 scan(String…) 메서드를 노출합니다.
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
이 방법은 scan 메서드를 사용하여 지정된 패키지에서 컴포넌트를 자동으로 스캔하고, 해당 컴포넌트들을 빈으로 등록합니다. 이 방식은 애플리케이션이 큰 경우나 패키지 내에 여러 컴포넌트가 있을 때 유용합니다.
• scan(String... basePackages): 지정된 패키지를 스캔하여 @Component, @Service, @Repository, @Controller 등으로 표시된 클래스들을 빈으로 등록합니다.
• refresh(): 컨텍스트를 초기화하고 빈을 생성합니다.
요약
• **register**를 사용하면 개별 구성 클래스를 지정할 수 있습니다.
• **scan**을 사용하면 지정된 패키지를 스캔하여 모든 빈을 자동으로 등록할 수 있습니다.
두 방법 모두 스프링 애플리케이션에서 빈을 생성하고 관리하는 데 사용되며, 상황에 따라 적절한 방법을 선택할 수 있습니다.
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
이 방법은 register 메서드를 사용하여 여러 @Configuration 클래스를 수동으로 등록합니다. 그런 다음 refresh 메서드를 호출하여 애플리케이션 컨텍스트를 초기화합니다. 이 방식은 특정 구성 클래스를 직접 지정하여 빈을 구성할 때 유용합니다.
• register(Class<?>... annotatedClasses): 지정된 클래스들을 설정 파일로 사용하여 컨텍스트를 구성합니다.
• refresh(): 컨텍스트를 초기화하고 빈을 생성합니다.
Using the @Bean Annotation
@Bean은 메서드 레벨 어노테이션이며 XML <bean/> 엘리먼트와 직접적으로 대응됩니다. 이 어노테이션은 <bean/>에서 제공하는 다음과 같은 일부 속성을 지원합니다.
- init-method
- destroy-method
- autowiring
- name
@Bean 애노테이션은 @Configuration 어노테이션이 붙은 클래스나 @Component 어노테이션이 붙은 클래스에서 사용할 수 있습니다.
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
하지만, 자바 8의 디폴트 메서드를 이용하면 인터페이스에서도 @Bean을 사용할 수 있습니다. 이 경우, 인터페이스를 구현하는 클래스가 @Configuration 어노테이션을 갖고 있어야 하고, 인터페이스의 디폴트 메서드에서 정의된 빈도 해당 클래스가 스프링 컨텍스트에 등록될 때 같이 등록됩니다.
코드 분석
1. BaseConfig 인터페이스:
• 이 인터페이스는 스프링 빈을 생성하기 위한 기본 설정을 정의합니다.
• @Bean 어노테이션이 붙은 transferService() 메서드는 디폴트 메서드로 구현되며, 이는 이 인터페이스를 구현하는 클래스들이 이 메서드를 상속받을 수 있게 합니다.
• 디폴트 메서드를 사용하면 모든 구현 클래스에 공통적인 빈을 제공할 수 있습니다.
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
2. AppConfig 클래스:
• 이 클래스는 @Configuration 어노테이션을 통해 스프링 설정 클래스임을 나타냅니다.
• 이 클래스는 BaseConfig 인터페이스를 구현하며, BaseConfig에 정의된 transferService 빈을 상속받습니다.
• 따라서 AppConfig는 transferService 빈을 제공하는 설정 클래스로 작동합니다.
@Configuration
public class AppConfig implements BaseConfig {
}
동작 방식
• AppConfig 클래스는 BaseConfig 인터페이스를 구현하기 때문에, BaseConfig에 정의된 transferService() 메서드가 빈으로 등록됩니다.
• 즉, ApplicationContext에서 AppConfig를 로드하면, transferService 빈이 자동으로 등록되고 사용할 수 있게 됩니다.
요약
• 이 코드 구조는 기본 설정을 인터페이스에 정의하고, 이를 구현한 여러 설정 클래스에서 재사용할 수 있는 유연한 방법을 제공합니다.
• @Bean 어노테이션과 디폴트 메서드를 활용하여, 공통 빈 정의를 여러 설정 클래스에서 간편하게 상속하고 사용할 수 있습니다.
네, 맞습니다. @Configuration 어노테이션은 스프링 프레임워크에서 사용되는 어노테이션으로, 해당 클래스가 하나 이상의 스프링 빈(Bean)을 정의할 수 있음을 나타냅니다. 쉽게 말해, 이 어노테이션이 붙은 클래스는 스프링 애플리케이션 컨텍스트에서 빈을 생성하고 관리하는 설정 클래스임을 스프링에게 알려주는 역할을 합니다.
네, 맞습니다. @Component는 스프링 프레임워크에서 사용되는 어노테이션으로, 해당 클래스가 스프링 컨텍스트에 의해 관리되는 빈(Bean)으로 등록될 것임을 나타냅니다.
간단히 말해서, @Component가 붙은 클래스는 스프링이 자동으로 인식하여 애플리케이션 컨텍스트에 빈으로 등록하게 됩니다. 이를 통해 개발자는 별도로 XML 설정 파일이나 다른 빈 설정 클래스를 작성할 필요 없이, 필요한 클래스에 @Component를 붙이는 것만으로 스프링에서 해당 객체를 빈으로 관리할 수 있습니다.
스프링 빈의 라이프사이클 콜백이란?
스프링에서 **빈(Bean)**이란 스프링 컨테이너에서 관리하는 객체를 말해요. 이 빈은 만들어지고, 설정되고, 사용되고, 마지막에는 제거되기까지 여러 단계(라이프사이클)를 거칩니다. 이 과정에서 스프링은 빈에게 특정한 시점에 해야 할 일을 알려주는 “콜백 메서드”를 호출해요.
1. @PostConstruct와 @PreDestroy
이 두 어노테이션은 빈의 초기화와 소멸 단계에서 실행할 메서드를 지정하는 데 사용됩니다.
• @PostConstruct: 빈이 생성되고 나서 초기화 작업을 할 때 실행됩니다. 예를 들어, 데이터베이스 연결을 설정하는 코드가 여기에 들어갈 수 있어요.
• @PreDestroy: 빈이 삭제되기 전에 정리 작업을 할 때 실행됩니다. 예를 들어, 열려 있는 데이터베이스 연결을 닫는 작업을 여기에 넣을 수 있어요.
2. 스프링의 일반 라이프사이클 콜백
스프링에는 이 외에도 특정 인터페이스를 구현함으로써 빈의 라이프사이클 동안 특정 작업을 할 수 있습니다.
• InitializingBean: 이 인터페이스의 afterPropertiesSet() 메서드는 빈이 생성되고 나서 설정 작업을 할 때 호출됩니다.
• DisposableBean: 이 인터페이스의 destroy() 메서드는 빈이 제거될 때 호출됩니다.
• *Aware 인터페이스: 빈이 스프링 컨테이너에 의해 관리될 때 컨테이너의 특정 정보나 기능에 접근할 수 있도록 해주는 인터페이스들이에요. 예를 들어 ApplicationContextAware를 구현하면 스프링의 애플리케이션 컨텍스트에 접근할 수 있게 됩니다.
3. @Bean 어노테이션의 init-method와 destroy-method
@Bean 어노테이션을 사용하면 스프링 XML에서 init-method와 destroy-method를 설정하던 것과 비슷하게 특정 메서드를 초기화 및 소멸 단계에서 호출하도록 지정할 수 있습니다.
결론
스프링은 빈의 라이프사이클 동안 다양한 시점에 특별한 작업을 할 수 있도록 여러 가지 방법을 제공합니다. @PostConstruct, @PreDestroy, 그리고 @Bean 어노테이션에서의 init-method와 destroy-method 설정이 그 예입니다. 이를 통해 빈이 생성되거나 제거될 때 필요한 초기화나 정리 작업을 자동으로 수행할 수 있습니다.
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
@Bean 어노테이션의 동작 방식
• beanOne의 초기화(init): beanOne() 메서드를 호출하면 BeanOne 객체가 생성되고, 생성된 객체에 대해 init() 메서드가 호출됩니다. 즉, BeanOne 객체가 처음 생성될 때 스프링이 자동으로 init() 메서드를 실행해서 초기화 작업을 수행합니다.
• beanTwo의 정리(cleanup): beanTwo() 메서드를 호출하면 BeanTwo 객체가 생성되고, 애플리케이션이 종료되거나 스프링 컨테이너가 해당 빈을 제거할 때 cleanup() 메서드가 호출됩니다. 이때 cleanup() 메서드가 실행되면서 정리 작업이 수행됩니다.
정리
• beanOne이 초기화되는 시점: beanOne() 메서드를 통해 BeanOne 객체가 생성될 때, 스프링은 자동으로 init() 메서드를 호출해 초기화 작업을 합니다.
• beanTwo가 정리되는 시점: beanTwo() 메서드를 통해 생성된 BeanTwo 객체가 스프링 컨테이너에서 제거될 때, 스프링은 자동으로 cleanup() 메서드를 호출해 정리 작업을 합니다.
따라서, beanOne을 호출한다고 해서 빈이 “초기화”되고, beanTwo를 호출한다고 해서 빈이 “삭제”되는 것은 아닙니다. 초기화는 빈이 생성될 때, 정리는 빈이 컨테이너에서 제거될 때 발생합니다.
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
// ...
}
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
}
이 코드에서는 beanOne() 메서드 내부에서 BeanOne 객체를 생성한 후, 직접 init() 메서드를 호출합니다.
• 즉, 빈이 생성되는 즉시 초기화 작업이 수행됩니다.
• 이 방식은 개발자가 명시적으로 초기화 메서드를 호출하기 때문에, 어떤 메서드가 초기화 작업을 수행하는지 코드에서 바로 확인할 수 있습니다.
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
}
• 이 코드에서는 @Bean 어노테이션의 initMethod 속성을 사용해 초기화 메서드를 지정합니다.
• 스프링 컨테이너가 빈을 생성하고 관리할 때, 자동으로 init() 메서드를 호출해 초기화를 수행합니다.
• 개발자가 init() 메서드를 직접 호출할 필요가 없으며, 스프링 컨테이너가 빈의 라이프사이클을 관리하면서 초기화 작업을 알아서 처리합니다.
결론
• 두 코드 예제는 BeanOne 객체의 초기화 작업을 수행한다는 점에서 기능적으로 동일합니다. 다만, 첫 번째 예제에서는 초기화를 개발자가 직접 처리하는 반면, 두 번째 예제에서는 스프링 컨테이너가 관리합니다.
• 두 번째 예제가 더 스프링스러운 방식이며, 빈 초기화 로직을 깔끔하게 관리할 수 있어 더 권장되는 방식입니다.
@SessionScope는 Spring 프레임워크에서 사용되는 스코프 어노테이션 중 하나로, 웹 애플리케이션에서 HTTP 세션의 범위 내에서 빈(Bean)의 생명주기를 관리하기 위해 사용됩니다.
주요 특징:
• 범위(Session Scope): @SessionScope로 지정된 빈은 HTTP 세션이 시작될 때 생성되고, 해당 세션이 종료될 때 소멸됩니다. 즉, 한 사용자가 웹 애플리케이션과 상호작용하는 동안 세션이 유지되는 한, 이 빈의 인스턴스는 고유하게 유지됩니다.
• 사용 예시: 이 어노테이션은 주로 사용자별 데이터를 세션 동안 유지하고 싶을 때 유용합니다. 예를 들어, 로그인된 사용자의 정보를 관리하는 빈이나 장바구니와 같은 데이터를 저장하는 빈에 사용될 수 있습니다.
Customizing Bean Naming
기본적으로 구성 클래스는 @Bean 메서드의 이름을 결과 빈의 이름으로 사용합니다. 그러나 이 기능은 다음 예제에서 보여지는 것처럼 name 속성을 사용하여 재정의할 수 있습니다.
@Configuration
public class AppConfig {
@Bean("myThing")
public Thing thing() {
return new Thing();
}
}
Bean Aliasing는 여러 개의 이름(별칭)을 동일한 빈에 부여하는 것을 의미합니다. 여러개도 붙일 수 있다!!
'Note-Taking' 카테고리의 다른 글
Annotation 기반의 Container Configuration 개념 정리 (0) | 2024.09.03 |
---|---|
Autowired 어노테이션 사용 방법 정리 (0) | 2024.09.03 |
Instrumentation API 정리 (0) | 2024.09.03 |
Spring Framework에서 테스트 어노테이션과 자바 기반 설정의 역할 정리 (0) | 2024.08.09 |
Java 클래스 구조 정리 (0) | 2024.08.07 |