답변:
생성자가 호출 될 때 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'
in a constructor, the injection of the dependencies has not yet occurred.
setter 또는 field injection에서는 true이지만 생성자 injection에서는 true가 아닙니다.
클래스가 생성자에서 모든 초기화를 수행하는 경우 @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);
}
});
}
인스턴스화 및 주입이 완료된 후 사후 생성 방법의 처리를 수행해야합니다.
final
. 이러한 패턴을 감안할 때@PostConstruct
J2EE에 추가되는 이유는 분명히 다른 사용 사례를 보았어야합니까?