回答:
コンストラクタが呼び出されたとき、Beanはまだ初期化されていないため、依存関係は注入されません。では@PostConstruct
この方法Beanが完全に初期化され、あなたは依存関係を使用することができます。
これは、このメソッドがBeanライフサイクルで1回だけ呼び出されることを保証する規約であるためです。Beanがその内部作業でコンテナによって複数回インスタンス化されることは(まれではありますが)発生する可能性がありますが、それはそれ@PostConstruct
が1回だけ呼び出されることを保証します。
主な問題は、次のとおりです。
コンストラクターでは、依存関係の注入はまだ発生していません*
*明らかにコンストラクタインジェクションを除く
実際の例:
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
およびJava 11では@PreDestroy
完全に削除されました。
それらを使い続けるには、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.
セッターまたはフィールドインジェクションでは真ですが、コンストラクタインジェクションでは真ではありません。
クラスがコンストラクターですべての初期化を実行する場合、@PostConstruct
実際には冗長です。
ただし、セッターメソッドを使用してクラスの依存関係が注入されている場合、クラスのコンストラクターはオブジェクトを完全に初期化できず、すべてのセッターメソッドが呼び出された後で一部の初期化を実行する必要がある場合があるため、の使用例です@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で注釈が付けられたメソッドに移動されます。
ポストコンストラクトメソッドの処理は、@ 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に追加されているのでしょうか。彼らは別のユースケースを確実に見たはずです。