likes
comments
collection
share

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

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

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

推荐阅读

本文内容

阅读之前TestBeanService 被解析成 BeanDifinition 的时机与过程invokeBeanFactoryPostProcessors 执行过程分析invokeBeanDefinitionRegistryPostProcessors 执行过程分析BeanFactoryPostProcessor 对 BeanDefinition 的修改通过监听 ApplicationEnvironmentPreparedEvent 事件修改属性值@Value 注入 & @Autowired 注入Bean 属性注入发生的时机Bean 属性注入发生的过程Bean 的实例化过程BeanPostProcessor 的处理时机使用 BeanPostProcessor 修改 Bean使用 InitializingBean指定 Bean 的 init-method 方法总结BeanFactoryPostProcessor 对于 init-method 的影响附:案例工程地址及参考

阅读之前

继续承接上一篇 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 模式运行工程,可以看到断点进入时的情况如下图所示:

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

这里通过执行堆栈逆向找到 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, truefalse);        // 遍历 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, truefalse);        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, truefalse);            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, truefalse);    // 同样将实现 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 属性注入发生的时机

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

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

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

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

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 中方法的前后做一些埋点。

// TestBeanServiceProcessorpublic 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 之后问题解决。

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

附:案例工程地址及参考

转载自:https://juejin.cn/post/6844904020721532942
评论
请登录