手写spring-beanPostProcessor | 简易代理
现在我们要处理 spring 代理机制,以廖雪峰老师的代码案例 userService
和 userServiceProxy
为例介绍事务的实现:
在 main
中得到的 userService
的 bean,是被 BeanPostProcessor
将 userService
替换的 userServicePoxy
(对 BeanPostProcessor
来说就是当传入的 bean
同属于 userService
类,会创建其代理返回)。而在 userServicePoxy
中,将 uesrService
作为变量,调用 userServicePoxy
的方法。
需要注意的是:在需要 userService
时返回 userServicePoxy
,而对于bean实际的属性 jdbcTemplate
注入到原始的 userService
中。
整理一下思路:
- 对于被代理的bean,需要这个bean时应该返回代理
- 虽然我们获取到的bean是代理,但是注入的依赖应该在原本的bean上,保证原本bean的功能正常
那么在后续的代码实现中我们需要做的第一步就是筛选出 BeanPostProcessor
的 bean,这是示例:
@Bean
BeanPostProcessor createProxy() {
// ……
}
那么对应的我们应该判断这个 bean 的类型是否是 BeanPostProcessor
,而不是像前面的 @Configuration
去处理注解。再将筛选出的 BeanPostProcess
存放到类的List beanPostProcessors
List<BeanPostProcessor> processors = this.beans.values().stream()
// 过滤出 BeanPostProcessor 类型的bean
.filter(this::isBeanPostProcessorDefinition).sorted().map(bd -> {
return (BeanPostProcessor) createBeanAsEarlySingleton(bd);
}).collect(Collectors.toList());
this.beanPostProcessors.addAll(processors);
而更细致的处理就是就是在 setter+字段注入 和 初始化方法 中了:
在setter+字段注入的 injectBean
新增处理,就是我们将属性注入到原本的bean中:
Object instance = getProxiedInstance(beanDefinition);
injectProperties(beanDefinition, beanDefinition.getBeanClass(), instance);
在初始化方法的 initBean
中处理,相对于原本的只是调用 callMethod
,这里需要获取到原始bean,然后对这个bean执行初始化,然后是 beanPostPocessor
的初始化处理。
void initBean(BeanDefinition beanDefinition) {
// 获取bean示例,或者被代理的原始实例:
final Object beanInstance = getProxiedInstance(beanDefinition);
callMethod(beanInstance, beanDefinition.getInitMethod(), beanDefinition.getInitMethodName());
// 调用 BeanPostProcessor.postProcessAfterInitialization()
beanPostProcessors.forEach(bp -> {
Object processedInstance = bp.postProcessAfterInitialization(beanDefinition.getInstance(), beanDefinition.getName());
if (processedInstance != beanDefinition.getInstance()) {
logger.atDebug().log("BeanPostProcessor {} return different bean from {} to {}.", bp.getClass().getSimpleName(),beanDefinition.getInstance().getClass().getName(), processedInstance.getClass().getName());
beanDefinition.setInstance(processedInstance);
}
});
}
最后是相当于整个实现的工具方法——获取到原始的bean的方法:
我们应该如何在 bean 可能被代理所修改过的情况下获取到原始的 bean?
这里的方法是:遍历反转后所有的 BeanPostProcessor
,我们将具体的获取交给接口的实现,因为在这个实现类中会将原本的bean作为属性。
注意这里的反转 Collections.revers(reversedBeanPostProcessors);
属性的应用可能是多层次的,正好契合反转后的顺序。
Object getProxiedInstance(BeanDefinition def) {
Object beanInstance = def.getInstance();
// 如果代理改变了原始bean,有希望向原始bean注入属性:
ArrayList<BeanPostProcessor> reversedBeanPostProcessors = new ArrayList<>(this.beanPostProcessors);
Collections.reverse(reversedBeanPostProcessors);
for (BeanPostProcessor revered : reversedBeanPostProcessors) {
Object restoredInstance = revered.postProcessOnSetProperty(beanInstance, def.getName());
if (restoredInstance != beanInstance) {
logger.atDebug().log("BeanPostProcessor {} specified injection from {} to {}.", revered.getClass().getSimpleName(),
beanInstance.getClass().getSimpleName(), restoredInstance.getClass().getSimpleName());
beanInstance = restoredInstance;
}
}
return beanInstance;
}
转载自:https://juejin.cn/post/7372078061896335397