zoukankan      html  css  js  c++  java
  • Spring Bean的生命周期

     Spring容器可以管理singleton作用域的Bean的生命周期,可以调用创建、初始化、销毁等生命周期的方法。

    对于prototype作用域的Bean,Spring容器只负责创建,创建后Bean的实例就交给客户端代码来管理,Spring容器不再跟踪其生命周期。


    Bean的生命周期

    1、检查此Bean是否有依赖的Bean,如果所依赖的Bean尚未实例化,则先实例化依赖的bean;

       如果依赖的bean都已实例化,则调用此Bean的构造方法或工厂方法创建此Bean的实例

    2、利用依赖注入注入所需依赖(给成员变量赋值)

    3、如果Bean实现了BeanNameAware接口,则调用setBeanName()方法传入当前Bean的name。

    4、如果Bean实现了BeanFactoryAware接口,则调用setBeanFactory()传入当前工厂实例的引用

    5、如果Bean实现了ApplicationContextAware接口,则调用setApplicationContext()方法传入当前ApplicationContext实例的引用

    6、如果BeanPostProcessor和Bean关联,则调用预初始化方法postProcessBeforeInitialzation()进行加工操作,Spring AOP即利用此实现。

    7、容器前处理(可以实现一些自定义的操作)

    8、如果BeanPostProcessor和Bean关联,则调用初始化方法postProcessAfterInitialization()。此时,Bean已经可以被正常使用了。

    9、如果指定了作用域为singleton,则将实例放在Spring IoC的缓存池中,并触发Spring容器对该Bean的生命周期管理,如果指定作用域为prototype,则将该Bean交给调用者,由调用者管理该Bean的生命周期。

    10、容器后处理(销毁bean的实例时要做的操作)

     

    说明:

    以上接口中,均只有一个方法。

    并不建议让Bean实现多个接口,因为继承多个接口会使代码耦合较高。


    容器前处理

    将bean的实例放到spring容器之前做一些处理。

    有3种方式可以实现容器前处理:

    • 使用@PostConstruct标注要调用的方法
    • 实现InitializingBean接口,在afterPropertiesSet()中写代码
    • 在xml中使用init-method属性指定要调用的方法

    容器后处理

    在spring容器销毁bean的实例之前做一些处理。

    同样有3种方式可以实现容器后处理:

    • 使用@PreDestroy标注要调用的方法
    • 实现DisposableBean接口,在destory()中写代码
    • 在xml中使用destory-method属性指定要调用的方法

    不管是容器前处理,还是容器后处理,这三种方式都可以一起使用。

    一起使用时,都是先执行注解标注的方法,再执行接口中的方法,最后执行xml中指定的方法。

    有的教程说 init-method <=> @PostConstruct , destroy-method  <=>  @PreDestroy,

    如果只使用三种中的一种,这三种的效果是一样的,这句话是对的;

    如果同时使用2种或3种,则执行有先后之分,这句话是错的。

      


    lazy-init

    <bean name="" class="" lazy-init="true" />

    默认scope="singleton",spring容器启动时就实例化scope="singleton"的bean。

    lazy-init配置是否延迟加载bean:

    • true   延迟加载,需要时才创建
    • false   默认值。不延迟加载,spring容器启动时就实例化scope="singleton"的bean

    虽然所有<bean>都能配置lazy-init,但lazy-init属性只对scope="singleton"的<bean>起作用。


     

    示例

    依赖:

    @Component
    @Scope("prototype")
    public class B {
        public B(){
            System.out.println("正在创建B类实例...");
        }
    }

    为避免B类在spring容器启动时就创建实例,将其作用域设置为prototype。

    主调类:

    @Component
    public class A implements InitializingBean, DisposableBean {
        private B b;
    
        @Autowired
        public A(B b) {
            System.out.println("正在执行A的构造函数...");
            this.b = b;
        }
    
        @PostConstruct
        public void postConstruct(){
            System.out.println("正在执行@PostConstruct注解指定的方法...");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("正在执行InitializingBean接口中的afterPropertiesSet()方法...");
        }
    
        public void xmlInit(){
            System.out.println("正在执行xml中init-method指定的方法...");
        }
    
        @PreDestroy
        public void preDestroy(){
            System.out.println("正在执行@PreDestroy注解指定的方法...");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("正在执行DisposableBean接口中的destroy()方法...");
        }
    
        public void xmlDestroy(){
            System.out.println("正在执行xml中destroy-method指定的方法...");
        }
    }

    xml配置:

    <?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 https://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.chy.bean"/>
        <bean name="a" class="com.chy.bean.A" init-method="xmlInit" destroy-method="xmlDestroy" />
    </beans>

    测试类:

    public class Test {
        public static void main(String[] args) {
            //创建spring容器的实例(会实例化所有scope="singleton"的bean)
            ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-config.xml");
    
            //关闭spring容器(会销毁所有spring容器中的bean实例)
            applicationContext.close();
        }
    }

    在基于Web的Spring容器中,WEB服务器(比如Tomcat)已经提供了对应的设置,在Web应用关闭时,会自动关闭Spring容器。

    在非Web的Spring容器中,需要手动调用close()方法关闭spring容器。

    ApplicationContext即Spring容器,是一个接口,没有声明close()方法,如果把spring容器声明为ApplicatioContext,则不能使用close()方法。

    ApplicationContext的实现类提供了close()方法,要声明为实现类(比如ClassPathXmlApplicationContext)才能使用close()方法。

    运行程序,控制台输出如下:

    正在创建B类实例...
    正在执行A的构造函数...
    正在执行@PostConstruct注解指定的方法...
    正在执行InitializingBean接口中的afterPropertiesSet()方法...
    正在执行xml中init-method指定的方法...
    正在执行@PreDestroy注解指定的方法...
    正在执行DisposableBean接口中的destroy()方法...
    正在执行xml中destroy-method指定的方法...

    执行过程分析:

    A依赖B,B是prototype,需要时才创建实例,A是singleton,spring容器启动时就创建实例。

    (1)A所依赖的B尚未实例化,先创建B的实例

    (2)创建A的实例,注入B的实例

    (3)执行容器前处理(先注解,再接口,最后xml)

    (4)A的作用域是singleton,将创建的A的实例放到spring容器中(如果是prototype,则不放到容器中)

    (5)spring容器关闭,销毁spring容器中所有的bean,执行容器后处理,销毁A的实例。

  • 相关阅读:
    北京除了木樨园哪里有卖布料的?要高级布料,不要那种便宜的小摊。
    郭培_百度百科
    木樨园批发市场淘布归来
    九头身美女_百度百科
    「花田对」CSDN程序员专场——谁来拯救技术宅!_豆瓣
    时间囊咖啡馆免费提供小型活动场地_豆瓣
    北京的布料市场
    适合入门自学服装裁剪滴书(更新ing)
    不说技术~2016-07-02我们是幸福的一家人
    插件~使用ECharts动态在地图上标识点~动态添加和删除标识点
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/11123792.html
Copyright © 2011-2022 走看看