【问题标题】:Get parent bean in prototype bean that gets injected在被注入的原型 bean 中获取父 bean
【发布时间】:2010-10-20 23:55:11
【问题描述】:

我想要一个像这样的 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 的范围是原型,所以它将作为一个新实例注入到每个希望它被注入的父级中。

我的大想法是利用这种模式来编写一个可以注入到普通 bean 中的 LoggerBean。子 bean 应该像 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...


编辑:只是为了更新状态。毕竟我没有实现这个,因为这是过度工程......

【问题讨论】:

    标签: spring dependency-injection design-patterns slf4j javabeans


    【解决方案1】:

    我觉得这更简单:

    @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());
      }
    }
    

    【讨论】:

    • SomeBean 范围是什么?在您的应用程序中 SomeBean 是一个实例?
    【解决方案2】:

    用原帖者给出的解决方案修复了几个错误:

    import java.lang.reflect.Field;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.util.ReflectionUtils;
    
    public interface DependencyInjectionAware {
    
    void injectedInto(final Object bean, final String beanName);
    
    public static class DependencyInjectionAwareBeanPostProcessor implements
            BeanPostProcessor {
    
        private static final Logger logger =   Logger.getLogger(DependencyInjectionAwareBeanPostProcessor.class);
    
        @Override
        public Object postProcessBeforeInitialization(final Object bean,
                final String beanName) {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(final Object bean,
                final String beanName) {
            for (final Field f : bean.getClass().getDeclaredFields()) {
                logger.info("scanning field " + f.getName() + " of bean " + beanName + " (class= " + bean.getClass() + ")");
    
                if (DependencyInjectionAware.class.isAssignableFrom(f.getType())) {
                    ReflectionUtils.makeAccessible(f);
                    try {
                        final DependencyInjectionAware diAware = (DependencyInjectionAware) f.get(bean);
                        diAware.injectedInto(bean, beanName);
                    } catch (final IllegalArgumentException e) {
                        ReflectionUtils.handleReflectionException(e);
                    } catch (final IllegalAccessException e) {
                        ReflectionUtils.handleReflectionException(e);
                    }                   
                }
            }
            return bean;
        }
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多