1

次のような 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に頼らなければならないかもしれません...


編集:ステータスを更新するだけです。これはオーバーエンジニアリングであるため、結局これを実装しませんでした...

4

2 に答える 2

0

私はこれがより簡単だと思います:

@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Component
public class SubBean implements ApplicationContextAware{
  private Object parent;
  public void setApplicationContext(ApplicationContext ctx){
    ...
  }
  public Object getParent(){ 
    return parent; 
  }
  //ADDED CODE
  public void setParent(Object parent) {
    this.parent = parent;
  }
  //END ADDED CODE
}

@Component
public class SomeBean implements InitializingBean{

  private SubBean sub;
  //ADDED CODE
  @Resource
  public void setSub(SubBean sub) {
      this.sub = sub;
      sub.setParent(this);
  }
  //END ADDED CODE

  public void afterPropertiesSet(){
    Assert.isTrue(this == sub.getParent());
  }
}
于 2010-11-24T23:29:21.850 に答える