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配置文件中通过abstract
和parent
标签配置需要注入的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先创建,后销毁
- 使用自动注入时,虽然有依赖,但是也是按照配置的顺序进行创建和销毁