注入详解
注入分为两种,如下:
- Set 注入
- 构造注入
Set 注入详解
使用 <property>
标签。
对成员变量进行注入赋值。针对于 不同类型的成员变量。在<property>
标签中可以嵌套其他标签。
成员变量分为两类:
- JDK内置类型
- 用户自定义类型
JDK内置类型
JDK内置类型,Java本身定义的类型例如:
int
String[]
Set<String>
List<String>
Map<String>
Properties
怎么进行赋值呢?如下分别进行讨论。
String
+ 8 种基本类型(char, boolean, byte、short、int、long、float、double )
使用<value>
标签。
// private int id;
<property name="id">
<value>10</value>
</property>
// private String name;
<property name="name">
<value>Adam</value>
</property>
- 数组类型,需要新增
<list>
标签。
// private String[] emails;
<property name="emails">
<list>
<value>sun@gamil.com</value>
<value>adam@gamil.com</value>
<value>bob@gamil.com</value>
</list>
</property>
- set 集合
配置集合,set集合无序,不重复。
<set>
标签是set集合的核心。里面嵌套各种类型标签。这里是<value>
标签是因为定义了set<String>
String的泛型。
// private Set<String> tels;
<property name="tels">
<set>
<value>13231323123</value>
<value>13231323123</value>
<value>13661366166</value>
</set>
</property>
//输出只有两个值,set会把重复的值过滤调,不可重复,且无序
//13231323123
//13661366166
- List 集合
有序,可重复,使用<list>
标签,里面可嵌套其他标签。
// private List<String> addresses;
<property name="addresses">
<list>
<value>cpark</value>
<value>askin</value>
<value>partington</value>
<value>askin</value>
</list>
</property>
//ouput:
//cpark
//askin
//partington
//askin
- Map 集合
需要有<map>
<entry>
<key>
标签,值根据对应的类型选取标签。
<entry>
标签 里面对应一个键``值
对。
键
需要用一个<key>
标签来标记,键的泛型是String类型,所以在嵌套一个<value>
标签。
值
没有特殊标签,值的泛型是String类型 用<value>
标签。
// private Map<String,String> maps;
<property name="maps">
<map>
<entry>
<key><value>key0</value></key>
<value>123123</value>
</entry>
<entry>
<key><value>key1</value></key>
<value>456456</value>
</entry>
</map>
</property>
- Properties 类型
Properties类型是特殊的map。 key value 都是String类型, key = String value=String
使用<props>
和<prop>
标签。
一个<prop>
标签里面就代表一个键
值
对,
键
写在 key属性里,
值
直接写在<prop>
</prop>
标签之间,本身就是string类型所以省去了<value>
标签。
// private Properties p;
<property name="p">
<props>
<prop key="user">value1</prop>
<prop key="user2">value2</prop>
</props>
</property>
用户自定义类型
- 为用户提供set get方法
但是还是需要创建set get 方法,因为Spring在底层反射创建的时候会 自动调用这些函数。
我们所说的解藕,不是不需要这些函数,而是我们给对象属性赋值或更新值的时候,不需要在代码里修改(在代码里修改还需要重新编译),而是通过修改配置文件,并不需要重编代码。
package com.gogogo;
public class UserServiceImpl implements UserService{
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
- 配置文件中进行注入(赋值)
<property>
属性就是在为我们的成员变量 set 值。
//public class UserServiceImpl implements UserService{
// private UserDAO userDAO;
//}
//
<bean id="userService" class="com.gogogo.UserServiceImpl">
<property name="userDAO">
<bean class="com.gogogo.UserDAOImpl"/>// 只使用一次,此处省略id配置
</property>
</bean>
- 第二种赋值方式
如下我们会发现,代码冗杂,每次都要重新创建userDAO
,占用内存。
<bean id="userService" class="com.gogogo.UserServiceImpl">
<property name="userDAO">
<bean class="com.gogogo.UserDAOImpl"></bean>
</property>
</bean>
<bean id="orderService" class="com.gogogo.OrderServiceImpl">
<property name="userDAO">
<bean class="com.gogogo.UserDAOImpl"></bean>
</property>
</bean>
解决方案:
先创建 userDAO
增加 id
属性,方便被调用。
<bean id="userDAO" class="com.gogogo.UserDAOImpl"></bean>
使用<ref bean="bean_id">
引用 userDAO
成员变量。
<bean id="userService" class="com.gogogo.UserServiceImpl">
<property name="userDAO"> //成员属性名
<ref bean="userDAO"></ref> // 引用上面定义的bean
</property>
</bean>
<bean id="orderService" class="com.gogogo.OrderServiceImpl">
<property name="userDAO"> //成员属性名
<ref bean="userDAO"></ref> // 引用上面定义的bean
</property>
</bean>
Set 注入简化写法
- 基于属性简化
- JDK 类型注入
value 属性替换<value>
标签。
注意:只能是基于String类型 + 8种基本类型 (char, boolean, byte, short, int, long, float, double), 简化<value>
标签。
//<property name="id">
// <value>10</value>
//</property>-->
<property name="id" value="10"></property>
//<property name="name">
// <value>Cristina</value>
//</property>-->
<property name="name" value="Cristina"></property>
- 用户自定义类型
ref 属性替换<ref>
标签。
<bean id="userDAO" class="com.gogogo.UserDAOImpl"></bean>
//<bean id="userService" class="com.gogogo.UserServiceImpl">
// <property name="userDAO">
// <ref bean="userDAO"></ref>
// </property>
//</bean>
<bean id="userService" class="com.gogogo.UserServiceImpl">
<property name="userDAO" ref="userDAO">
</property>
</bean>
- 基于 命名空间 p 简化
新增 命名空间p:name="xiaowang" p:id="3"
即省去了后面的赋值,且需要引入xmlns:p="http://www.springframework.org/schema/p"
格式如下:
<bean id="" class="" p:name="" p:id ="" />
<bean id="" class="" p:userDAO-ref=""></bean>
<bean id="person" class="com.gogogo.Person" p:name="xiaowang" p:id="3">
// <property name="id" value="10"></property>
// <property name="name" value="Cristina"></property>
</bean>
//<bean id="userService" class="com.gogogo.UserServiceImpl">
// <property name="userDAO" ref="userDAO">
// </property>
//</bean>
<bean id="userService" class="com.gogogo.UserServiceImpl" p:userDAO-ref="userDAO"/>
构造注入
Spring调用构造方法,通过配置文件为成员变量赋值。使用 <constructor-arg>
标签。
- 开发步骤
- 提供有参构造方法
package com.gogogo.constructer;
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;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 提供配置文件
因为不是set注入不提供set方法,那配置文件中就不能使用<Property>
标签,构造注入使用<constructor-arg>
标签, 一个<constructor-arg>
标签 注入一个属性,且顺序要和类中定义的成员属性顺序一致,否则编译保存。
// private String name;
// private int age;
<bean id="customer" class="com.gogogo.constructer.Customer">
<constructor-arg name="name" value="jake"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
</bean>
测试结果
public void Test4(){
// 获得工厂
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//获得对象
Customer customer = (Customer) ctx.getBean("customer");
System.out.println("customer: " + customer);
}
// ouput
// customer: Customer{name='jake', age=22}
构造方法重载
函数名相同(参数个数不同,参数类型不同)
- 参数个数不同
通过控制<constructor-arg>
标签个数来处理 - 构造参数个数相同
指定类型,引入type 属性
进行区分
总结
Set 注入使用 <property>
标签
构造注入使用 <constructor-arg>
标签,顺序要一致
Set注入在实战中运用更多,构造注入要考虑重载,比较麻烦,Spring框架底层 也大量运用了set注入。
奥利给
祝学习开心❤️