什么是依赖注入?
依赖注入(Dependency Injection,DI)是Spring框架的核心之一。
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。
Bean的注入方式
依赖注入有两种:构造注入、设值注入。
构造注入,本质其实就是通过类的构造方法初始化对象:
public class Order {
private String orderId;
private String orderName;
public Order(String orderId, String orderName) {
this.orderId = orderId;
this.orderName = orderName;
System.out.println("执行了有参构造");
}
}
使用构造注入需要用到constructor-arg
标签,同时我们的bean类必须要有对应的构造方法。
<!-- 构造器注入属性-->
<bean id="order" class="com.symc.spring.bean.Order">
<constructor-arg name="orderId" value="123000"></constructor-arg>
<constructor-arg name="orderName" value="Forward"></constructor-arg>
</bean>
我们还可以通过构造器参数的索引注入属性的值,索引是从0开始。
<!-- 构造器注入属性-->
<bean id="order" class="com.symc.spring.bean.Order">
<constructor-arg index="0" value="123001"/>
<constructor-arg index="1" value="Forward"/>
</bean>
我们还需要注意的是,在配置文件中的bean
标签的id不允许重复,如果要同时使用不同的构造函数,需要换名字。
<!--无参构造-->
<bean id="order" class="com.symc.spring.bean.Order"></bean>
<!--有参构造-->
<bean id="order_arg" class="com.symc.spring.bean.Order">
<constructor-arg index="0" value="123001"/>
<constructor-arg index="1" value="Forward"/>
</bean>
设值注入本质是基于对象属性set方法实现。所以这种方式不需要依赖构造方法,但是注入属性必须要有set方法!
public class User {
private String name;
private String password;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("name:"+name+"\t通过反射机制调用set方法!");
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
设值注入配置文件中可以用property
标签。
<bean id="user" class="com.symc.spring.bean.User">
<property name="name" value="Forward Seen"></property>
<property name="password" value="123456"></property>
</bean>
测试一下
@Test
public void startApplication() {
User user = classPathXmlApplicationContext.getBean("user", User.class);
System.out.println(user);
}
p名称空间注入
p名称空间注入是通过set方法注入值,使用这种方式需要在xml配置文件头部引入P标签:
xmlns:p="http://www.springframework.org/schema/p"
引入后如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用p标签注入属性,原理是通过反射机制调用set方法-->
<bean id="order" class="com.symc.spring.bean.Order"
p:orderId="1230001" p:orderName="Forward">
</bean>
</beans>
可见,使用P标签的方式更加简洁。
注入空值
<bean id="user" class="com.symc.bean.User">
<property name="name" value="Forward"></property>
<property name="password" >
<null></null>
</property>
注入特殊符号
<< 转移为:<<
>>转移为:>>
<bean id="user" class="com.symc.bean.User">
<!-- <property name="name" value="<<Forward>>"></property> -->
<property name="bookName" value="<<Forward >>"></property>
</bean>
Cdata注入方式
<bean id="user" class="com.symc.bean.User">
<!-- <property name="name" value="<<Forward>>"></property> -->
<property name="bookName"><value><![CDATA[<<Forward>>]]></value></property>
</bean>
注入属性外部bean
演示:
先定义一个接口
public interface MemberDao {
void addMember();
}
实现接口
public class MemberDaoImpl implements MemberDao{
public void addMember() {
System.out.println("A member is added!");
}
}
使用
public class MemberService {
private MemberDao memberDao;
public MemberDao getMemberDao() {
return memberDao;
}
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void addMember(){
//原生方式
// memberDao = new MemberDaoImpl();
memberDao.addMember();
}
}
配置文件中引入另一个bean
属性
<bean id="memberDao" class="com.symc.spring.dao.MemberDaoImpl"></bean>
<bean id="memberService" class="com.symc.spring.service.MemberService">
<property name="memberDao" ref="memberDao"></property>
</bean>
注入内部bean
1.数据库表 一对多或者一对一的关系
2.一个部门有多个员工 一对多
3.站在员工角度考虑 员工属于那个部门
4.站在部门的角度考虑 部门下n多个员工
public class Dept {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class Emp {
private Integer id;
private String name;
private Dept dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", dept=" + dept +
'}';
}
}
<!-- 内部注入bean-->
<bean id="emp" class="com.symc.spring.bean.Emp">
<property name="id" value="0213"></property>
<property name="name" value="Forward"></property>
<property name="dept">
<bean id="dept" class="com.symc.spring.bean.Dept">
<property name="id" value="06140102"></property>
<property name="name" value="2班"></property>
</bean>
</property>
</bean>
级联赋值
<!--级联赋值写法1-->
<bean id="emp" class="com.symc.spring.bean.Emp">
<property name="id" value="614010213"></property>
<property name="name" value="Forward"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.symc.spring.bean.Dept">
<property name="id" value="6140102"></property>
<property name="name" value="2班"></property>
</bean>
<!--级联注入bean 2-->
<bean id="emp" class="com.symc.spring.bean.Emp">
<property name="name" value="Forward"></property>
<property name="id" value="614010213"></property>
<property name="dept" ref="dept"></property>
<property name="dept.id" value="6140102"></property>
<property name="dept.name" value="2班"></property>
</bean>
<bean id="dept" class="com.symc.spring.bean.Dept"></bean>
注入集合类型属性
1.注入数组类型
2.注入list集合类型
3.注入Map集合类型属性
4.注入set集合属性
public class Student {
private String[] arrays;
private List<String> list;
private Map<Integer,String> map;
private Set<String> set;
public String[] getArrays() {
return arrays;
}
public void setArrays(String[] arrays) {
this.arrays = arrays;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
}
<!--注入集合类型属性-->
<bean id="student" class="com.symc.spring.bean.Student">
<property name="arrays">
<array>
<value>Hello,</value>
<value>Spring!</value>
</array>
</property>
<property name="list">
<list>
<value>Hello</value>
<value>Forward</value>
</list>
</property>
<property name="map">
<map>
<entry key="1001" value="Forward"></entry>
<entry key="1002" value="Love"></entry>
</map>
</property>
<property name="set">
<set>
<value>Study</value>
<value>Study</value>
<value>Play</value>
</set>
</property>
</bean>
@Test
public void injectionCollection() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("collection.xml");
Student student = (Student) app.getBean("student");
System.out.println("arrays:");
for (String s : student.getArrays()) {
System.out.print(s);
}
System.out.println("\nlist:");
student.getList().forEach(e -> {
System.out.print(e + "\t");
});
System.out.println("\nmap:");
Set keySet = student.getMap().keySet();
keySet.forEach(e -> {
System.out.print(e + "\t");
});
System.out.println("\nset:");
student.getSet().forEach(e -> {
System.out.print(e + "\t");
});
}
注入对象集合类型
<!--注入对象集合类型-->
<bean id="student" class="com.symc.spring.bean.Student">
<property name="courses">
<set>
<ref bean="course_java"></ref>
<ref bean="course_sql"></ref>
</set>
</property>
</bean>
<bean id="course_java" class="com.symc.spring.bean.Course">
<property name="name" value="Java面向对象"></property>
</bean>
<bean id="course_sql" class="com.symc.spring.bean.Course">
<property name="name" value="数据库"></property>
</bean>
@Test
public void injectionObjectCollection(){
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("collection1.xml");
Student student = (Student) app.getBean("student");
Set<Course> courses = student.getCourses();
courses.forEach(e->{
System.out.println(e);
});
}
引入公共list
需要引入标签库:
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"></beans>
使用:
<!--引入公共list-->
<util:list id="list">
<value>Forward Seen</value>
<value>Forward Seen2</value>
<value>Forward Seen3</value>
</util:list>
<bean id="student" class="com.symc.spring.bean.Student">
<property name="list" ref="list"></property>
</bean>
@Test
public void injectionPublicCollection(){
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("collection2.xml");
Student student = app.getBean("student", Student.class);
System.out.println(student.getList());
}