views:

10

answers:

0

Hi,

I would like to have a Bean and a SubBean like this:

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

The trick I want to achieve is, that the SubBean automagically gets a reference to the Bean it got injected into. Because the scope of the subbean is prototype, it will get injected as a new instance in every parent that wants it to get injected.

My big idea is to exploit this pattern to write a LoggerBean which can be injected into normal beans. The subbean should work just like a SLF4J Logger.

So does anyone know the magic to make this work? :)


EDIT: I've found a solution to do this with a custom 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;
  }
}

Here is the Interface:

public interface IDependencyInjectionAware {
  void injectedInto(Object parent);
}

And here a Bean using it:

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

Here a test with a normal Bean which works perfectly:

@Component 
public class UsingBean implements InitializingBean {
  @Resource
  private SomeAwareBean b;
  public void afterPropertiesSet(){
    Assert.notNull(b); //works
    Assert.isTrue(b.getParent() == this); //works
  }
}

Though, when using the same with a normal class which gets the depedencies injected via @Configurable, the test fails:

@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
  }
}

So this seems to have gotten me to another question: Why won't my custom BeanPostProcessor run on a @Configurable classes? Maybe I have to resort to AspectJ afterall...