问题
日志中出现如下warning:
demo.test.bpp.DataCache] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
问题复现
@Retention(RetentionPolicy.RUNTIME)
public @interface RandomInt {
int min();
int max();
}
@Component
@Data
// @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class DataCache {
public DataCache() {
System.out.println("new DataCache");
}
@RandomInt(min = 2, max = 10)
private int group;
private String name;
}
public class RandomIntProcessor implements BeanPostProcessor {
public RandomIntProcessor() {
System.out.println("new RandomIntProcessor");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean name in RandomIntProcessor: " + beanName);
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
RandomInt injectRandomInt = field.getAnnotation(RandomInt.class);
if (injectRandomInt != null) {
int min = injectRandomInt.min();
int max = injectRandomInt.max();
int randomValue = RandomUtils.nextInt(min, max);
field.setAccessible(true);
ReflectionUtils.setField(field, bean, randomValue);
}
}
return bean;
}
}
@Component
public class BizProcessor implements BeanPostProcessor {
@Autowired
// @Lazy
private DataCache dataCache;
public BizProcessor() {
System.out.println("new BizProcessor");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean name in BizProcessor: " + beanName);
// for debug
try {
throw new RuntimeException("see see");
} catch (Exception e) {
e.printStackTrace();
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
public int getData() {
return dataCache.getGroup();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RandomIntProcessor.class, DataCache.class, BizProcessor.class})
public class NotEligibleForAutoProxyingIntegrationTest {
@Autowired
private BizProcessor bizProcessor;
@Autowired
private DataCache dataCache;
@Test
public void givenAutowireInBeanPostProcessor_whenSpringContextInitialize_thenNotEligibleLogShouldShow() {
System.out.println("result: " + bizProcessor.getData());
System.out.println("result: " + dataCache.getGroup());
}
}
- 在BizProcessor中,dataCache的@Lazy注解被注释的话,输出如下:
result: 0
result: 0
- 在BizProcessor中,增加dataCache的@Lazy注解
result: 6
result: 6
原理解释
BeanPostProcessor会被spring容器特殊处理、不同对待。所有的BeanPostProcessor实例和他们的直接依赖会在启动的时候被直接实例化,这作为ApplicationContext特殊的启动阶段。下一步,所有的BeanPostProcessor会被按照顺序被注册进容器,并被应用到后面所有的bean。因为AOP自动代理也是一种BeanPostProcessor,所以所有的BeanPostProcessor实例以及他们的直接依赖都不会被自动代理,也就不会被应用切面织入(AOP这一句不太懂)。
为了解决BeanPostProcessor和他的依赖之间的死循环,可以在BeanPostProcessor依赖的Bean上增加@Lazy注解。这样当该依赖Bean被使用时,会被初始化。这样就可以被BeanPostProcessor处理了。