前言
我们知道spring框架的核心就是IOC容器了,那么IOC容器主要的作用就是创建对象和处理对象之间的依赖关系。上次介绍了创建对象的集中方式,那么本文主要延续上一节内容,讲解IOC容器如何处理对象之间的依赖关系。
依赖注入(DI)
依赖注入是通过IOC容器将指定的依赖对象或者基本类型的变量注入指定的对象中。这么说比较抽象。比如:之前的mvc设计模式,在action中需要调用service层的方法,就必须由程序员自己new一个service实例,然后才能使用,即action必须依赖service才能实现业务。还有这种new一个对象,硬编码的方式也不利于维护。现在有了IOC容器,可以由容器帮助我们创建对象以及处理对象之间的依赖关系。所有事都交给容器来管理。我们只管会配置会使用它即可。
依赖注入的方式
(1)set方式注入(最常用)
<!-- dao instance -->
<bean id="userDao" class="com.nwpu.geeker.UserDao"></bean>
<!-- service instance -->
<bean id="userService" class="com.nwpu.geeker.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- action instance -->
<bean id="userAction" class="com.nwpu.geeker.UserAction">
<property name="userService" ref="userService"></property>
</bean>
**注意:**set方式最常用也是必须得掌握的。因为在实现开发中,mvc设计模式下dao层是数据访问接口层,service是业务逻辑层,在处理业务逻辑的时候,必须要和数据打交道。那么就必须依赖于dao层的方法。因此必须在service层依赖dao层的对象。而Action层也必须依赖service层处理业务。所以,上面配置是将userDao注入到userService中,将userService注入到userAction中。Ref属性必须是已存在于IOC容器的对象才能直接引用。
(2)内部bean方式
<bean id="userAction" class="com.nwpu.geeker.UserAction">
<property name="userService">
<bean class="com.nwpu.geeker.UserService">
<property name="userDao">
<bean class="com.nwpu.geeker.UserDao"></bean>
</property>
</bean>
</property>
</bean>
内部bean的方式主要是定义一个bean就能实现这个bean所依赖的对象的所有方法。缺点就是只能使用外部的bean,内部的bean不能使用。例如:只能使用userAction,而不能使用里面bean,userService实例。
(3)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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
给对象属性注入值:
# p 名称空间给对象的属性注入值
(spring3.0以上版本才支持)
-->
<bean id="userDao" class="com.nwpu.geeker.UserDao"></bean>
<bean id="userService" class="com.nwpu.geeker.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="com.nwpu.geeker.UserAction" p:userService-ref="userService"></bean>
<!-- 传统的注入:
<bean id="user" class="com.nwpu.geeker.User" >
<property name="name" value="xxx"></property>
</bean>
-->
<!-- p名称空间优化后 -->
<bean id="user" class="com.nwpu.geeker.User" p:name="Jack001"></bean>
</beans>
P名称空间注入方式必须在配置文件中添加 xmlns:p="http://www.springframework.org/schema/p"
,直接在《bean》标签中使用p属性即可,很方便。
(4)自动装配(了解)
根据名称自动装配:autowire=”byName”,自动去IOC容器中找与属性名同名的引用的对象,并自动注入。
<!-- ###############自动装配############### -->
<bean id="userDao" class="com.nwpu.geeker.UserDao"></bean>
<bean id="userService" class="com.nwpu.geeker.UserService" autowire="byName"></bean>
<!-- 根据“名称”自动装配: userAction注入的属性,会去ioc容器中自动查找与属性同名的对象 -->
<bean id="userAction"
class="com.nwpu.geeker.UserAction" autowire="byName"></bean>
也可以定义到全局, 这样就不用每个bean节点都去写autowire=”byName”
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byName"> 根据名称自动装配(全局)
<!-- ###############自动装配############### -->
<bean id="userDao" class="com.nwpu.geeker.UserDao"></bean>
<bean id="userService" class="com.nwpu.geeker.UserService"></bean>
<bean id="userAction" class="com.nwpu.geeker.UserAction"></bean>
</beans>
根据类型自动装配:autowire=”byType”,必须确保改类型在IOC容器中只有一个对象;否则报错。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType">
<!-- ###############自动装配############### -->
<bean id="userDao" class="com.nwpu.geeker.UserDao"></bean>
<bean id="userService" class="com.nwpu.geeker.UserService"></bean>
<!-- 如果根据类型自动装配: 必须确保IOC容器中只有一个该类型的对象 -->
<bean id="userAction" class="com.nwpu.geeker.UserAction"></bean>
<!-- 报错: 因为上面已经有一个该类型的对象,且使用了根据类型自动装配
<bean id="userService_test" class="com.nwpu.geeker.UserService" autowire="byType"></bean>
-->
</beans>
总结:
Spring提供的自动装配主要是为了简化配置; 但是不利于后期的维护。(一般不推荐使用)
(5)注解
注解方式可以简化spring的IOC容器的配置!
使用注解步骤:
1)先在配置文件中引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
2)开启注解扫描(指定扫描的包)
<context:component-scan base-package="com.nwpu.geeker"></context:component-scan>
3)使用注解
通过注解的方式,把对象加入ioc容器。
创建对象以及处理对象依赖关系,相关的注解如下:
@Component 指定把一个对象加入IOC容器
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource 属性注入
代码演示:
dao层
// 把当前对象加入ioc容器
//@Component("userDao") // 相当于bean.xml 【<bean id=userDao class=".." />】
//@Component // 加入ioc容器的UserDao对象的引用名称, 默认与类名一样, 且第一个字母小写
//@Repository // 在持久层可以选择用这个注解
public class UserDao {
public UserDao(){
System.out.println("UserDao.UserDao()");
}
public UserDao(int id){
System.out.println("UserDao.UserDao(int id)" + id);
}
public void save() {
System.out.println("DB:保存用户!!!");
}
}
service层
//@Component("userService") // userService加入ioc容器
//@Component
@Service // 表示业务逻辑层的组件
public class UserService {
// @Resource // 根据类型查找 【在容器中要确保该类型只有一个变量】
@Resource(name = "userDao") // 根据名称查找
private UserDao userDao; // 去容器中找UserDao类型的变量,找到后就赋值
public void save() {
userDao.save();
}
}
action层
//@Component("userAction") // 加入IOC容器
//@Component
@Controller // 控制层的组件
public class UserAction {
@Resource
private UserService userService;
public String execute() {
userService.save();
return null;
}
}
总结:
1) 使用注解,可以简化配置,且可以把对象加入IOC容器,及处理依赖关系(DI)
2) 注解可以和XML配置一起使用。