6、依赖注入(DI)
依赖注入(Dependency Injection,DI)
- 依赖 : 指 bean 对象的创建依赖于容器,bean 对象的依赖资源。
- 注入 : 指 bean 对象中的所有属性由容器来注入
6.1 构造器注入
之前的案例已经使用
6.2 set 方式注入【重点】
6.2.0 环境搭建
-
复杂类型
public class Address { private String address; getXxx()/setXxx()/toString() }
-
真实测试对象
public class Student { private String name; private Address address; private String[] books; private List<String> hobbies; private Map<String,String> card; private Set<String> games; private String wife; private Properties info; getXxx()/setXxx()/toString() }
-
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="student" class="com.song.pojo.Student"> <!--第一种:普通值注入,value --> <property name="name" value="张三"/> </bean> </beans>
-
测试类
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student)context.getBean("student"); System.out.println(student.getName()); } }
6.2.1 普通值(常量)注入
<bean id="student" class="com.song.pojo.Student">
<!--普通值注入,value -->
<property name="name" value="张三"/>
</bean>
6.2.2 Bean 注入,引用
<bean id="address" class="com.song.pojo.Address">
<property name="address" value="北京"/>
</bean>
<bean id="student" class="com.song.pojo.Student">
<!--Bean 注入,ref-->
<property name="address" ref="address"/>
</bean>
6.2.3 数组注入
<!--数组注入-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
6.2.4 list 注入
<!-- list 注入-->
<property name="hobbies">
<list>
<value>打球</value>
<value>唱歌</value>
<value>跳舞</value>
</list>
</property>
6.2.5 map 注入
<!-- map 注入-->
<property name="card">
<map>
<entry key="身份证" value="123456"/>
<entry key="银行卡" value="456789"/>
</map>
</property>
6.2.6 set 注入
<!-- set 注入-->
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
6.2.7 null 注入
<!-- null 注入-->
<!--<property name="wife" value=""/>-->
<property name="wife">
<null/>
</property>
6.2.8 properties 注入
<!-- properties 注入-->
<property name="info">
<props>
<prop key="driver">2018020202</prop>
<prop key="url">男</prop>
<prop key="username">张三</prop>
<prop key="password">123456</prop>
</props>
</property>
测试:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student)context.getBean("student");
System.out.println(student.toString());
}
测试结果:
Student{
name='张三',
address=Address{address='北京'},
books=[红楼梦, 西游记, 水浒传, 三国演义],
hobbies=[打球, 唱歌, 跳舞],
card={身份证=123456,银行卡=456789},
games=[LOL, COC, BOB],
wife='null',
info={password=123456,url=男,driver=2018020202,userme=张三}
}
6.3 拓展方式注入(p 命名空间和 c 命名空间)
实体类:
public class User {
private String name;
private int age;
有参构造/无参构造/get/set/toString……
}
beans.xml 配置文件:
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p 命名空间注入,可以直接注入属性的值:property -->
<bean id="user" class="com.song.pojo.User" p:name="张三" p:age="18"/>
<!-- c 命名空间注入,通过构造器注入:construct-arg -->
<bean id="user2" class="com.song.pojo.User" c:age="18" c:name="李四"/>
</beans>
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
// User user = (User) context.getBean("user");
// User user = context.getBean("user", User.class); // 第二个参数写上,就不用强转了
User user = context.getBean("user2", User.class);
System.out.println(user);
}
结果:
//User{name='张三', age=18}
User{name='李四', age=18}
注意:不能直接使用,必须先在头文件中加入约束文件。
-
p 命名空间约束文件:
xmlns:p="http://www.springframework.org/schema/p"
-
p 命名空间类似于 set 方法注入,bean 实体类中必须有无参构造
-
c 命名空间约束文件:
xmlns:c="http://www.springframework.org/schema/c"
-
c 命名空间注入类似于构造器注入,bean 实体类中必须有有参构造
6.4 bean 的作用域(Bean scopes)
在 Spring 中,那些组成应用程序的主体及由 Spring IoC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IoC 容器初始化、装配及管理的对象。
官方文档:
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
-
单例模式(Spring 默认机制)
当一个 bean 的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。
Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。
注意:Singleton 作用域是 Spring 中的缺省作用域。显式表示为:
<bean id="user" class="com.song.pojo.User" scope="singleton"/>
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user = context.getBean("user", User.class); User user2 = context.getBean("user", User.class); System.out.println(user == user2); // true }
-
原型模式
每次从容器中 get 时,都会产生一个新对象。
当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。
Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。
根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。
<bean id="user" class="com.song.pojo.User" scope="prototype"/>
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user = context.getBean("user", User.class); User user2 = context.getBean("user", User.class); System.out.println(user == user2); // false }
-
其余的 request、session、application 这些只能在 web 开发中使用,只能用在基于 web 的 Spring ApplicationContext 环境。