관리 Bean @PostConstruct
에서 일반 Java 오브젝트 생성자 후에 호출됩니다.
@PostConstruct
일반 생성자 대신 Bean을 사용 하여 초기화하는 이유는 무엇 입니까?
답변
-
생성자가 호출 될 때 Bean이 아직 초기화되지 않았기 때문에 종속성이 주입되지 않기 때문입니다. 에서
@PostConstruct
방법 빈은 완전히 초기화 당신은 종속성을 사용할 수 있습니다. -
이는이 메소드가 Bean 라이프 사이클에서 한 번만 호출되도록 보장하는 계약이기 때문입니다. 내부 작업에서 컨테이너가 Bean을 여러 번 인스턴스화 할 가능성은 있지만 (아마도)
@PostConstruct
한 번만 호출 될 수 있습니다.
답변
주요 문제는 다음과 같습니다
생성자에서 종속성 주입이 아직 발생하지 않았습니다. *
* 생성자 주입은 분명히 제외
실제 예 :
public class Foo {
@Inject
Logger LOG;
@PostConstruct
public void fooInit(){
LOG.info("This will be printed; LOG has already been injected");
}
public Foo() {
LOG.info("This will NOT be printed, LOG is still null");
// NullPointerException will be thrown here
}
}
중요 :
@PostConstruct
및 @PreDestroy
완전히 된 자바 (11)에서 제거 .
계속 사용하려면 종속성에 javax.annotation-api JAR을 추가해야합니다 .
메이븐
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
그래들
// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
답변
클래스가 생성자에서 모든 초기화를 수행하는 경우 @PostConstruct
실제로 중복됩니다.
그러나 클래스에 setter 메소드를 사용하여 의존성이 주입 된 경우 클래스 생성자가 객체를 완전히 초기화 할 수 없으며 때로는 모든 setter 메소드를 호출 한 후 일부 초기화를 수행해야하므로 유스 케이스입니다 @PostConstruct
.
답변
다음 시나리오를 고려하십시오.
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
필드 주입 전에 Car를 인스턴스화해야하므로 생성자 실행 중에 주 입점 엔진이 여전히 null이므로 NullPointerException이 발생합니다.
이 문제는 Java 생성자 주입을 위한 JSR-330 종속성 주입 또는 Java @PostConstruct 메소드 주석을위한 JSR 250 공통 주석 으로 해결할 수 있습니다 .
@PostConstruct
JSR-250은 Java SE 6에 포함 된 공통 주석 세트를 정의합니다.
PostConstruct 주석은 초기화를 수행하기 위해 종속성 주입이 완료된 후에 실행되어야하는 메소드에서 사용됩니다. 이 메소드는 클래스를 서비스하기 전에 호출해야합니다. 이 주석은 의존성 주입을 지원하는 모든 클래스에서 반드시 지원되어야합니다.
JSR-250 Chap. 2.5 javax.annotation.PostConstruct
@PostConstruct 어노테이션은 인스턴스가 인스턴스화되고 모든 인젝션이 수행 된 후에 실행될 메소드 정의를 허용합니다.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
생성자에서 초기화를 수행하는 대신 코드는 @PostConstruct로 주석이 달린 메소드로 이동합니다.
post-construct 메소드의 처리는 @PostConstruct로 주석이 달린 모든 메소드를 찾아서 차례로 호출하는 간단한 문제입니다.
private void processPostConstruct(Class type, T targetInstance) {
Method[] declaredMethods = type.getDeclaredMethods();
Arrays.stream(declaredMethods)
.filter(method -> method.getAnnotation(PostConstruct.class) != null)
.forEach(postConstructMethod -> {
try {
postConstructMethod.setAccessible(true);
postConstructMethod.invoke(targetInstance, new Object[]{});
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
});
}
인스턴스화 및 주입이 완료된 후 사후 생성 방법의 처리를 수행해야합니다.
답변
또한 생성자 기반 초기화는 일종의 프록시 또는 원격 작업이 필요할 때마다 의도 한대로 작동하지 않습니다.
ct는 EJB가 deserialize 될 때마다 그리고 새로운 프록시가 생성 될 때마다 호출됩니다 …