SpringBoot Bean的生命周期

5 篇文章 0 订阅
1 篇文章 0 订阅

一般情况下,我们只是关心如何正确地将Bean装配到容器中,并不关心Ioc容器是如何装配和销毁Bean的过程。但是恰恰有时候,我们需要自定义初始化或销毁Bean的过程,以满足一些“特殊的”需求。比如,数据源在关闭的时候调用其close方法,这是项目开发过程中很常见的需求。


Bean的生命周期大致可以分为4个部分:
1. Bean的定义
2. Bean的初始化
3. Bean的生存期
4. Bean的销毁


Bean的定义
  1. 资源定位的过程。
    如使用@ComponentScan定义的扫描路径去找@Component的类(PS:现在启动类@SpringBootApplication会直接扫描本包内的@Compnent注释的类)

  2. 解析资源并保存定义。

  3. Spring IoC容器装载Bean定义。
    (PS:此时还是没有实例化Bean)

Bean的生命周期

完成了以上三步,还没有实例化的生成,更没有完成依赖注入。默认情况下,Spring会继续完成Bean的实例化和依赖注入。
但是在某些情况下,我们希望Spring 在装载Bean之后,不采取自动实例化和依赖注入,而是在我们要取出这个Bean的时候再执行初始化等操作。

ComponentScan中还有一个配置项lazyInit,默认值为false,就是说不会延迟初始化。但我们将其配置为true时,将会执行延迟初始化。但在spring boot中,这个配置项目即使配置了也可能无效,具体看下面的方法。

资源定位
解析Bean的定义
装载Bean的定义
实例化
依赖注入DI
  • 解析Bean定义后会将定义保存在BeanDefinition实例中。
  • 依赖注入例如@Autowired注入的资源。
  • 默认情况下,在Spring IoC容器初始化的时候,Bean将会自动实例化和注入。如果不想跟随Ioc容器初始化,在Spring web开发中可以通过以下步骤进行延迟加载(缺少一个都不能实现):
    1. 首先在对应实体类上面加上@Lazy注解。
    2. 然后在@Autowired注解引用该Bean的地方同时再加上@Lazy注解。
    3. 使用@Bean注入的地方(如果有)也要加上@Lazy。
      在这里插入图片描述
接口BeanNameAware

Spring容器在初始化和销毁Bean之前,会自动回调BeanNameAware中的setName方法。

接口BeanFactoryAware

Spring容器会继getName方法后自动回调BeanFactoryAware中的setBeanFactory方法。

接口ApplicationContextAware

需要容器实现ApplicationContext接口才会被调用。ApplicationContext是BeanFactory的子接口,BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例化目标Bean。而ApplicationContext在初始化上下文时就实例化所有单实例的Bean。基于注解配置的应用上下文的IoC容器实现了AnnotationConfigApplicationContext,它就是ApplicationContext接口的一个实现类,默认实例化DefaultListableBeanFactory工厂
示范Bean:

@Component
@Data
public class Animal implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
    private String name;
    private Integer age;
    private String cry;
    @Override
    public void setBeanName(String name) {
        System.out.println("Animal被赋予了姓名:" + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Animal被工厂创建了出来:" + beanFactory.getClass().getName());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("加载容器环境中:" + applicationContext.getClass().getName());
    }
}

控制台输出:

Animal被赋予了姓名:animal
Animal被工厂创建了出来:org.springframework.beans.factory.support.DefaultListableBeanFactory
加载容器环境中:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
接口BeanPostProcessor

接口代码:

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法调用后(即afterPropertiesSet方法后)被调用
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

这个接口的方法改写,会对该容器中所有的bean都生效。

@PostConstruct

写上这个注释的方法就是自定义初始化方法了,没什么好说的。

接口InitializingBean

继承该接口后,再实现afterPertiesSet方法。到此实例化完成,进入生存期。

接口BeanPostProcessor

回调postProcessAfterInitialization方法。针对所有Bean有效。

@PreDestory

写上这个注释的方法就是自定义销毁方法了,没什么好说的。

接口DisableBean

继承该接口,再实现dstory方法。到这里,Spring中一个Bean的生命周期结束了。
只要继承、使用了以上任意接口或注解,延迟加载的配置将会失效。
demo项目地址:项目地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值