• Spring中bean创建和销毁的顺序


    1. 引言

    本篇博客主要学习和联系Spring框架中bean的创建和销毁顺序,以及如何自定义bean的生命周期。

    参考博文:https://itsoku.blog.csdn.net/article/details/104368546

    使用vscode部署Spring项目过程略。

    2. 无依赖注入的bean的创建和销毁

    2.1 创建两个独立的类

    2.1.1 类LiwanLiangImpl

    创建接口LiwanLiang.java

    package com.liwl.dev;
    
    import org.springframework.beans.factory.DisposableBean;
    
    public interface LiwanLiang extends DisposableBean{
        
    }
    

    DisposableBean接口

    创建实现类LiwanLiangImpl.java

    package com.liwl.dev;
    
    public class LiwanLiangImpl implements LiwanLiang{
        
        private String name;
        private int age;
    
        public LiwanLiangImpl(){
            System.out.println("调用LiwanLiangImpl bean 无参构造方法");
        }
    
        public LiwanLiangImpl(String name,int age,School school){
            System.out.println("调用LiwanLiangImpl bean 有参构造方法");
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "name:" + name +","+ "age:"+age;
        }
        
        @Override
        public void destroy() throws Exception {
            System.out.println("LiwanLiangImpl bean 销毁");
        }
    }
    

    2.1.2 类CompanyImpl

    package com.liwl.dev;
    
    import org.springframework.beans.factory.DisposableBean;
    
    public interface Company extends DisposableBean {
        
    }
    
    package com.liwl.dev;
    
    public class CompanyImpl implements Company {
    
        private String name;
        private String address;
    
        public CompanyImpl(){
            System.out.println("调用CompanyImpl bean 无参构造方法");
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String company) {
            this.name = company;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return return "[Company bean]" + ",name:" + name + ",address:" + address;
        }
        
        @Override
        public void destroy() throws Exception {
            System.out.println("CompanyImpl bean 销毁");
            
        }
    }
    

    2.2 运行测试

    修改springdi.xml

    <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">
    
        <import resource="liwanliang.xml"/>
        <import resource="company.xml"/>
    
    </beans>
    

    修改liwanliang.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" autowire="byName">
            <property name="name" value="liwl" />
            <property name="age" value="30"/>
        </bean>
    </beans>
    

    修改company.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <bean id="company" class="com.liwl.dev.CompanyImpl">
            <property name="name" value="nsccwx"/>
            <property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
        </bean>
    
    </beans>
    

    修改LiwlTest.java

    package com.liwl.dev;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class LiwlTest {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springdi.xml");
            LiwanLiangImpl liwl001 = (LiwanLiangImpl) context.getBean("liwl001");
            CompanyImpl work = (CompanyImpl) context.getBean("company");
            System.out.println(liwl001);
            System.out.println(work);
            context.close();
        }
    }
    

    运行结果

    调用LiwanLiangImpl bean 无参构造方法
    调用CompanyImpl bean 无参构造方法
    [LiwanLiangImpl bean],name:liwl001,age:30
    [CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号
    CompanyImpl bean 销毁
    LiwanLiangImpl bean 销毁
    

    这个结果看到:

    Spring先创建LiwanLiangImpl的bean,然后创建CompanyImpl的bean。销毁bean的过程,先销毁CompanyImpl bean,后销毁LiwanLiangImpl bean。

    调整spingdi.xml里面内容如下

    <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">
    
        <import resource="company.xml"/>
        <import resource="liwanliang.xml"/>
    
    </beans>
    

    运行结果

    调用CompanyImpl bean 无参构造方法
    调用LiwanLiangImpl bean 无参构造方法
    [LiwanLiangImpl bean],name:liwl001,age:30
    [CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号
    LiwanLiangImpl bean 销毁
    CompanyImpl bean 销毁
    

    从上面的配置和运行结果,可得出结论:

    bean的创建顺序与xml中定义bean的一致,而销毁的顺序与xml定义bean的顺序相反

    3. 通过构造方法注入的bean的创建和销毁

    本节让类LiwanLiangImpl依赖SchoolImpl,SchoolImpl依赖CompanyImpl,通过测试验证Spring创建和销毁bean时的顺序

    3.1 创建依赖类

    3.1.1 类LiwanLiangImpl

    package com.liwl.dev;
    
    public class LiwanLiangImpl implements LiwanLiang{
        
        private String name;
        private int age;
        private School school;
    
        public LiwanLiangImpl(){
            System.out.println("调用LiwanLiangImpl bean 无参构造方法");
        }
    
        public LiwanLiangImpl(String name,int age,School school){
            System.out.println("调用LiwanLiangImpl bean 有参构造方法");
            this.name = name;
            this.age = age;
            this.school = school;
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
    
        public School getSchool() {
            return school;
        }
    
        public void setSchool(School school) {
            this.school = school;
        }
    
        @Override
        public String toString() {
            return "[LiwanLiangImpl bean]" + ",name:" + name + ",age:" + age + ",school:" + school;
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("LiwanLiangImpl bean 销毁");
        }
    }
    

    3.1.2 类SchoolImpl

    package com.liwl.dev;
    
    public class SchoolImpl implements School{
    
        private String name;
        private String address;
    
        public SchoolImpl(){
            System.out.println("调用SchoolImpl bean 无参构造方法");
        }
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "[SchoolImpl bean]" + ",name:" + name + ",address:" + address;
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("SchoolImpl bean 销毁");
        }
    }
    
    

    3.2 运行测试

    修改spring.xml

    <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">
    
        <import resource="company.xml"/>
        <import resource="school.xml"/>
        <import resource="liwanliang.xml"/>
    
    </beans>
    

    修改LiwlTest.java

    package com.liwl.dev;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class LiwlTest {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springdi.xml");
            LiwanLiangImpl liwl001 = (LiwanLiangImpl) context.getBean("liwl001");
            System.out.println(liwl001);
            context.close();
        }
    }
    

    运行结果

    调用CompanyImpl bean 无参构造方法
    调用SchoolImpl bean 有参构造方法
    调用LiwanLiangImpl bean 有参构造方法
    [LiwanLiangImpl bean],name:liwanliang-xml,age:30,school:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号
    LiwanLiangImpl bean 销毁
    SchoolImpl bean 销毁
    CompanyImpl bean 销毁
    

    修改spring.xml

    <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">
    
        <import resource="liwanliang.xml"/>
        <import resource="school.xml"/>
        <import resource="company.xml"/>
    
    </beans>
    

    运行结果

    调用CompanyImpl bean 无参构造方法
    调用SchoolImpl bean 有参构造方法
    调用LiwanLiangImpl bean 有参构造方法
    [LiwanLiangImpl bean],name:liwanliang-xml,age:30,school:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号
    LiwanLiangImpl bean 销毁
    SchoolImpl bean 销毁
    CompanyImpl bean 销毁
    

    结论:

    • 通过构造方法注入时的bean,与xml配置顺序无关

    • bean对象的创建顺序和bean的依赖顺序一致。school的创建company,所以company先创建。liwanliang依赖school,所以school先创建

    • bean对象的销毁顺序和bean创建的顺序相反。最先创建的company最后销毁,最后创建的liwanliang最先销毁

    4. 通过depend-on干预bean的创建和销毁顺序

    通过xml配置,可以设置无依赖bean的创建顺序。通过强依赖,也可以调整bean的创建顺序。

    对于大量不存在强依赖关系的bean,如果想要调整bean的创建和销毁顺序,如果要调整xml或者强依赖,这样的操作不够优雅。

    Spring提供了depend-on的方式来解决这样的问题。

    depend-on的使用方式

    <bean id="bean1" class="类全名" depend-on="bean2,bean3,bean4" />
    

    即通过depend on标签设置当前bean1的依赖,多个依赖用逗号隔开。

    此时无论bean2,bean3,bean4在任何地方,都可以确保bean1在创建之前,先把bean2,bean3,bean4创建好。

    bean1可能会依赖于bean2,bean3,bean4中的一些资源或者其他功能,但又没有强制去bean1类中通过属性定义去依赖bean2,bean3,bean4

    本节让类LiwanLiangImpl依赖SchoolImpl,CompanyImpl,通过测试验证depend-on对创建和销毁bean时的顺序干预

    4.1 修改LiwanLiangImpl

    package com.liwl.dev;
    
    public class LiwanLiangImpl implements LiwanLiang{
        
        private String name;
        private int age;
        private School school;
        private Company company;
    
        public LiwanLiangImpl(){
            System.out.println("调用LiwanLiangImpl bean 无参构造方法");
        }
    
        public LiwanLiangImpl(String name,int age,School school){
            System.out.println("调用LiwanLiangImpl bean 有参构造方法");
            this.name = name;
            this.age = age;
            this.school = school;
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
    
        public School getSchool() {
            return school;
        }
    
        public void setSchool(School school) {
            this.school = school;
        }
    
        public Company getCompany() {
            return company;
        }
    
        public void setCompany(Company company) {
            this.company = company;
        }
    
    
        @Override
        public String toString() {
            return "[LiwanLiangImpl bean]" + ",name:" + name + ",age:" + age + ",school:" + school + ",company:" + company;
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("LiwanLiangImpl bean 销毁");
        }
    }
    

    4.2 运行测试

    修改sprindi.xml

    <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">
    
        <bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byName">
            <property name="name" value="liwl" />
            <property name="age" value="30"/>
        </bean>
    
        <bean id="school" class="com.liwl.dev.SchoolImpl">
            <property name="name" value="jiangnan"/>
            <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
        </bean>
    
        <bean id="company" class="com.liwl.dev.CompanyImpl">
            <property name="name" value="nsccwx"/>
            <property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
        </bean>
    
    
    </beans>
    

    运行结果如下

    调用SchoolImpl bean 无参构造方法
    调用CompanyImpl bean 无参构造方法
    调用LiwanLiangImpl bean 无参构造方法
    [LiwanLiangImpl bean],name:liwl,age:30,school:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号,company:[CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号
    LiwanLiangImpl bean 销毁
    CompanyImpl bean 销毁
    SchoolImpl bean 销毁
    

    修改springdi.xml

    <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">
    
        <bean id="school" class="com.liwl.dev.SchoolImpl">
            <property name="name" value="jiangnan"/>
            <property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
        </bean>
    
        <bean id="company" class="com.liwl.dev.CompanyImpl">
            <property name="name" value="nsccwx"/>
            <property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
        </bean>
    
        <bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byName">
            <property name="name" value="liwl" />
            <property name="age" value="30"/>
        </bean>
    
    </beans>
    

    结论:SchoolImpl和CompanyImpl被LiwanLiangImpl依赖,他们先于LiwanLiangImpl创建,而销毁则是晚于LiwanLiangImpl。

    5. 总结

    • bean的创建顺序有3种:
      • 无依赖的bean,bean的创建跟xml定义的顺序有关
      • 有依赖的bean,先创建bean 依赖的其他bean
      • 大量不知道是否有依赖的bean,通过depend-on指定依赖关系,depend-on指定的bean先创建
    • bean的销毁顺序只有1种:
      • 先创建的后销毁,后创建的先销毁
  • 相关阅读:
    对我人生影响最大的三位老师
    自我介绍
    转-一般产品的使用过程
    谷歌浏览器开发调试工具中Sources面板 js调试等 完全介绍 --转载
    接口测试--总结
    常见正则表达式
    B/S架构的软件,主要的功能测试点有哪些
    SQL语句大全转
    11.2
    11.1
  • 原文地址:https://www.cnblogs.com/liwanliangblog/p/15927453.html
Copyright © 2020-2023  润新知