注入(injection)
注入
1、什么是注入
通过Spring工厂及配置文件为所创建对象的成员变量赋值
1.1 为什么需要注入
通跟代码直接为成员变量赋值,有耦合
1.2 如何进行注入[开发步骤]
- 类的成员变量提供set get方法
- 配置spring的配置文件
<bean id="person" name="p,p1" class="com.company.basic.Person">
<property name="id">
<value>100</value>
</property>
<property name="name">
<value>李四</value>
</property>
</bean>
1.3 注入的好处
解耦合
2、Spring注入的原理(非源码)
Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方式我们也称之为set注入
Set注入详解
针对于不同类型的成员变量,在<property>标签,需要嵌套其他标签
<property>
xxx
</property>
1、JDK内置类型
1.1 基本类型加String
<property name="name">
<value>李四</value>
</property>
1.2 数组类型
<property name="emails">
<list>
<value>48484@qq.com</value>
<value>48484dad@qq.com</value>
<value>48484dsa@qq.com</value>
</list>
</property>
集合注意事项
- 集合里面不包含重复的数据
- 集合如果没有限制泛型类型(则Object),那么里面的元素放置不受限制
1.3 set类型
<property name="tels">
<set>
<value>31231341221</value>
<value>56654454545</value>
<value>56654454545</value>
<value>56654454545</value>
</set>
</property>
<property name="tels">
<set>
<value>31231341221</value>
<ref bean=""/>
<set></set>
...
</set>
</property>
1.4 List集合
<property name="addresses">
<list>
<value>这里</value>
<value>那里</value>
<value>这里</value>
</list>
</property>
<property name="addresses">
<list>
<value>这里</value>
<ref bean=""/>
<set></set>
...
</list>
</property>
1.5 Map集合
注意: map – entry
- – key有特定的标签
<key></key>
- 值根据对应类型选择对应类型的标签
<property name="qqs">
<map>
<entry>
<!-- key有一个限制的key标签,而value没有限制标签 -->
<key>
<value>我的qq</value>
</key>
<value>123456789</value>
</entry>
<entry>
<key>
<value>他的qq</value>
</key>
<value>12345678910</value>
</entry>
</map>
</property>
<map>
<entry>
<key>
<value>我的qq</value>
</key>
<ref bean=""/>
</entry>
</map>
1.6 Properties
Properties类型特殊的 Map key=String value=String
<property name="p">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
</props>
</property>
1.7 复杂的JDK类型(如:Date)
需要程序员自定义类型转换器,处理。
测试方法
/**
* 用于测试:测试JDK内置类型
*
*/
@Test
public void test7(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Person person = (Person) ctx.getBean("person");
String[] emails = person.getEmails();
for (String email : emails) {
System.out.println("email = " + email);
}
System.out.println("------------------------------------------");
Set<String> tels = person.getTels();
for (String tel : tels) {
System.out.println("tel = " + tel);
}
System.out.println("------------------------------------------");
List<String> addresses = person.getAddresses();
for (String address : addresses) {
System.out.println("address = " + address);
}
System.out.println("------------------------------------------");
Map<String, String> qqs = person.getQqs();
for (Map.Entry<String, String> entry : qqs.entrySet()) {
System.out.println("key:" + entry.getKey() +" value:" +entry.getValue());
}
// 或者这样遍历
Set<String> keys = qqs.keySet();
for (String key : keys) {
System.out.println("key:" + key + " value:" + qqs.get(key));
}
System.out.println("------------------------------------------");
Properties properties = person.getP();
System.out.println("key is key1 value is " + properties.getProperty("key1"));
System.out.println("key is key2 value is " + properties.getProperty("key2"));
}
2、用户自定义类型
2.1 第一种方式
- 为成员变量提供set get方法
- 在配置文件里面进行注入
<bean id="userService" class="xxx.UserServiceImpl">
<property name="UserDao">
<bean class="xxx.UserDaoImpl"/>
</property>
</bean>
2.2 第二种方式
第一种赋值方式存在的问题
- 配置文件代码冗余
- 被注入的对象(UserDA0),多次创建,浪费(JVM)内存资源
方法:
- 为成员变量提供set get方法
- 在配置文件里面进行注入
<bean id="userDao" class="xxx.UserDaoImpl"/>
<bean id="userService" class="xxx.UserSerivceImpl">
<property name="userDao">
<ref bean="userDao"/>
</property>
</bean>
#Spring4.x废除了 <ref local=""/> 基本等效 <ref bean=""/>
3、set注入的简化方式
3.1 基于属性简化
<!-- 原本 -->
<bean id="person" class="xxx.Person">
<property name="name">
<value>小明</value>
</property>
</bean>
JDK类型注入
<bean id="person" class="com.company.basic.Person">
<property name="name" value="小明"/>
<property name="id" value="123456"/>
</bean>
<!-- 原本 -->
<bean id="userService" class="xxx.UserServiceImpl>
<property name="userDao">
<ref bean="userDao"/>
</property>
</bean>
用户自定义类型注入
<bean id="userDao" class="com.company.basic.UserDaoImpl"/>
<bean id="userService" class="com.company.basic.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
3.2 基于p命名空间的简化
注意: value属性只能简化8种基本类型+String注入标签
JDK类型注入
<bean id="person" class="com.company.basic.Person" p:name="小明" p:id="5"/>
用户自定义类型注入
<bean id="userDao" class="com.company.basic.UserDaoImpl"/>
<bean id="userService" class="com.company.basic.UserServiceImpl" p:userDao-ref="userDao"/>
测试方法
@Test
public void test8(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.register(new User("第一个","1234"));
userService.login("第一个","4567");
}
@Test
public void test9(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
Person person = (Person) ctx.getBean("person");
System.out.println("person = " + person);
}
构造注入、反转控制 与 依赖注入
注入分类
注入:通过Spring的配置文件,为成员变量赋值
Set注入:Spring调用Set方法通过配置文件为成员变量赋值
构造注入:Spring调用构造方法通过配置文件为成员变量赋值
1. 步骤
- 提供有参构造方法
package com.company.basic.customer;
import java.io.Serializable;
public class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
}
- Spring的配置文件
<bean id="customer" class="com.company.basic.customer.Customer">
<constructor-arg>
<value>张三</value>
</constructor-arg>
<constructor-arg>
<value>123456</value>
</constructor-arg>
</bean>
2. 构造方法重载
参数个数不同时
通过控制<constructor-arg>标签的数量进行区分
构造参数个数相同时
通过在标签引入 type属性 进行类型的区分<constructor-arg type="">
3. 注入总结
未来的实战中, 应用set注入还是构造注入?
答案:set注入更多
- 构造注入麻烦(重载)
- Spring框架底层大量应用了set注入
反转控制 与 依赖注入
1. 反转(转移)控制(IOC Inverse of Control)
控制:对于成员变量的控制权
反转控制:把对于成员变量赋值的控制权,从代码中反转(转移)到Spring工厂和配置文件中完成
- 好处:解耦合
底层实现:工程设计模式
2.依赖注入(Dependency Injection DI)
注入:通过Spring的工厂及配置文件,为对象(bean, 组件)的成员变量赋值
依赖注入:当一个类需要另一个类时,就意味着依赖,一-旦出现依赖,就可以把另-个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)。
- 好处:解耦合