likes
comments
collection
share

手写spring-beanPostProcessor | 简易代理

作者站长头像
站长
· 阅读数 28

现在我们要处理 spring 代理机制,以廖雪峰老师的代码案例 userServiceuserServiceProxy 为例介绍事务的实现:

main 中得到的 userService 的 bean,是被 BeanPostProcessoruserService 替换的 userServicePoxy(对 BeanPostProcessor 来说就是当传入的 bean 同属于 userService 类,会创建其代理返回)。而在 userServicePoxy 中,将 uesrService 作为变量,调用 userServicePoxy 的方法。

需要注意的是:在需要 userService 时返回 userServicePoxy,而对于bean实际的属性 jdbcTemplate 注入到原始的 userService 中。

整理一下思路:

  1. 对于被代理的bean,需要这个bean时应该返回代理
  2. 虽然我们获取到的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
评论
请登录