我想像这样拥有一个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的引用。因为subbean的范围是原型,所以它将作为一个新实例注入到希望它被注入的每个父项中。
我的主要想法是利用这种模式编写一个可以注入普通bean的LoggerBean。子bean应该像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);
}
这是一个使用它的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 ...
编辑:只是为了更新状态。我没有实现这个,因为这是过度工程......
答案 0 :(得分: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());
}
}
答案 1 :(得分:0)
修复了原始海报给出的解决方案的几个错误:
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;
}
}
}