Spring(10)——beanオブジェクトの変更に使用できるBeanPostProcessor
もっと読む
10 BeanPostProcessor
10.1概要
BeanPostProcessorはSpringで定義されているインターフェースであり、これは前に紹介したInitializingBenとDispposable Beanインターフェースと類似しています.Springは、初期化されたbeanの前後にBenPostProcessorの実現類をフィードバックし、InitializingBeanとDispsable Beanインターフェースとは異なり、BenPostProcessorインターフェースは、すべてのBeanに対して役割を果たします.つまり、Bean初期化前後にBenPostProcessorの実現類をリセットします.対応するbeanでInitializingBeanまたはDispposable Beanインターフェースを実現してこそ、それをリピートすることができる.
BeanPostProcessorインターフェースの定義は以下の通りです.
以下はSpringソースの中でbeanを初期化するロジックです.ソースから見れば
BeanPostProcessorの登録はとても簡単です.普通のbeanとしてSpringのbean容器に定義するだけで、Springは自動的にそれを検出し、現在のbean容器に登録することができます.BenPostProcessorは容器バインディングであり、BenPostProcessorは同じビーン容器の中のbeanだけをリピートすることができます.つまり、BenPostProcessorは父容器または子容器の中のbeanをリピートすることができません.
Bean容器にBenPostProcessorを定義した後、Springは最初にBenPostProcessorに対応するbeanを具体化します.BenPostProcessorの
BeanPostProcessorはSpring内部でも多く使われています.特にAOPエージェント部分です.ユーザがビーンPostProcessorを実現する必要がある場合も含め、直接または間接的に関連するビーンは、プロキシに成功しないように注意してください.
10.3例
次に簡単に自分をカスタマイズするBeanPostProcessorの例を見て、例としてはBenPostProcessorを簡単に実現し、
bean容器の中で複数のBenPostProcessorを同時に定義することができます.このように、新たな実用化の後に各BenPostProcessorを順次使用します.もちろん、あるBenPostProcessorが折り返したら、nullに戻ります.一つのbean容器の中で複数のBenPostProcessorが同時に定義されている場合、デフォルトではBenPostProcessorがbean容器で定義している順序に従って、新しい実用化されたbeanをリピートします.もう一つの方法は、BenPostProcessorのフィードバック順序を定義する方法であり、私たちがカスタマイズしたBeaBenPostProcessorのクラスを同時にOrderedインターフェースを実現し、その後、SpringはOrderedインターフェースによって定義された
以下は、Orderedインターフェースを実装し、
本論文の転送先:https://elim.iteye.com/blog/2386920
10 BeanPostProcessor
10.1概要
BeanPostProcessorはSpringで定義されているインターフェースであり、これは前に紹介したInitializingBenとDispposable Beanインターフェースと類似しています.Springは、初期化されたbeanの前後にBenPostProcessorの実現類をフィードバックし、InitializingBeanとDispsable Beanインターフェースとは異なり、BenPostProcessorインターフェースは、すべてのBeanに対して役割を果たします.つまり、Bean初期化前後にBenPostProcessorの実現類をリセットします.対応するbeanでInitializingBeanまたはDispposable Beanインターフェースを実現してこそ、それをリピートすることができる.
BeanPostProcessorインターフェースの定義は以下の通りです.
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
参照したように、BenPostProcessorインターフェースでは、方法postProcessBeforeInitialization()
は、1つのbeanが完全に初期化される前にリピートされ、このとき対応するbeanはすでに実装されているが、対応する属性注入などはまだ行われていない.すなわち、InitializingBenのafterPropertiesSet()
方法またはbean対応するinit-methodを呼び出す前に.一方、方法postProcessAfterInitialization()
は、beanが完全に初期化された後にリフローされ、このとき対応する依存注入が完了した、すなわち、InitializingBenを呼び出すafterPropertiesSet()
方法または対応するinit-method方法の後である.両方法のパラメータ及び戻り値は同じ意味であり、パラメータbeanは現在の状態のbeanを表し、パラメータbean Nameは現在のbeanの名前を表し、方法に対応する戻り値はbean容器に入れる必要があるbeanを表しているので、ユーザはこの2つの方法の中でbeanを修正し、即ち自分のbeanをカプセル化して返すことができる.以下はSpringソースの中でbeanを初期化するロジックです.ソースから見れば
applyBeanPostProcessorsBeforeInitialization()
方法で登録されたBenPostProcessorのpostProcessBeforeInitialization()
方法を使って順次にフィードバックし、invokeInitMethods()
方法で現在のbean対応する初期化方法を順次呼び出します.applyBeanPostProcessorsAfterInitialization
方法により、登録されたBeaBenPostProcessorのpostProcessorAfterInitialization()
方法を用いて順次にフィードバックする. protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
10.2登録BeanPostProcessorの登録はとても簡単です.普通のbeanとしてSpringのbean容器に定義するだけで、Springは自動的にそれを検出し、現在のbean容器に登録することができます.BenPostProcessorは容器バインディングであり、BenPostProcessorは同じビーン容器の中のbeanだけをリピートすることができます.つまり、BenPostProcessorは父容器または子容器の中のbeanをリピートすることができません.
Bean容器にBenPostProcessorを定義した後、Springは最初にBenPostProcessorに対応するbeanを具体化します.BenPostProcessorの
lazy-initialization=”true”
またはdefault-lazy-initialization=”true”
を制定したら、Springはそれらを無視します.これもよく分かります.他のbeanを実装する時にのみこれらのBenPostProcessorが役に立ちます.このような仕組みを考えると、Springはbeanを初期化する際にdepends-on属性に指定されたbeanを優先的に初期化します.だから、私達のBenPostProcessorがdepends-onを通じて他のbeanに対する依存を指定した時、他のbeanはBenPostProcessorによって回されないです.もちろんここにも紹介のdepends-on対応するbeanが含まれます.また、BeanPostProcessorの実装後に直接または間接的に注入を行う必要があるbeanも、実用化時間が早まるため、BenPostProcessorにフィードバックされない.また、BenPostProcessorの間ではリピーターが行われません.つまり、BeanPostProcessorsorAはBenPostProcessor初期化時にリピートしません.BeanPostProcessorはSpring内部でも多く使われています.特にAOPエージェント部分です.ユーザがビーンPostProcessorを実現する必要がある場合も含め、直接または間接的に関連するビーンは、プロキシに成功しないように注意してください.
10.3例
次に簡単に自分をカスタマイズするBeanPostProcessorの例を見て、例としてはBenPostProcessorを簡単に実現し、
postProcessBeforeInitialization()
とpostProcessAfterInitialization()
の方法で直接に対応するbeanを返して、postProcessBeforeInitialization()
の方法で対応するbeanの名前を簡単に印刷します.public class HelloBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("beanName-----------" + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}
BenPostProcessorを実現したら、bean容器に定義することができます.その定義は普通のbeanの定義と同じです.<bean class="com.app.HelloBeanPostProcessor"/>
10.4コールバック順序bean容器の中で複数のBenPostProcessorを同時に定義することができます.このように、新たな実用化の後に各BenPostProcessorを順次使用します.もちろん、あるBenPostProcessorが折り返したら、nullに戻ります.一つのbean容器の中で複数のBenPostProcessorが同時に定義されている場合、デフォルトではBenPostProcessorがbean容器で定義している順序に従って、新しい実用化されたbeanをリピートします.もう一つの方法は、BenPostProcessorのフィードバック順序を定義する方法であり、私たちがカスタマイズしたBeaBenPostProcessorのクラスを同時にOrderedインターフェースを実現し、その後、SpringはOrderedインターフェースによって定義された
getOrder()
方法の戻り値に基づいて、BenPostProcessorのフィードバックの順序を決定し、getOrder()
は値が小さいほど最初に戻る.また、Orderedインターフェースを実現したBeanPostProcessorは、常にOrderedインターフェースを実現していないBeanPostProcessorよりも先にフィードバックを行い、管理を容易にするために、Orderedインターフェースを実現するか、いずれも実現しないかを推奨します.以下は、Orderedインターフェースを実装し、
getOrder()
方法の戻り値をパラメータとして構成する例である.public class HelloBeanPostProcessor implements BeanPostProcessor, Ordered {
private int order;
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("beanName-----------" + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return order;
}
}
その後、構成時には、getOrder()
方法の戻り値をパラメータorderによって指定することができる.<bean class="com.app.HelloBeanPostProcessor" p:order="3"/>
(注:本文はSpring 4.1.0に基づいて書いています.)本論文の転送先:https://elim.iteye.com/blog/2386920