PostConstruct & PreDestroy, CDI Jakart Contexts & Dependency Injection
1. PostConstruct 및 PreDestroy
PostConstruct
초기화를 수행하기 위한 의존성 주입이 완료된 후 실행해야 하는 메서드에서 사용합니다,
클래스를 사용하기 전에 호출되어야 합니다.
(다른 Bean이 이 Bean을 사용할 수 있게 되기 전에 이 메서드가 호출됩니다)
이 때 애플리케이션이 실행되고 Bean이 로드됩니다.
PreDestroy
컨테이너에서 인스턴스를 삭제하는 과정 중에 있음을 알려주는 콜백 알림으로,
보유하고 있던 리소스를 해제하는 데 일반적으로 사용됩니다.
애플리케이션이 종료되기 전에, 컨텍스트에서 Bean이 삭제되기 전에 특정 작업을 하고자 할 때 사용합니다.
특정 작업은 보통 cleanup을 합니다.
(DB 등에 연결되어 있다면 cleanup으로 종료할 수 있습니다)
예시입니다.
@Component
class SomeClass {
// 의존성을 연결하는 대로 초기화하는 것을 가정
private SomeDependency someDependency;
public SomeClass(SomeDependency someDependency) {
super();
this.someDependency = someDependency;
System.out.println("SomeClass All dependencies are ready!");
}
/**
* 초기화 과정의 일부,
* 초기화를 수행하기 위해 의존성 주입이 완료된 후 실행해야 하는 메서드에서 사용,
* 클래스를 사용하기 전에 호출되어야 함
* (다른 Bean이 이 Bean을 사용할 수 있게 되기 전에 이 메서드가 호출)
* dovmv
*/
@PostConstruct
public void initialize() {
System.out.println("@PostConstruct Initialize");
someDependency.getReady();
}
@PreDestroy
public void cleanup() {
System.out.println("@PreDestroy Cleanup");
}
}
@Component
class SomeDependency{
public void getReady() {
System.out.println("[getReady] Some logic using SomeDependency");
}
}
@Configuration
@ComponentScan
public class PrePostAnnotationsContextLauncherApplication {
public static void main(String[] args) {
try (
var context =
new AnnotationConfigApplicationContext
(PrePostAnnotationsContextLauncherApplication.class);
) {
Arrays.stream(context.getBeanDefinitionNames())
.forEach(System.out::println);
}
}
}
위 코드의 출력문은 아래와 같습니다.
SomeClass All dependencies are ready!
@PostConstruct Initialize
[getReady] Some logic using SomeDependency
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
prePostAnnotationsContextLauncherApplication
someClass
someDependency
@PreDestroy Cleanup
의존성을 연결하는 대로 초기화 논리를 실행하려는 경우
(예컨대 데이터베이스 등에서 데이터를 가져오려는 경우)
@PostConstruct를 사용할 수 있으며,
컨테이너에서 Bean이 삭제되기 전에,
(애플리케이션 컨텍스트에서 삭제되기 전에)
cleanup을 수행하려는 경우에는
@PreDestroy를 사용할 수 있습니다.
2. CDI Jakart Contexts & Dependency Injection
CDI는 어노테이션 그룹을 정의한 규격(스펙)이며 의존성 주입을 수행하는 데 사용할 수 있습니다.
CDI는 Jakarta EE에 속한 규격(specifiction)이며 Spring Framework에서 지원합니다.
Spring Framework V1은 2004년에 도입되었고,
CDI 규격은 2009년의 Java EE 6 플랫폼에 도입되었습니다.
지금은 Jakarta Contexts and Dependendy Injection이라고 부릅니다.
CDI는 규격이고, 인터페이스입니다. 따라서 구현이 없습니다.
(Spring Framework에서 CDI를 구현합니다)
CDI에는 중요한 API 어노테이션 몇 가지가 정의되어 있습니다.
Inject, Named, Qualifier, Scope, Singleton 이 예시에 해당합니다.
Inject는 Autowired와 비슷하고,
Named는 Component와 비슷합니다.
Qualifier, Scope, Singleton은 Spring에 있는 어노테이션과 비슷합니다.
의존성을 추가하고 코드를 작성하며 확인해보겠습니다.
pom.xml
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<version>2.0.1</version>
</dependency>
gradle
implementation 'jakarta.inject:jakarta.inject-api:2.0.1'
데이터 서비스를 사용하는 비즈니스 서비스가 있다고 가정을 해보겠습니다.
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Arrays;
//@Component
@Named
class BusinessService {
private DataService dataService;
//@Autowired
@Inject
public void setDataService(DataService dataService) {
System.out.println("Setter Injection");
this.dataService = dataService;
}
public DataService getDataService() {
return dataService;
}
}
//@Component
@Named
class DataService {
}
@Configuration
@ComponentScan
public class CdiContextLauncherApplication {
public static void main(String[] args) {
try (
var context =
new AnnotationConfigApplicationContext
(CdiContextLauncherApplication.class);
) {
Arrays.stream(context.getBeanDefinitionNames())
.forEach(System.out::println);
System.out.println(context.getBean(BusinessService.class)
.getDataService());
}
}
}
위 코드의 출력문은 아래와 같습니다.
Setter Injection
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
cdiContextLauncherApplication
businessService
dataService
com.ride.learnspringframework2.example.g1.DataService@20f5239f
두 어노테이션간 출력문의 차이는 없으며,
통상적으로 Spring 프로젝트에서는 CDI 스펙보다는 Componet, Autowired를 사용합니다.
'Java' 카테고리의 다른 글
[SpringFramework] 개념 및 용어 정리 (0) | 2023.12.20 |
---|---|
[SpringFramework] Spring Annotations (1) | 2023.12.20 |
[SpringFramework] Lazy Initialization vs. Eager Initialization, Bean Scopes (0) | 2023.12.17 |
[SpringFramework] Bean 우선순위 부여(@Primary, @Qualifier) (0) | 2023.11.29 |
[SpringFramework] Spring Container, Java Bean vs. POJO vs. Spring Bean (0) | 2023.11.26 |