次のような Bean と SubBean が必要です。
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Component
public class SubBean implements ApplicationContextAware{
private Object parent;
public void setApplicationContext(ApplicationContext ctx){
this.parent = doSomeMagicToGetMyParent(ctx);
}
public Object getParent(){
return parent;
}
}
@Component
public class SomeBean implements InitializingBean{
@Resource
private SubBean sub;
public void afterPropertiesSet(){
Assert.isTrue(this == sub.getParent());
}
}
私が達成したいトリックは、SubBean が注入された Bean への参照を自動的に取得することです。サブビーンのスコープはプロトタイプであるため、サブビーンの注入を希望するすべての親に新しいインスタンスとして注入されます。
私の大きなアイデアは、このパターンを利用して、通常の Bean に注入できる LoggerBean を作成することです。サブビーンは、SLF4J ロガーと同じように機能する必要があります。
では、これを機能させる魔法を知っている人はいますか? :)
編集:カスタム BeanPostProcessor でこれを行うソリューションを見つけました:
@Component
public class DependencyInjectionAwareBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
for (Field f : bean.getClass().getFields()) {
if (f.getType().isInstance(IDependencyInjectionAware.class)) {
ReflectionUtils.makeAccessible(f);
try {
IDependencyInjectionAware diAware = (IDependencyInjectionAware) f.get(bean);
diAware.injectedInto(bean);
} catch (IllegalArgumentException e) {
ReflectionUtils.handleReflectionException(e);
} catch (IllegalAccessException e) {
ReflectionUtils.handleReflectionException(e);
}
}
}
return bean;
}
}
インターフェイスは次のとおりです。
public interface IDependencyInjectionAware {
void injectedInto(Object parent);
}
そして、ここでそれを使用する Bean:
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Component
public class SomeAwareBean implements IDependencyInjectionAware {
private Object parent;
public void injectedInto(Object parent){
this.parent = parent;
}
public Object getParent(){
return parent;
}
}
ここでは、完全に機能する通常の Bean を使用したテストを示します。
@Component
public class UsingBean implements InitializingBean {
@Resource
private SomeAwareBean b;
public void afterPropertiesSet(){
Assert.notNull(b); //works
Assert.isTrue(b.getParent() == this); //works
}
}
ただし、@Configurable を介して注入された依存関係を取得する通常のクラスで同じものを使用すると、テストは失敗します。
@Configurable
public class UsingPlainClass implements InitializingBean {
@Resource
private SomeAwareBean b;
public void afterPropertiesSet(){
Assert.notNull(b); //works
Assert.isTrue(b.getParent() == this); //fails because null is returned
}
}
だから、これは私に別の質問をさせたようです:なぜ私のカスタム BeanPostProcessor は @Configurable クラスで実行されないのですか? 結局、AspectJに頼らなければならないかもしれません...
編集:ステータスを更新するだけです。これはオーバーエンジニアリングであるため、結局これを実装しませんでした...