SpringBoot 系列-Bean 的生命周期与扩展

个人博客:glmapper
更多请关注 glmapper工作室 微信公众号

注:本篇基于 SpringBoot 2.2.2.RELEASE 版本,Spring 各个版本之间多少存在一些差异,不过主流程基本相同;大家在阅读过程中需关注这点。

继续承接上一篇 SpringBoot 系列-启动过程分析,本篇围绕一个 bean 的生命周期,对 bean 进行一些修改和扩展。本篇将涉及到以下主要内容:

阅读之前

下面是本篇文章的“主人公” TestBeanService ,定义如下:

public class TestBeanService {
    /**
     * 依赖注入
     */
    @Autowired
    private InjectBeanService injectBeanService;
    /**
     * 属性注入
     */
    @Value("${spring.application.name}")
    private String appName;

    public String test() {
        return injectBeanService.testInject();
    }
}

TestBeanService 里面包括两个属性,一个是 injectBeanService ,另外一个是 appName,分别通过 @Autowired 和 @Value 注入值。本篇最终希望完成的目标是能够完成了解 Bean 属性注入的过程,以及 Bean 的实例化过程;除此之外,从 Spring 扩展的角度,来对 BeanFactoryPostProcess、BeanPostProcess、ApplicationListener、InitializingBean 以及 initMethod 的执行时机和作用进行分析。

TestBeanService 被解析成 BeanDifinition 的时机与过程

Spring 容器刷新流程非常复杂,当我们想 debug BeanDifinition 加载过程时可能没法很快找到入口,这里可以直接面向 BeanDifinition 的最终去向来 debug。我们知道 BeanFactory 接口本身是不具体注册 BeanDifinition 能力的,这个能力是由 BeanDefinitionRegistry 接口提供。那么就看下 BeanDefinitionRegistry 的 registerBeanDefinition 方法有几个具体的实现,然后在这几个实现出打上断点,执行找到具体的处理入口。

我们将断点打在 DefaultListableBeanFactory#registerBeanDefinition 这个方法入口处,debug 模式运行工程,可以看到断点进入时的情况如下图所示:

这里通过执行堆栈逆向找到 BeanDifinition 的加载入口是容器刷新阶段的 invokeBeanFactoryPostProcessors 方法;这里就详细分析下 testBeanService 这个 beandifition 是怎么被注册到容器中的。

invokeBeanFactoryPostProcessors 执行过程分析

invokeBeanFactoryPostProcessors 这个方法实现非常长,但是基本处理过程很简单,存在很多重复的步骤。为了方便理解整个过程,这里还是有必要贴一下代码,代码中会详细标注所做的事情是什么,这个过程是构建 BeanFactory 非常重要一步。掌握这个过程,就可以随意玩转 BeanFactoryPostProcessor 了。

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();
    // 当前 beanFactory 是否是 BeanDefinitionRegistry 类型
    // 只有是 BeanDefinitionRegistry 类型,才具备注册 beanDefinition 的能力
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 普通的 BeanFactoryPostProcessor 集合
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // BeanDefinitionRegistryPostProcessor 类型处理器集合
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        // 这里 beanFactoryPostProcessors 是在 SharedMetadataReaderFactoryContextInitializer 中加进来的,是 Spring 自己的处理器
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // 如果是 BeanDefinitionRegistryPostProcessor 类型,就加到 registryProcessors
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                // 执行 BeanDefinitionRegistryPostProcessor 后置处理
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                // 否则就放到 regularPostProcessors
                regularPostProcessors.add(postProcessor);
            }
        }

        // 不要在这里初始化 FactoryBeans:需要保留所有未初始化的常规bean,以使 beanFacotryPostProcessor 对其处理!
        // 分离实现 PriorityOrdered,Ordered和其余优先级的 BeanDefinitionRegistryPostProcessor。
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 首先,调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors。
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        // 遍历 BeanDefinitionRegistryPostProcessors
        for (String ppName : postProcessorNames) {
            // 只处理实现 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 符合上述条件的 BeanDefinitionRegistryPostProcessor 放到 currentRegistryProcessors 中,供后面使用
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // 标记当前 postProcessor 已经处理过了
                processedBeans.add(ppName);
            }
        }
        // 排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 调用 BeanDefinitionRegistryPostProcessor 后置处理器
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 接下来,调用实现 Ordered的BeanDefinitionRegistryPostProcessors
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 最后,调用所有其他 BeanDefinitionRegistryPostProcessor,直到不再出现(保证全部处理完)。
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }

        // 现在,调用到目前为止已处理的所有处理器的 postProcessBeanFactory 回调。
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        // 调用在上下文实例中注册的工厂处理器。就是前面提到的 SharedMetadataReaderFactoryContextInitializer 中注册的
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // 这里再次拿到所有的 BeanFactoryPostProcessor
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // 同样将实现 PriorityOrdered、Order 和普通的 BeanFactoryPostProcessor 分离开
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            // 跳过-已在上述第一阶段处理过
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // 首先,调用实现PriorityOrdered的BeanFactoryPostProcessors。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // 优先执行实现 PriorityOrdered 接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // 接下来,调用实现Ordered的BeanFactoryPostProcessors。
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // 执行实现 Ordered 接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // 最后,调用所有其他 BeanFactoryPostProcessor
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // 执行其他没有实现任何优先级接口的 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    // 清除缓存的合并 beanDefinition,因为后处理器可能已经修改了原始元数据
    beanFactory.clearMetadataCache();
}

上面代码段中大体就是,先处理 BeanDefinitionRegistryPostProcessor 类型的 BeanFactoryPostProcessor ,然后再处理普通的 BeanFactoryPostProcessor;在这里处理过程中,会根据一些排序规则来调整各个 BeanFactoryPostProcessor 的执行顺序。

这里先处理 BeanDefinitionRegistryPostProcessor 类型的 BeanFactoryPostProcessor 是一定的,因为需要在这个阶段去注册 BeanDefinition。在 classpath 下的所有 BeanDefinition 都被注册之后,再执行普通 BeanFactoryPostProcessor 的后置回调,这样就可以覆盖所有的 BeanDefinition。

invokeBeanDefinitionRegistryPostProcessors 执行过程分析

在第一次调用 invokeBeanDefinitionRegistryPostProcessors 时,当前的 BeanDefinitionRegistryPostProcessor 只有一个,就是 org.springframework.context.annotation.ConfigurationClassPostProcessor 。

在 ConfigurationClassPostProcessor 类中,会解析 @Configuration、@ComponentScan、@ComponentScans、@Import 等注解。ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口继承了 BeanFactoryPostProcessor 接口,所以 ConfigurationClassPostProcessor 中需要重写 postProcessBeanDefinitionRegistry() 方法和 postProcessBeanFactory() 方法。而 ConfigurationClassPostProcessor 类的作用就是通过这两个方法去实现的。更多细节可以参考 ConfigurationClassPostProcessor源码解析 这篇文章,写的非常 nice。

invokeBeanDefinitionRegistryPostProcessors 处理的核心过程如下:

  • 1、ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry:BeanDefinition 触发加载的入口
  • 2、ConfigurationClassPostProcessor#processConfigBeanDefinitions:解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
  • 3、ComponentScanAnnotationParser#parse:根据注解的属性值来过滤加载 classpath 下的 beanDefinition(默认条件就是 basePackages,默认的 basePackages 为当前启动类的根包)
  • 4、ClassPathBeanDefinitionScanner#doScan:处理 basePackages 下所以的 beanDefinition,被打了 @Service、@Compoment 等注解的类都会被解析到
  • 5、DefaultListableBeanFactory#registerBeanDefinition:将 beanDefinition 注册到 BeanFactory 中(beanDefinitionMap 中)

那么到这里 TestBeanService 的 BeanDefinition 就被注册到 BeanFactory 中了。

BeanFactoryPostProcessor 对 BeanDefinition 的修改

在本篇文章所对应的案例工程中,也实现了一个 BeanFactoryPostProcessor ,没有实现任何排序接口。这个 TestBeanServiceBeanFactoryPostProcessor 的作用是将原来的 TestBeanService 修改为 ProxyTestBeanService。代码如下:

public class TestBeanServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 根据类型拿到所有的 beanNames
        Iterable<String> beanNames = getBeanNames(beanFactory, TestBeanService.class);
        // 这里因为只有一个 TestBeanService ,所以只处理第一个
        beanNames.forEach(beanName -> {
            System.out.println("begin to execute BeanFactoryPostProcessor...");
            BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
            // 先从工程中拿到原始 beanDefinition
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            // 这里构建一个新的 BeanDefinition,类型为 ProxyTestBeanService,ProxyTestBeanService 是 TestBeanService 的子类
            RootBeanDefinition proxy = new RootBeanDefinition(ProxyTestBeanService.class);
            // 这里设置指定的initMethod
            proxy.setInitMethodName(beanDefinition.getInitMethodName());
            // 设置一些属性
            proxy.setPropertyValues(beanDefinition.getPropertyValues());
            proxy.setPrimary(beanDefinition.isPrimary());
            proxy.setRole(BeanDefinition.ROLE_APPLICATION);
            // 将原始 beanDefinition 移除掉
            beanDefinitionRegistry.removeBeanDefinition(beanName);
            // 将代理的新的 beanDefinition 注册进去
            beanDefinitionRegistry.registerBeanDefinition(beanName,proxy);
            System.out.println("current bean type is : " + proxy.getBeanClass().getTypeName());
            return;
        });
    }
}

invokeBeanFactoryPostProcessors 执行过程分析中已经分析了 BeanFactoryPostProcessor 执行的时机和过程,这里不再赘述。TestBeanServiceBeanFactoryPostProcessor 的作用就是先将原始的 TestBeanService 的 Beandefinition 从容器中移除掉,然后构建一个 ProxyTestBeanService 的 Beandefinition,然后注册到容器中,beanName 没有变,所以通过 BeanFactoryPostProcessor 可以修改最原始的 Bean 信息,也可以通过 BeanFactoryPostProcessor 来动态注册一个新的 Bean。

通过监听 ApplicationEnvironmentPreparedEvent 事件修改属性值

上面完成了对 TestBeanService 的 BeanDefinition 的修改,将 TestBeanService 对象换成了 ProxyTestBeanService。前面提到 TestBeanService 中有两个需要注入的值,一个是通过 @Autowired 注入,一个是通过 @Value 注入,先来看 @Value 注入。@Value 注入的值来自 Enviroment,这里关于 Enviroment 和配置解析及构建不多说,本篇中关注的是如何将 @Value 注入的值改变掉。

ApplicationEnvironmentPreparedEvent 事件是在环境准备完成时发送的事件,此时 Enviroment 已经准备好,可以随时为容器刷新提供环境变量支持。那么既然此时容器中的 Enviroment 对象已经 ready ,说明配置的 application.properties、系统参数等均已经被解析好了,而此时目标 Bean 还没有被刷新,其内部需要被注入的属性值还没有被注入,那么此时就可以通过监听这个事件,来对 Enviroment 中已经准备好的值进行修改,以改变实际被注入的值。代码如下:

public class ChangeAppNameListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        // 获取原始 spring.application.name 的值
        String applicationName = environment.getProperty("spring.application.name");
        System.out.println("origin applicationName is : " + applicationName);
        // 修改 spring.application.name
        Properties props = new Properties();
        props.put("spring.application.name", "updateAppName");
        environment.getPropertySources().addFirst(new PropertiesPropertySource("decrypted_properties", props));

        applicationName = environment.getProperty("spring.application.name");
        System.out.println("updated applicationName is : " + applicationName);
    }
}

@Value 注入 & @Autowired 注入

在 Spring 中,无论是 @Value 注入还是 @Autowired 注入,都是由 AutowiredAnnotationBeanPostProcessor 这个后置处理器处理的。

在很多开源的框架中,其内部自定义的注解也大都是通过 BeanPostProcessor 这个后置处理器来处理的。

AutowiredAnnotationBeanPostProcessor 中有个 AutowiredFieldElement 内部类,这个内部类的作用就是注入目标 bean 的属性值的。这里就包括 @Value 的注入和 @Autowired 注入。

Bean 属性注入发生的时机

容器刷新及属性注入调用堆栈如下:

从堆栈看出,在容器刷新的最后阶段,会通过 finishBeanFactoryInitialization 这个方法实例化所有剩余的(非延迟初始化)单例 bean;这个过程就是绝大多数 bean 实例化的过程。这个过程中会涉及到以下两个比较重要的点:1、BeanPostProcessor 处理,2、依赖注入。从上面其实也可以看出,依赖注入的发生就是通过 BeanPostProcessor 处理完成的。下图为遍历所有目标属性,依次注入属性的过程:

Bean 属性注入发生的过程

这里以 @Autowired 注入为例,@Value 注入和 @Autowired 注入过程基本是一样的。@Autowired 注入相比于 @Value 注入,会涉及到初始化另外一个 Bean 的过程。

// 构建一个依赖描述符对象
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// 设置包含此依赖项的具体类
desc.setContainingClass(bean.getClass());
// 初始化一个注入的 beanName 集合,用于后面注册到容器中
// 这里实际上只有一个,如果有多个实例 bean 存在,则需要通过 Qualifier 指定了
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
    // 解析依赖,依赖注入
    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
    // 抛出注入失败异常
    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
    if (!this.cached) {
        if (value != null || this.required) {
            this.cachedFieldValue = desc;
            // 注册依赖的 bean
            registerDependentBeans(beanName, autowiredBeanNames);
            if (autowiredBeanNames.size() == 1) {
                String autowiredBeanName = autowiredBeanNames.iterator().next();
                // 判断容器中是否存在此依赖 bean,并且校验 bean 的类型是否匹配
                if (beanFactory.containsBean(autowiredBeanName) &&
                        beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                    // 缓存注入值
                    this.cachedFieldValue = new ShortcutDependencyDescriptor(
                            desc, autowiredBeanName, field.getType());
                }
            }
        }
        else {
            // 没有找到 依赖bean 实例,且 required 为 false 
            this.cachedFieldValue = null;
        }
        this.cached = true;
    }
}
// value 为解析到的属性值,如果不为空,则通过反射设置给目标 Bean,完成属性的注入
if (value != null) {
    ReflectionUtils.makeAccessible(field);
    field.set(bean, value);
}

属性注入发生在 populateBean(填充 Bean)的过程,在 Bean 属性填充完成之后就是 Bean 的实例化过程。

Bean 的实例化过程

这里截取 AbstractAutowireCapableBeanFactory#doCreateBean 方法中的一小段代码,来承接上下文:

// 初始化bean实例。
Object exposedObject = bean;
try {
    // 填充 Bean
    populateBean(beanName, mbd, instanceWrapper);
    // 实例化 Bean
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    // 省略异常处理
}

这里通过代码就很好的和上一小节的内容关联起来了,即填充 Bean -> 实例化 Bean 。在 Bean 的实例化阶段会涉及到两个比较重要的扩展:1、BeanPostProcessor,2、InitializingBean。

BeanPostProcessor 的处理时机

BeanPostProcessor 有两个抽象方法,一个是实例化之前调用,一个是实例化之后调用。InitializingBean 接口只有一个 afterPropertiesSet 方法,afterPropertiesSet 方法的执行介于实例化之前实例化之后调用之间。BeanPostProcessor 的处理时机是在调用 initializeBean 方法中触发的,下面为 initializeBean 方法中的部分代码片段:

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    // 实例化之前调用
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
    // 调用 InitializingBean 和指定的 init-method 方法
    invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
    throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
    // 实例化之后调用
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

这里的 bean 对象实际上已经是完整的 bean 了,postProcessBeforeInitialization 和 postProcessAfterInitialization 是相对于是否执行 InitializingBean 的 afterPropertiesSet 和执行 Bean 指定的 initMethod 方法而言的。

使用 BeanPostProcessor 修改 Bean

从 initializeBean 方法中可以看出,了,postProcessBeforeInitialization 和 postProcessAfterInitialization 两处回调返回放回的是 wrappedBean,也就意味着我们可以在这两个方法中对容器中的原始 Bean 做一些处理,比如代理一层原始的 Bean,或者修改 Bean 中的一些属性等。

在案例工程中提供了一个 TestBeanServiceProcessor ,其作用是对 TestBeanService 类型的 Bean 做一层代理,使得在执行 TestBeanService 中方法的前后做一些埋点。

// TestBeanServiceProcessor
public class TestBeanServiceProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 如果 bean 的类型是 TestBeanService,则将其包装成 TestBeanWrapperService 并返回
        if (bean instanceof TestBeanService){
            System.out.println("begin to execute postProcessBeforeInitialization.");
            TestBeanWrapperService testBeanService = new TestBeanWrapperService((TestBeanService)bean);
            return testBeanService;
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TestBeanService){
            System.out.println("begin to execute postProcessAfterInitialization.");
        }
        return bean;
    }
}
// 代理类 TestBeanWrapperService,注意这里代理类也应该是 TestBeanService 类型,否在是后面使用时就会找不到 Bean 实例
public class TestBeanWrapperService extends TestBeanService {
    private final TestBeanService delegate;
    public TestBeanWrapperService(TestBeanService delegate){
        this.delegate = delegate;
    }

    /**
     * 实现对 test 方法执行前后进行拦截
     **/
    @Override
    public String test() {
        try {
            before();
            return delegate.test();
        } finally {
            after();
        }
    }

    private void before(){
        System.out.println("before execute test.");
    }

    private void after(){
        System.out.println("after execute test.");
    }
}

使用 InitializingBean

如果一个 bean 集成了 InitializingBean 接口,那么就需要重写其 afterPropertiesSet 方法。这里感觉有点漏洞,afterPropertiesSet 动作其实早就完成了,另外因为 afterPropertiesSet 是在 postProcessAfterInitialization 方法之前调用,所以还是可以在 postProcessAfterInitialization 对属性做修改。实际使用过程中需要关注下这个点,一般情况下,我们会在 afterPropertiesSet 中做一些初始化动作,比如启动连接 Zookeeper。

public class TestBeanService implements InitializingBean {
    // 省略其他代码
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("begin to execute afterPropertiesSet...");
    }
}

指定 Bean 的 init-method 方法

init-method 方法只能通过 @Bean 或者 xml 方式指定,如果是使用 @Component 或者 @Service 注解标准的 Bean ,则可以通过 @PostConstruct 注解标注方法,对应的是 destroy-method 和 @PreDestroy 。

public class TestBeanService implements InitializingBean{
    // 省略其他代码

    // init 方法
    public void init(){
        System.out.println("begin to execute init...");
    }
}
// 在自动配置类或者 xml 文件中指定 initMethod
@Bean(initMethod = "init")
public TestBeanService testBeanService(){
    return new TestBeanService();
}

总结

本篇围绕 TestBeanService 这个 Bean 展开,对其生命周期,及其生命周期各个阶段扩展点进行了介绍,包括修改注入的属性值、修改其 BeanDefinition、修改 Bean 实例等等,从扩展点的视角来洞悉一个 Bean 的生命周期。

BeanFactoryPostProcessor 对于 init-method 的影响

因为 init-method 这个点是后面想起来加上去的,在实际测试过程中,发现 TestBeanService 中指定的 init 方法没有被执行(正常情况下是在 afterPropertiesSet 之后就会执行的);对于这个 TestBeanService 在案例工程中有两处对其进行了修改,一个是修改其 BeanDefinition ,一个是修改 其 Bean 实例;最终拿到的 bean 的类型是 TestBeanWrapperService,在此之前 Bean 的类型是 ProxyTestBeanService ,无论是TestBeanWrapperService 还是 ProxyTestBeanService 都是 TestBeanService 的子类,init 方法又是 public 的,所以从这个角度来看,不可能不生效。所以基本可以排除因为访问权限问题导致。最后 debug 下面代码发现,mbd.getInitMethodName() 返回的是 null, mbd 是 RootBeanDefinition;

PS: BeanDefinition 中 getInitMethodName 方法是在 Spring 5.1 版本之后才有的,之前版本都是 在 AbstractBeanDefinition 这个抽象类中定义。

if (mbd != null && bean.getClass() != NullBean.class) {
    // 从当前 bean  的 BeanDefinition 对象中获取 initMethod 方法名
    String initMethodName = mbd.getInitMethodName();
    if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
        invokeCustomInitMethod(beanName, bean, mbd);
    }
}

问题出在这里,在 TestBeanServiceBeanFactoryPostProcessor 处理时,没有将原始 BeanDefinition 的 initMethod 给新的 ProxyTestBeanService,所以导致后面所有基于此实例化的 bean 的 BeanDefinition 都没有 initMethod 方法。在TestBeanServiceBeanFactoryPostProcessor#postProcessBeanFactory 方法中补充设置 InitMethodName 之后问题解决。

// 这里设置指定的initMethod
proxy.setInitMethodName(beanDefinition.getInitMethodName());

附:案例工程地址及参考

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

glmapper_2018

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值