示例
(1)创建接口 UserService 以及实现类 UserServiceImple
UserService:
package Service;
public interface UserService {
public void say();
}
UserServiceImple:
package Service.Implement;
import Dao.UserDao;
import Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceImple implements UserService {
@Override
public void say() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.say();
}
}
(2)在 xml 配置文件中增加 UserServiceImple 的配置信息
<bean id="userService" class="Service.Implement.UserServiceImple"/>
(3)创建 UserController 类进行测试
import Service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) app.getBean("userService");
userService.say();
}
}
问题分析
这种做法将 UserServiceImple 和 UserDaoImple 的实例都存在 Spring 容器中,在程序中完成了二者的组装,而在 Controller 中只需要使用 UserServiceImple ,而不需要关心 UserDaoImple 如何获取,故考虑在容器内部完成二者的组装
依赖注入(DI)
依赖注入是 Spring框架中IoC的具体体现
在编写程序时,通过控制反转,将对象的创建交给了 Spring 来控制,但代码中一定还会存在依赖的情况,如业务层调用持久层的方法,依赖注入可以让 Spring 自动的向某个对象提供它需要的对象
bean 的依赖注入方式
(1)构造方法
修改 UserServiceImple ,增加无参和含参数 UserDao 的构造方法,删除不必要的代码
package Service.Implement;
import Dao.UserDao;
import Service.UserService;
public class UserServiceImple implements UserService {
private UserDao userDao;
public UserServiceImple() {
}
public UserServiceImple(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void say() {
userDao.say();
}
}
在 xml 配置文件中增加依赖注入的配置信息,用 <constructor-arg> 标签进行构造方法的参数传入
用 name 指定构造方法参数的形参名,
用 ref 指定传入的对象的 id,这里需要传入容器中 UserDaoImple 的实例,故为对应 bean 的 id
<bean id="userDao" class="Dao.Implement.UserDaoImple"/>
<bean id="userService" class="Service.Implement.UserServiceImple">
<constructor-arg name="userDao" ref="userDao"/>
</bean>
(2)set 方法
修改 UserServiceImple ,增加 UserDao 成员和 set 方法,删除不必要的代码
package Service.Implement;
import Dao.UserDao;
import Service.UserService;
public class UserServiceImple implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void say() {
userDao.say();
}
}
在 xml 配置文件中增加依赖注入的配置信息,用 <property> 标签进行属性注入
用 name 指定该类中相应的 set 方法名后面的字段,并将第一个字母改为小写,如该类中的 setUserDao 方法,name 即为 userDao,而并非是该类中成员变量 userDao,尽管二者相同
用 ref 指定需要注入的对象的 id,与上文中的 ref 同理,填写容器中相应 bean 的 id 即可
<bean id="userDao" class="Dao.Implement.UserDaoImple"/>
<bean id="userService" class="Service.Implement.UserServiceImple">
<property name="userDao" ref="userDao"/>
</bean>
经过这样的配置后,UserController 中调用 getBean 方法获取 UserServiceImple 对象时,该对象便已经自动装载了 UserDaoImple 实例,但如果直接使用 new 创建 UserServiceImple 对象,则没有这个效果,也就是说,只有容器内的对象才能自动装载需要的实例
(3)p命名空间注入
该方法与 set 方法类似,需要在 UserServiceImple 类中创建 set 方法
区别在于 xml 配置文件中不再使用 <property> 标签进行属性注入,而是在 <bean> 标签中通过属性的方式进行注入
首先声明p命名空间,在 xml 配置文件的 <beans> 标签上增加如下代码
xmlns:p="http://www.springframework.org/schema/p"
再使用 p:userDao-ref 属性指定需要注入的对象,同样的,这里的 userDao 也是与 set 方法名后面的字段的首字母改为小写保持一致
完整 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Dao.Implement.UserDaoImple"/>
<bean id="userService" class="Service.Implement.UserServiceImple" p:userDao-ref="userDao"/>
</beans>
bean 的依赖注入的数据类型
其中,引用数据类型的注入即为 bean 对象注入,刚刚已经做过详细叙述,不再赘述,重点介绍普通数据类型和集合数据类型
(1)普通数据类型
在 UserDaoImple 中增加两个普通数据类型的成员
对于 set 方法注入,需对每个数据成员创建 set 方法
package Dao.Implement;
import Dao.UserDao;
public class UserDaoImple implements UserDao {
private String userName;
private int age;
public void setUserName(String userName) {
this.userName = userName;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void say() {
System.out.println(userName + " " + age);
System.out.println("喵~");
}
}
在 xml 配置文件中使用 <property> 进行属性注入,使用 value 指定注入的内容
<bean id="userDao" class="Dao.Implement.UserDaoImple">
<property name="userName" value="猫头夜鹰"/>
<property name="age" value="18"/>
</bean>
对于构造方法注入,需创建相应的构造方法
package Dao.Implement;
import Dao.UserDao;
public class UserDaoImple implements UserDao {
private String userName;
private int age;
public UserDaoImple(String userName, int age) {
this.userName = userName;
this.age = age;
}
@Override
public void say() {
System.out.println(userName + " " + age);
System.out.println("喵~");
}
}
在 xml 配置文件中使用 <constructor-arg> 传入参数,使用 value 指定传入内容
<bean id="userDao" class="Dao.Implement.UserDaoImple">
<constructor-arg name="userName" value="猫头夜鹰"/>
<constructor-arg name="age" value="18"/>
</bean>
(2)集合数据类型
集合的种类较多,以 List 、Map 、Properties 三种集合为例,介绍集合注入
创建这三种类型的数据成员,并创建它们的 set 方法
package Dao.Implement;
import Dao.UserDao;
import Entity.User;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class UserDaoImple implements UserDao {
private List<String> strList;
private Map<String, User> userMap;
private Properties properties;
public void setStrList(List<String> strList) {
this.strList = strList;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public void say() {
System.out.println(strList);
System.out.println(userMap);
System.out.println(properties);
System.out.println("喵~");
}
}
其中,Map 中含有实体类 User
package Entity;
public class User {
private String userName;
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" + "userName='" + userName + '\'' + ", age=" + age + '}';
}
}
在 xml 配置文件中使用 <property> 进行属性注入,<property> 标签内部填写集合的具体内容
对于 List 、Map 、Properties 三种集合,分别使用 <list> 、<map> 、<props> 进行创建,在这些标签内部填写集合的具体内容,若为普通数据类型,则用 <value> ,若为键值对,则用 <entry> 并用属性 key 和 value 指定键和值,若键或值为引用类型,则使用 key-ref 或 value -ref 指定,若为 properties ,则用 <prop> 并用 key 指定键,而内容填写在标签中
<bean id="userDao" class="Dao.Implement.UserDaoImple">
<property name="strList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="userMap">
<map>
<entry key="user1" value-ref="user1"/>
<entry key="user2" value-ref="user2"/>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">result1</prop>
<prop key="p2">result2</prop>
<prop key="p3">result3</prop>
</props>
</property>
</bean>
<bean id="user1" class="Entity.User">
<property name="userName" value="皮卡丘"/>
<property name="age" value="3"/>
</bean>
<bean id="user2" class="Entity.User">
<property name="userName" value="卡比兽"/>
<property name="age" value="5"/>
</bean>
引入其他配置文件(分模块开发)
在实际开发中,配置内容会非常多,配置文件的体积较大,为了便于管理,可以将配置文件拆分保存,并在 Spring 的主配置文件中 <import> 标签进行加载
<import resource="applicationContext-product.xml"/>
<import resource="applicationContext-user.xml"/>
在加载主配置文件时,这些分文件的内容也会一同加载