XML的设置注入与域属性注入
设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而
在 Spring 的依赖注入中大量使用。
更多的使用设置注入,而非构造注入
03di package com.bjpowernode.di01;
学生类
public class Student {
private String name;
private int age;
private School school; //对象属性,域属性
public void setName(String name) {
System.out.println("执行setName()方法");
this.name = name;
}
public void setAge(int age) {
System.out.println("执行setAge()方法");
this.age = age;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", school=" + school + "]";
}
}
学校类
public class School {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "School [name=" + name + "]";
}
}
测试类
public class MyTest {
@Test
public void test01() {
//创建容器对象,加载Spring配置文件
//会从类路径src下查找配置文件
//底层反射调用的是无参构造器new instance 如果写有参构造会屏蔽掉无参构造 导致初始化失败
String resource = "com/bjpowernode/di01/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
Student student = (Student) ac.getBean("myStudent");
System.out.println(student);
}
}
配置文件
<!-- 注册School -->
<bean id="mySchool" class="com.bjpowernode.di01.School">
<property name="name" value="清华大学"/>
</bean>
<!-- 注册Student -->
<bean id="myStudent" class="com.bjpowernode.di01.Student">
<property name="name" value="张三"/>
<property name="age" value="23"/>
<property name="school" ref="mySchool"/>
</bean>
注意普通成员变量与域属性注册的方式不同
‘
结果:执行setName()方法
执行setAge()方法
Student [name=张三, age=23, school=School [name=清华大学]]
构造注入
03di package com.bjpowernode.di02;
用的少
学生类
public class Student {
private String name;
private int age;
private School school; //对象属性,域属性
public Student(String name, int age, School school) {
super();
this.name = name;
this.age = age;
this.school = school;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", school=" + school + "]";
}
}
学校类不变
测试类不变
配置文件
</bean>
<!-- 注册Student -->
<bean id="myStudent" class="com.bjpowernode.di02.Student">
<constructor-arg name="name" value="李四"/>
<constructor-arg name="age" value="24"/>
<constructor-arg name="school" ref="mySchool"/>
<!--
<constructor-arg index="0" value="李四"/>
<constructor-arg index="1" value="24"/>
<constructor-arg index="2" ref="mySchool"/>
-->
<!--
<constructor-arg value="李四"/>
<constructor-arg value="24"/>
<constructor-arg ref="mySchool"/>
-->
</bean>
集合属性注入(重要,但不建议用这种写法)
03di package com.bjpowernode.di05;
学校类不变
public class School {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "School [name=" + name + "]";
}
}
学生类
public class Some {
private School[] schools;
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String, Object> myMap;
private Properties myPros;
public void setSchools(School[] schools) {
this.schools = schools;
}
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, Object> myMap) {
this.myMap = myMap;
}
public void setMyPros(Properties myPros) {
this.myPros = myPros;
}
@Override
public String toString() {
return "Some [schools=" + Arrays.toString(schools) + ", myStrs=" + Arrays.toString(myStrs) + ", myList="
+ myList + ", mySet=" + mySet + ", myMap=" + myMap + ", myPros=" + myPros + "]";
}
}
重点在于注册配置文件
<!-- 注册School -->
<bean id="mySchool" class="com.bjpowernode.di05.School">
<property name="name" value="清华大学"/>
</bean>
<bean id="mySchool2" class="com.bjpowernode.di05.School">
<property name="name" value="北京大学"/>
</bean>
<!-- 注册Some -->
<bean id="mySome" class="com.bjpowernode.di05.Some">
<property name="schools">
<array>
<ref bean="mySchool"/>
<ref bean="mySchool2"/>
</array>
</property>
<property name="myStrs">
<array>
<value>中国</value>
<value>北京</value>
</array>
</property>
<property name="myList">
<list>
<value>大兴</value>
<value>亦庄</value>
</list>
</property>
<property name="mySet">
<set>
<value>大族企业湾</value>
<value>10号楼</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="mobile" value="1234567"/>
<entry key="QQ" value="7654321"/>
</map>
</property>
<property name="myPros">
<props>
<prop key="education">大学</prop>
<prop key="gender">男</prop>
</props>
</property>
</bean>
测试类
@Test
public void test01() {
//创建容器对象,加载Spring配置文件
//会从类路径src下查找配置文件
//底层反射调用的是无参构造器new instance 如果写有参构造会屏蔽掉无参构造 导致初始化失败
String resource = "com/bjpowernode/di05/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
Some some = (Some) ac.getBean("mySome");
System.out.println(some);
}
输出结果
Some [schools=[School [name=清华大学], School [name=北京大学]], myStrs=[中国, 北京], myList=[大兴, 亦庄], mySet=[大族企业湾, 10号楼], myMap={mobile=1234567, QQ=7654321}, myPros={education=大学, gender=男}]
集合属性注入简单写法
03di package com.bjpowernode.di06;
注意只有不使用ref的非引用数组和set集合才可以简写
只修改配置文件
<!-- 注册School -->
<bean id="mySchool" class="com.bjpowernode.di06.School">
<property name="name" value="清华大学"/>
</bean>
<bean id="mySchool2" class="com.bjpowernode.di06.School">
<property name="name" value="北京大学"/>
</bean>
<!-- 注册Some -->
<bean id="mySome" class="com.bjpowernode.di06.Some">
<property name="schools">
<array>
<ref bean="mySchool"/>
<ref bean="mySchool2"/>
</array>
</property>
<property name="myStrs" value="中国,北京"/>
<property name="myList" value="大兴,亦庄"/>
<property name="mySet" value="大族企业湾,10号楼"/>
<property name="myMap">
<map>
<entry key="mobile" value="1234567"/>
<entry key="QQ" value="7654321"/>
</map>
</property>
<property name="myPros">
<props>
<prop key="education">大学</prop>
<prop key="gender">男</prop>
</props>
</property>
</bean>
对于域属性的自动注入
03di package com.bjpowernode.di07;
byName
autowire="byName"会从容器中查找与实体类的域属性同名的Bean的id,并将该Bean对象自动注入该该域属性
package07
配置文件
<!-- 注册School -->
<bean id="school" class="com.bjpowernode.di07.School">
<property name="name" value="清华大学"/>
</bean>
<!-- 注册Student -->
<bean id="myStudent" class="com.bjpowernode.di07.Student" autowire="byName">
<property name="name" value="张三"/>
<property name="age" value="23"/>
byType
autowire=“byType” 会从容器中查找与实体类的域属性类型相同的(包括is-a继承关系的)Bean,并将该Bean对象自动注入给该域属性,也就是说域属性的id可以改为任意,也可以不写
注意类型相同的Bean如果有两个 会报错
03di package com.bjpowernode.di08;
继承自school类
public class PrimarySchool extends School {
private String address;
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "PrimarySchool [address=" + address + "]";
}
}
配置文件
<!-- 注册School -->
<bean id="mySchool" class="com.bjpowernode.di08.School">
<property name="name" value="清华大学"/>
</bean>
<bean id="myPrimarySchool" class="com.bjpowernode.di08.School">
<property name="address" value="海淀区"/>
</bean>
<!-- 注册Student -->
<bean id="myStudent" class="com.bjpowernode.di08.Student" autowire="byType">
<property name="name" value="张三"/>
<property name="age" value="23"/>
</bean>
应修改为:去掉id="myPrimarySchool"这段代码
使用 SPEL
SPEL,Spring Expression Language,即 Spring EL 表达式语言。即,在 Spring 配置文件中为 Bean 的属性注入值时,可直接使用 SPEL 表达式计算的结果。SPEL 表达式以#开头,后跟一对大括号。用法: <bean id=“abc” value=“#{…}”/>。
通过使用 SPEL 实现生成随机年龄,实现两个类的属性保持一致,实现调用另一个类的方法
总结:功能强大,可以调用静态方法,访问其他Bean的属性,计算表达式,调用其他Bean的方法
03di package com.bjpowernode.di09;
学生类
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
人类
public class Person {
private String pname;
private int page;
public void setPname(String pname) {
this.pname = pname;
}
public void setPage(int page) {
this.page = page;
}
public String getPname() {
return pname;
}
public int getPage() {
return page;
}
@Override
public String toString() {
return "Person [pname=" + pname + ", page=" + page + "]";
}
public int computeAge() {
return page > 25 ? 25 :page;
}
}
配置文件
<!-- 注册School -->
<bean id="myPerson" class="com.bjpowernode.di09.Person">
<property name="pname" value="李四"/>
<property name="page" value="#{T(java.lang.Math).random() * 50}"/>
</bean>
<!-- 注册Student -->
<bean id="myStudent" class="com.bjpowernode.di09.Student">
<property name="name" value="#{myPerson.pname}"/>
<!--
<property name="age" value="#{myPerson.page > 25 ? 25 : myPerson.page}"/>
-->
<property name="age" value="#{myPerson.computeAge()}"/>
</bean>
测试
@Test
public void test01() {
//创建容器对象,加载Spring配置文件
//会从类路径src下查找配置文件
//底层反射调用的是无参构造器new instance 如果写有参构造会屏蔽掉无参构造 导致初始化失败
String resource = "com/bjpowernode/di09/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
Person myPerson = (Person) ac.getBean("myPerson");
System.out.println(myPerson);
Student student = (Student) ac.getBean("myStudent");
System.out.println(student);
}
为应用指定多个 Spring 配置文件
(一)平等关系 经常用
三种方式:
1)分别定义两个resource路径,传入两个参数
2)定义一个数组接收两个路径
3)最常用的使用通配符*
03-package com.bjpowernode.di13;
设置配置文件spring-base
<bean id="baseBean" abstract="true">
<property name="school" value="清华大学"/>
<property name="department" value="计算机系"/>
</bean>
设置配置文件spring-beans
<bean id="myStudent" class="com.bjpowernode.di13.Student" parent="baseBean">
<property name="name" value="张三"/>
<property name="age" value="23"/>
</bean>
<bean id="myTeacher" class="com.bjpowernode.di13.Teacher" parent="baseBean">
<property name="name" value="Reyco"/>
<property name="workAge" value="18"/>
</bean>
测试三种写法
@Test
public void test01() {
//使用异类抽象Bean注入
//String resource = "com/bjpowernode/di13/spring-base.xml";
//String resource2 = "com/bjpowernode/di13/spring-beans.xml";
//ApplicationContext ac = new ClassPathXmlApplicationContext(resource, resource2);
/*
* String resource = "com/bjpowernode/di13/spring-base.xml"; String resource2 =
* "com/bjpowernode/di13/spring-beans.xml"; String[] resources = {resource,
* resource2}; ApplicationContext ac = new
* ClassPathXmlApplicationContext(resources);
*/
String resource = "com/bjpowernode/di13/spring-*.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
Student student = (Student) ac.getBean("myStudent");
System.out.println(student);
Teacher teacher = (Teacher) ac.getBean("myTeacher");
System.out.println(teacher);
}
(二)包含关系
再写一个配置文件springtotal 引入那两个spring配置文件即可
即可分别引入,也可以使用通配符引用
03-package com.bjpowernode.di14;
<!--
<import resource="classpath:com/bjpowernode/di14/spring-base.xml"/>
<import resource="classpath:com/bjpowernode/di14/spring-beans.xml"/>
-->
<import resource="classpath:com/bjpowernode/di14/spring-*.xml"/>
在测试类中,直接使用springtotal即可
2.4 基于注解的 DI
对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 Bean 实例。Spring 中使用注解,
需要在原有 Spring 运行环境基础上再做一些改变,完成以下三个步骤。
(1)导入 AOP 的 Jar 包。因为注解的后台实现用到了 AOP 编程。
(2)更换新的约束文件
%SPRING_HOME%\docs\spring-framework-reference\html\xsd-configuration.html
(3)需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
学校类 加入组件
04 package com.bjpowernode.di01;
@Component("mySchool") // 组件,表示当前类被Spring容器所管理 只写一个参数value可以省略
public class School {
@Value("清华大学")
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "School [name=" + name + "]";
}
}
学生类 加入组件
@Component("myStudent") // 组件,表示当前类被Spring容器所管理
public class Student {
@Value("张三")
private String name;
@Value("23")
private int age;
private School school; //对象属性,域属性
public void setName(String name) {
System.out.println("执行setName()方法");
this.name = name;
}
public void setAge(int age) {
System.out.println("执行setAge()方法");
this.age = age;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", school=" + school + "]";
}
}
约束文件
扫描com.bjpowernode这个包及其子包
<context:component-scan base-package=“com.bjpowernode”/>
扫描com.bjpowernode这个包的子包
<context:component-scan base-package=“com.bjpowernode.*”/>
扫面一个包
<context:component-scan base-package=“com.bjpowernode.di01”/>
按类型与按名称注入域属性@Autowired 与@Qualifier
按类型
需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配 Bean 的方式。
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加
到 setter 上
04 package com.bjpowernode.di02;
学校类
学生类的域属性赋值
按名称
需要在域属性上联合使用注解@Autowired 与@Qualifier。@Qualifier 的 value 属性用于
指定要匹配的 Bean 的 id 值。同样类中无需 setter,也可加到 setter 上。
二者必须联合使用
域属性注解@Resource
和@Autowired用法一样
注解与 XML共同使用
注解的好处是,配置方便,直观。但其弊端也显而易见:以硬编码的方式写入到了 Java
代码中,其修改是需要重新编译代码的。
XML 配置方式的最大好处是,对其所做修改,无需编译代码,只需重启服务器即可将新
的配置加载。
若注解与 XML 同用,XML 的优先级要高于注解。这样做的好处是,需要对某个 Bean 做
修改,只需修改配置文件即可。当然,此时,Bean 类要有 setter 或构造器。
xml必须要有setter方法
04-package com.bjpowernode.di07;