1. 引言
本篇博客主要学习和联系Spring框架中bean的创建和销毁顺序,以及如何自定义bean的生命周期。
使用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种:
- 先创建的后销毁,后创建的先销毁