Spring基于xml配置bean的练习

1. 项目基本配置

本文最后更新时间:2022年2月26号

远程物理机上面部署的node99,我创建了一个目录/root/liwldev/java/web/spring

创建项目SpringXML:mvn archetype:generate -DgroupId=com.liwl.dev -DartifactId=SpringXML -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

使用vscode远程连接node99开始练习

2. set设值注入

在pom.xml添加以下内容:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.liwl.dev</groupId>
  <artifactId>SpringXML</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>SpringXML</name>
  <url>http://maven.apache.org</url>

  <properties>
      <spring.version>5.3.15</spring.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
  
     <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
     </dependency>
      
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <source>17</source>
          <target>17</target>
          <encoding>UTF8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

在目录/root/liwldev/java/web/spring/SpringXML/src/main下创建resources目录,在该目录下再创建beans.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">

</beans>

在目录/root/liwldev/java/web/spring/SpringXML/src/main/java/com/liwl/dev下创建Person.java和PersonImpl.java文件

Person.java源码文件内容如下:

package com.liwl.dev;

public interface Person {
    
}

PersonImpl.java源码文件内容如下:

package com.liwl.dev;

public class PersonImpl01 implements Person {
    
    private String name;
    private int age;

    public PersonImpl01(){
        System.out.println("[PersonImpl01] 无参构造方法调用");
    }

    public PersonImpl01(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("[PersonImpl01] 有参构造方法调用");
    }

    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 + "\nage:" + age;
    }
}

在beans.xml里面配置bean,内容如下:

<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="liwl" class="com.liwl.dev.PersonImpl01">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

</beans>

在目录/root/liwldev/java/web/spring/SpringXML/src/test/java/com/liwl/dev下创建MyTest.java,内容如下:

package com.liwl.dev;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        PersonImpl01 liwl = (PersonImpl01) context.getBean("liwl");
        System.out.println(liwl);
        context.close();
    }
}

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
name:liwanliang
age:30

至此 ,一个使用spring框架xml配置bean的过程便完成了。

3. 构造方法注入

第二节中通过xml配置的标签property,这个是 使用了set设值方法配置的bean。本节练习使用构造方法配置bean。

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01">
        <constructor-arg name="name" value="liwanliang"/>
        <constructor-arg name="age" value="30"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl01] 有参构造方法调用
name:liwanliang
age:30

从结果能够看出,spring在创建PersonImpl的对象bean时,调用了有参构造函数。

4. 引用类型的注入

第二节中通过标签property配置的只是bean的基本数据类型属性。本节练习通过beans.xml注入引用类型。

先创建School.java和SchoolImpl.java源文件

School.java源文件

package com.liwl.dev;

public interface School {
    
}

SchoolImpl.java

package com.liwl.dev;

public class SchoolImpl implements School {
    
    private String name;
    private String address;

    public SchoolImpl(){
        System.out.println("[SchoolImpl] 无参构造方法调用");
    }

    public SchoolImpl(String name,String address){
        this.name = name;
        this.address = address;
        System.out.println("[SchoolImpl] 有参构造函数调用");
    }

    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 "name:" + name + "\naddress:" + address;
    }
}

在beans.xml里面配置bean,如下:

<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="liwl" class="com.liwl.dev.PersonImpl01">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
name:liwanliang
age:30
school:name:jiangnan
address:wuxi

可以看到在beans.xml里面配置了<property name="school" ref="school"/>,以此将SchoolImpl的bean对象注入到PersonImpl里面。

5. import标签

本节主要是对xml配置标签import的练习。

当一个项目变得复杂的时候,有必要进行模块化处理。xml同样可以分为多个xml配置文件,并且在主配置文件里面通过import标签引入。

修改beans.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">

    <import resource="person.xml" />
    <import resource="school.xml" />

</beans>

创建person.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="liwl" class="com.liwl.dev.PersonImpl01">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

</beans>

创建school.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="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
name:liwanliang
age:30
school:name:jiangnan
address:wuxi

6. autowire标签

本节接第四节。之前通过property注入了基本数据类型和引用数据类型。这种方式主要是手动来注入。

假如一个类要注入很多bean,通过手动注入的方式不仅繁琐,而且容易出错。spring的xml配置提供了autowire来实现自动注入。

autowire=byName自动注入

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
name:liwanliang
age:30
school:name:jiangnan
address:wuxi

这里通过autowirel="byName"来替代了<property name="school" ref="school"/>,实现了SchoolImpl的bean对象的注入。

工作原理就是spring会在扫描PersonImpl的bean时,发现了school的setter和getter,因此会从容器中去id=school的bean注入到id=liwl,这样就不需要我们手动配置了,避免了很多错误。

autowrie=byType自动注入

Spring会通过xml配置的autowire=byType来为配置了该标签的bean自动注入属性。比如PersonImpl了有school属性时,如果不手动配置而通过自动配置,除了能够通过autowire=byName来自动注入以外,通过byType注入表示Spring会扫描PersonImpl发现需要SchooImpl的bean,然后从容器里面找到已经注册的SchoolImpl的bean注入到PersonImpl内

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
name:liwanliang
age:30
school:name:jiangnan
address:wuxi

7. primary和autowire-candidata标签

如果Spring容器里面已经注册了同源类的多个bean,在依赖注入的时候,使用autowire=byType时,Spring无法分辨出该加载哪一个,所以会报错。

xml配置文件可以通过primary标签和autowire-candidata标签来确定哪些bean具有优先权,也就是优先注入。

比如在beans.xml里面配置两个SchoolImpl的bean,把PersonImpl的bean就注入类型设置为autowire=byType,如下:

<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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan01"/>
        <property name="address" value="wuxi01"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan02"/>
        <property name="address" value="wuxi02"/>
    </bean>

</beans>

F5运行MyTest.java,运行报错

WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'liwl' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'school'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.liwl.dev.School' available: expected single matching bean but found 2: school01,school02
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'liwl' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'school'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.liwl.dev.School' available: expected single matching bean but found 2: school01,school02

从报错信息可以看出,Spring在为id=liwl的bean注入依赖时,在容器里面发现了2个SchoolImpl实现类的bean,它无法确认注入哪个,因此报错。

此时我们需要通过primary或者autowire-candidata来设置

使用primary标签

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl" primary="true">
        <property name="name" value="jiangnan01"/>
        <property name="address" value="wuxi01"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan02"/>
        <property name="address" value="wuxi02"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果:

[PersonImpl]:
name:liwanliang
age:30
school:SchoolImpl_name:jiangnan01,SchoolImpl_address:wuxi01

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan01"/>
        <property name="address" value="wuxi01"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl" primary="true">
        <property name="name" value="jiangnan02"/>
        <property name="address" value="wuxi02"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果:

[PersonImpl]:
name:liwanliang
age:30
school:SchoolImpl_name:jiangnan02,SchoolImpl_address:wuxi02

总结:

  • primary默认是false。当两个同源的bean不显式设置primary=true时,都是false。
  • 要优先注入某个bean,需要设置primary=true

使用autowire-candidata标签

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl" autowire-candidate="false">
        <property name="name" value="jiangnan01"/>
        <property name="address" value="wuxi01"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan02"/>
        <property name="address" value="wuxi02"/>
    </bean>

</beans>

F5运行MyTest.java,运行结果

[PersonImpl]:
name:liwanliang
age:30
school:SchoolImpl_name:jiangnan02,SchoolImpl_address:wuxi02

修改beans.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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byType">
        <property name="name" value="liwanliang" />
        <property name="age" value="30"/>
    </bean>

    <bean id="school01" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan01"/>
        <property name="address" value="wuxi01"/>
    </bean>

    <bean id="school02" class="com.liwl.dev.SchoolImpl" autowire-candidate="false">
        <property name="name" value="jiangnan02"/>
        <property name="address" value="wuxi02"/>
    </bean>

</beans>

运行结果:

[PersonImpl]:
name:liwanliang
age:30
school:SchoolImpl_name:jiangnan01,SchoolImpl_address:wuxi01

总结:

  • 如果没有显式设置autowire-candidate="false",那么默认autowire-candidate="true"
  • 当要默认屏蔽同源的bean时,需要设置autowire-candidate="false"

8. abstract和parent标签

当多个bean需要注入同一个依赖bean时,可以在xml配置文件中通过abstractparent标签配置需要注入的bean。

创建PersonImpl02.java

package com.liwl.dev;

public class PersonImpl02 implements Person {
    
    private String name;
    private int age;
    private School school;


    public PersonImpl02(){
        System.out.println("[PersonImpl02] 无参构造方法调用");
    }

    public PersonImpl02(String name,int age,School school){
        this.name = name;
        this.age = age;
        this.school = school;
        System.out.println("[PersonImpl02] 有参构造方法调用");
    }

    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 "[PersonImpl02]:" + "\nname:" + name + "\nage:" + age + "\nschool:" + school;
    }
}

修改beans.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= "school" class="com.liwl.dev.SchoolImpl">
        <property name="address" value="wuxi"/>
        <property name="name" value="jiangnan"/>
    </bean>

    <bean id="sch" abstract="true">
        <property name="name" value="liwl"/>
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

    <bean id="liwl01" class="com.liwl.dev.PersonImpl01" parent="sch"/>
    <bean id="liwl02" class="com.liwl.dev.PersonImpl02" parent="sch"/>

</beans>

修改MyTest.java

package com.liwl.dev;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        PersonImpl01 liwl01 = (PersonImpl01) context.getBean("liwl01");
        System.out.println(liwl01);
        PersonImpl02 liwl02 = (PersonImpl02) context.getBean("liwl02");
        System.out.println(liwl02);
        context.close();
    }
}

修改beans.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= "school" class="com.liwl.dev.SchoolImpl">
        <property name="address" value="wuxi"/>
        <property name="name" value="jiangnan"/>
    </bean>

    <bean id="sch" abstract="true">
        <property name="name" value="liwl"/>
        <property name="age" value="30"/>
        <property name="school" ref="school"/>
    </bean>

    <bean id="liwl01" class="com.liwl.dev.PersonImpl01" parent="sch">
        <property name="name" value="liwl01"/>
        <property name="age" value="30"/>
    </bean>

    <bean id="liwl02" class="com.liwl.dev.PersonImpl02" parent="sch"/>

</beans>

运行结果

[PersonImpl01]:
name:liwl01
age:30
school:SchoolImpl_name:jiangnan,SchoolImpl_address:wuxi
[PersonImpl02]:
name:liwl
age:30
school:SchoolImpl_name:jiangnan,SchoolImpl_address:wuxi

总结:

  • 定义一个模板bean,不使用class标签,而使用abstract标签。其他bean通过parent标签依赖此bean
  • 模板bean可以设置属性默认值,依赖于模板bean的bean可以单独设置属性默认值,单独设置后覆盖模板bean设置的值

9. bean的四种构造方式

10. lazy-init标签

默认情况下,spring在启动时创建xml配置文件里面所有的bean。当一个复杂的系统有很多bean需要加载的时候 ,会导致spring启动项目很慢。

修改beans.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="liwl01" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwl01"/>
        <property name="age" value="30"/>
    </bean>
    <bean id="liwl02" class="com.liwl.dev.PersonImpl02" autowire="byName">
        <property name="name" value="liwl02"/>
        <property name="age" value="30"/>
    </bean>
    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

修改MyTest.java

package com.liwl.dev;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        context.close();
    }
}

运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
[PersonImpl02] 无参构造方法调用
[PersonImpl02] 对象销毁
[PersonImpl01] 对象销毁
[SchoolImpl] 对象销毁

修改beans.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="liwl01" class="com.liwl.dev.PersonImpl01" autowire="byName" lazy-init="true">
        <property name="name" value="liwl01"/>
        <property name="age" value="30"/>
    </bean>
    <bean id="liwl02" class="com.liwl.dev.PersonImpl02" autowire="byName">
        <property name="name" value="liwl02"/>
        <property name="age" value="30"/>
    </bean>
    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

运行MyTest.java

[PersonImpl02] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
[PersonImpl02] 对象销毁
[SchoolImpl] 对象销毁

11. bean的创建和销毁顺序

先看无依赖的bean的创建和销毁顺序:

修改beans.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="liwl01" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwl01"/>
        <property name="age" value="30"/>
    </bean>

    <bean id="liwl02" class="com.liwl.dev.PersonImpl02" autowire="byName">
        <property name="name" value="liwl02"/>
        <property name="age" value="30"/>
    </bean>

</beans>

修改Person.java

package com.liwl.dev;

import org.springframework.beans.factory.DisposableBean;

public interface Person extends DisposableBean{
    
}

修改PersonImpl01.java

package com.liwl.dev;

public class PersonImpl01 implements Person {
    
    private String name;
    private int age;
    private School school;


    public PersonImpl01(){
        System.out.println("[PersonImpl01] 无参构造方法调用");
    }

    public PersonImpl01(String name,int age,School school){
        this.name = name;
        this.age = age;
        this.school = school;
        System.out.println("[PersonImpl01] 有参构造方法调用");
    }

    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 "[PersonImpl01]:" + "\nname:" + name + "\nage:" + age + "\nschool:" + school;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("[PersonImpl01] 对象销毁");
    }
}

修改PersonImpl02.java

package com.liwl.dev;

public class PersonImpl02 implements Person {
    
    private String name;
    private int age;
    private School school;


    public PersonImpl02(){
        System.out.println("[PersonImpl02] 无参构造方法调用");
    }

    public PersonImpl02(String name,int age,School school){
        this.name = name;
        this.age = age;
        this.school = school
        System.out.println("[PersonImpl02] 有参构造方法调用");
    }

    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 "[PersonImpl02]:" + "\nname:" + name + "\nage:" + age + "\nschool:" + school;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("[PersonImpl02] 对象销毁");
    }
}

修改MyTest.java

package com.liwl.dev;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        PersonImpl01 liwl01 = (PersonImpl01) context.getBean("liwl01");
        System.out.println(liwl01);
        PersonImpl02 liwl02 = (PersonImpl02) context.getBean("liwl02");
        System.out.println(liwl02);
        context.close();
    }
}

F5运行MyTest.java,运行结果

[PersonImpl01] 无参构造方法调用
[PersonImpl02] 无参构造方法调用
[PersonImpl01]:
name:liwl01
age:30
school:null
[PersonImpl02]:
name:liwl02
age:30
school:null
[PersonImpl02] 对象销毁
[PersonImpl01] 对象销毁

能够看到:PersonImpl01先于PersonImpl02创建,后于PersonImpl02销毁

继续验证上面结论。调整beans.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="liwl02" class="com.liwl.dev.PersonImpl02" autowire="byName">
        <property name="name" value="liwl02"/>
        <property name="age" value="30"/>
    </bean>

    <bean id="liwl01" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwl01"/>
        <property name="age" value="30"/>
    </bean>

</beans>

运行结果

[PersonImpl02] 无参构造方法调用
[PersonImpl01] 无参构造方法调用
[PersonImpl01]:
name:liwl01
age:30
school:null
[PersonImpl02]:
name:liwl02
age:30
school:null
[PersonImpl01] 对象销毁
[PersonImpl02] 对象销毁

总结:无依赖的两个bean,其在Spring里面创建的顺序:先配置先创建,后配置先销毁

再来看有依赖的bean的创建和销毁顺序:

修改beans.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="wuxi"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl" autowire="byName">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

    <bean id="liwl" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwl"/>
        <property name="age" value="30"/>
    </bean>

</beans>

创建Company.java

package com.liwl.dev;

import org.springframework.beans.factory.DisposableBean;

public interface Company extends DisposableBean{
    
}

创建CompanyImpl.java

package com.liwl.dev;

public class CompanyImpl implements Company{

    private String name;
    private String address;

    public CompanyImpl(){
        System.out.println("[CompanyImpl] 无参构造方法调用");
    }

    public CompanyImpl(String name,String address){
        System.out.println("[CompanyImpl] 有参构造方法调用");
        this.name = name;
        this.address = address;
    }

    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 "CompanyImpl_name:" + name + ",CompanyImpl_address:" + address;
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("[CompanyImpl] 对象销毁");
    }
}

修改SchoolImpl.java,使其依赖Company对象

package com.liwl.dev;

public class SchoolImpl implements School {
    
    private String name;
    private String address;
    private Company company;

    public SchoolImpl(){
        System.out.println("[SchoolImpl] 无参构造方法调用");
    }

    public SchoolImpl(String name,String address,Company company){
        this.name = name;
        this.address = address;
        System.out.println("[SchoolImpl] 有参构造函数调用");
    }

    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;
    }

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    @Override
    public String toString() {
        return "SchoolImpl_name:" + name + ",SchoolImpl_address:" + address + ",SchoolImpl_company:" + company;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("[SchoolImpl] 对象销毁");
    }
}

F5运行MyTest.java,运行结果

[CompanyImpl] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
[PersonImpl01] 无参构造方法调用
[PersonImpl01]:
name:liwl
age:30
school:SchoolImpl_name:jiangnan,SchoolImpl_address:wuxiSchoolImpl_company:CompanyImpl_name:nsccwx,CompanyImpl_address:wuxi
[PersonImpl01] 对象销毁
[SchoolImpl] 对象销毁
[CompanyImpl] 对象销毁

总结:

  • 依赖关系:PersonImpl依赖SchoolImpl,SchoolImpl依赖CompanyImpl
  • bean创建顺序:CompanyImpl先于SchoolImpl,SchooImpl先于PersonImpl
  • bean销毁顺序:PersonImpl先于SchoolImpl,SchoolImpl先于CompanyImpl

调整beans.xml里面配置bean的顺序,再次验证一下

<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="liwl" class="com.liwl.dev.PersonImpl01" autowire="byName">
        <property name="name" value="liwl"/>
        <property name="age" value="30"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl" autowire="byName">
        <property name="name" value="jiangnan"/>
        <property name="address" value="wuxi"/>
    </bean>

    <bean id="company" class="com.liwl.dev.CompanyImpl">
        <property name="name" value="nsccwx"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

运行结果

[PersonImpl01] 无参构造方法调用
[SchoolImpl] 无参构造方法调用
[CompanyImpl] 无参构造方法调用
[PersonImpl01]:
name:liwl
age:30
school:SchoolImpl_name:jiangnan,SchoolImpl_address:wuxiSchoolImpl_company:CompanyImpl_name:nsccwx,CompanyImpl_address:wuxi
[PersonImpl01] 对象销毁
[SchoolImpl] 对象销毁
[CompanyImpl] 对象销毁

调整beans.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="liwl" class="com.liwl.dev.PersonImpl01">
        <constructor-arg name="name" value="liwl"/>
        <constructor-arg name="age" value="30"/>
        <constructor-arg name="school" ref="school"/>
    </bean>

    <bean id="school" class="com.liwl.dev.SchoolImpl">
        <constructor-arg name="name" value="jiangnan"/>
        <constructor-arg name="address" value="wuxi"/>
        <constructor-arg name="company" ref="company"/>
    </bean>

    <bean id="company" class="com.liwl.dev.CompanyImpl">
        <property name="name" value="nsccwx"/>
        <property name="address" value="wuxi"/>
    </bean>

</beans>

运行结果

[CompanyImpl] 无参构造方法调用
[SchoolImpl] 有参构造函数调用
[PersonImpl01] 有参构造方法调用
[PersonImpl01]:
name:liwl
age:30
school:SchoolImpl_name:jiangnan,SchoolImpl_address:wuxi,SchoolImpl_company:CompanyImpl_name:nsccwx,CompanyImpl_address:wuxi
[PersonImpl01] 对象销毁
[SchoolImpl] 对象销毁
[CompanyImpl] 对象销毁

总结:

  • 构造方法注入时,有强依赖。被依赖的bean先创建,后销毁
  • 使用自动注入时,虽然有依赖,但是也是按照配置的顺序进行创建和销毁
posted @ 2022-02-28 10:10  liwldev  阅读(125)  评论(0编辑  收藏  举报