前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring中Bean的生命周期了解一下,面试不怕被问

Spring中Bean的生命周期了解一下,面试不怕被问

作者头像
码农飞哥
发布2021-08-18 10:46:42
1.1K0
发布2021-08-18 10:46:42
举报
文章被收录于专栏:好好学习

前言

上一篇我们介绍了Spring IOC容器的启动过程以及bean的实例化过程,这一篇我们接着来学习另外一个知识点,就是Bean的生命周期,我们知道直接通过(new XX())来创建的实例,当这个实例没有被引用时就会被垃圾回收机制回收,但是通过IOC容器实例化的Bean的生命周期又是如何呢?IOC容器负责管理容器中所有的bean的生命周期,而在bean生命周期的不同阶段,Spring提供了不同的扩展点来改变bean的命运。当然容器只能帮助我们管理单例模式bean的完整生命周期,对于property的bean,Spring在创建好交给使用者之后则不会在管理后续的生命周期。

自定义扩展类

如果我们要自定义一个扩展类,通常需要实现 org.springframework.beans.factory.config.BeanFactoryPostProcessor接⼝,它是Spring对外提供的用来拓展Spring的接口,能够在Spring容器加载了所有bean的信息之后、bean实例化之前执行。他修改bean的定义属性;其中 PropertyResourceConfigurer就是 BeanFactoryPostProcessor的典型应用, PropertyResourceConfigurer可以将Xml文件中的占位符替换成属性文件中相应key对应的value值。下面以常见的数据库的连接配置举例说明一下:

  1. Spring的配置文件如下:
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context.xsd

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
        <list>
            <value>classpath:mysqldb.properties</value>
        </list>
        </property>
    </bean>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName"value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}"/>
        <property name="password"value="${jdbc.password}" />
    </bean>
</beans>
  1. 属性文件---mysqldb.properties
代码语言:javascript
复制
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis
jdbc.username=root
jdbc.password=root
  1. PropertyResourceConfigurer类的继承结构如下:

上述占位符的例子只是 BeanFactoryPostProcessor的应用之一,但这是Spring提供的拓展,不是我们自定义的,在实际项目中,我们可以通过自定义 BeanFactoryPostProcessor来实现敏感信息的解密处理,例如数据库的连接配置中的,密码我们可以配置成密文,这样就可以防止泄密的风险。解密处理的操作实例如下所示:我们自定义了 AESPropertyPlaceholderConfigurer类继承了 PropertyPlaceholderConfigurer类,然后重写 processProperties方法。

代码语言:javascript
复制
public class AESPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
            throws BeansException {
        String key = "jdbc.password";
        String aeskey = "0123456789012345";
        Object password = props.get(key);
        if (password != null) {
            try {
                props.put(key, AESUtil.decrypt(password.toString(), aeskey));
            } catch (Exception e) {
                log.warn("数据库密码错误", e);
            }
        }
        super.processProperties(beanFactoryToProcess, props);
    }

}

Bean的生命周期

说完了自定义扩展类,下面让我们来看看Bean的生命周期。首先,让我们看一下容器的生命周期以及其管理的Bean的生命周期。图中背景为绿色的部分就是Bean的生命周期。

说明

Bean的完整生命周期经历了各种方法的调用,这些方法可以划分为以下几类:

  1. Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中 <bean>init-methoddestroy-method指定的方法。
  2. Bean级生命周期接口方法:这个包括 BeanNameAwareInitializingBeanDiposableBean这些接口的方法。
  3. 容器级生命周期接口方法:这个包括了 BeanFactoryProcessor接口和 InstantiationAwareBeanPostProcessor接口。
  4. 工厂后处理器接口方法:这个包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

流程说明

1. Bean的实例化

  1. Spring对Bean进行实例化(相当于 new XXX()),对于 BeanFactory一般是延迟实例化,就是说调用 getBean方法才会实例化,但是对于 ApplicationContext,当容器初始化完成之后,就完成了所有Bean的实例化工作。实例化的对象被包装在 BeanWrapper对象中, BeanWrapper提供了设置对象属性的接口,从而避免了使用反射机制设置属性。

2. InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor这个接口主要是帮助你在Bean实例化之前做一些操作。它继承自 BeanPostProcessor接口,其中 postProcessBeforeInstantiation()方法是在目标对象实例化之前调用的方法,可以返回目标实例的一个代理用来代替目标实例。postProcessPropertyValues方法是在属性值被设置到目标实例之前调用,可以修改属性的设值。

3. 设置属性(依赖注入)

实例化后的对象被封装到 BeanWrapper对象中,并且此时对象是一个原生状态,并没有执行依赖注入。紧接着,Spring根据 BeanDefinition中的信息进行依赖注入。并且通过 BeanWrapper提供的设置属性的接口完成依赖注入。

4. 注入Aware接口

Spring 会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean。各种各样的Aware接口,其作用就是在对象实例化完成后将Aware接口定义中规定的依赖注入到当前实例中。比较常见的 ApplicationContextAware接口,实现了这个接口的类都可以获取到一个 ApplicationContext对象,当容器中每个对象的实例化过程走到 BeanPostProcessor前置处理这一步时,容器会检测到之前注册到容器的 ApplicationContextAwareProcessor,然后就会调用其 postProcessorBeforeInitialization()方法,检查并设置Aware相关的依赖。示例如下:

代码语言:javascript
复制
@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
        System.out.println("========ApplicationContext配置成功========");
    }
    }

5. BeanPostProcessor的postProcessBeforeInitialzation方法

经过上述步骤后,Bean对象已经被正确构造了,如果你想要对象被使用之前在进行自定义的处理,可以通过 BeanPostProcessor接口实现。该接口提供了两个方法 其中 postProcessBeforeInitialzation(Objectbean,StringbeanName) 方法;当前正在初始化的bean对象会被传递进来,我们就可以对这个Bean做任何处理,这个方法会先于 InitializingBean执行,因此称为前置处理。

6. InitializingBean与init-method

如果Bean实现了 InitializingBean接口,Spring将调用它们的 afterPropertiesSet方法,作用与在配置文件中对Bean使用 init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。afterPropertiesSet 方法与前置处理不同的是,由于其没有把Bean对象传进来,因此在这一步没有办法处理对象本身,只能增加一些额外的逻辑。

7.BeanPostProcess的postProcessAfterInitialzation方法

BeanPostProcesspostProcessAfterInitialzation(Objectbean,StringbeanName) 方法;当前正在初始化的bean对象会被传递进来,我们就可以对这个bean做任何处理。这个函数会在 InitializingBean完成后执行,因此称为后置处理。

8. Bean初始化结束

经过以上的工作以后,Bean的初始化就结束了,Bean将一直驻留在应用上下文中给应用使用,知道应用上下文被销毁。

9. DispostbleBean接口

如果Bean实现了 DispostbleBean接口,Spring将调用它的 destroy方法,作用与在配置文件中对Bean使用 destroy-method属性的作用是一样的,都是在Bean实例销毁前执行的方法。

完整的执行demo示例

总结

本文首先介绍了如何自定义扩展类,对 BeanFactoryProcessor接口的作用做了详细阐述,并介绍了其实现类 PropertyResourceConfigurer,这个实现类的作用就是讲占位符替换成属性文件中对应的属性值,紧接着就是介绍了如果自定义扩展类,通过数据库连接密码解密为例说明。第二部分就是介绍了Spring容器管理的Bean的完整生命周期,在Bean生命周期的不同阶段,Spring提供了不同的扩展点用来改变Bean的命运。希望本文对读者朋友们有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农飞哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 自定义扩展类
  • Bean的生命周期
    • 说明
    • 流程说明
      • 1. Bean的实例化
        • 2. InstantiationAwareBeanPostProcessor
          • 3. 设置属性(依赖注入)
            • 4. 注入Aware接口
              • 5. BeanPostProcessor的postProcessBeforeInitialzation方法
                • 6. InitializingBean与init-method
                  • 7.BeanPostProcess的postProcessAfterInitialzation方法
                    • 8. Bean初始化结束
                      • 9. DispostbleBean接口
                      • 完整的执行demo示例
                      • 总结
                      相关产品与服务
                      容器服务
                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档