Мне бы хотелось, чтобы Бин и 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 автоматически получает ссылку на Бин, в который он был введен.Поскольку область действия дочернего объекта является прототипом, он будет вставлен как новый экземпляр в каждый родительский объект, который хочет, чтобы его внедрили.
Моя большая идея состоит в том, чтобы использовать этот шаблон для написания LoggerBean, который можно вставить внормальные бобы.Подсолнечник должен работать точно так же, как SLF4J Logger.
Так кто-нибудь знает магию, чтобы заставить эту работу?:)
РЕДАКТИРОВАТЬ: Я нашел решение сделать это с помощью пользовательского 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);
}
А вот Бин, использующий его:
@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;
}
}
Здесь тест с обычным Бином, который отлично работает:
@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 в конце концов ...
РЕДАКТИРОВАТЬ: Просто чтобы обновить статус.Я не реализовал это в конце концов, потому что это - сверхинжиниринг ...