NO.9 Spring IOC 依赖注入—自动扫描
之前,我们都是将所有的配置都配置到配置文件中,假如一个工程中有成百上千个配置文件,那么找寻每个bean的配置就很难,怎么办呢?
假如一个业务逻辑,需要3-4个JavaBean,如果一个系统中需要几十个或上百个业务逻辑,需要300-400个Java文件。例如一个学生信息的维护,控制层stuAction,Service层stuService,Dao层stuDao,一个业务逻辑中最低要向配置文件中配置这三个,那么有没有一种比较好的方式?Spring提供了一种通过注解的方式让Spring进行扫描。
自动扫描,就是采用注解的形式。
特定组件包括:
@Component: 基本注解, 标识了一个受 Spring 管理的组件,通常标识在一些插件或过滤器上。
@Respository: 标识持久层组件,注解Dao层
@Service: 标识服务层(业务层)组件
@Controller: 标识控制层组件
@Component包含后三个,只要是JavaBean都可以用@Component去注解,后三个则是为了使程序有一定的分层能力。
首先,了解Spring中的自动扫描器.
context:component-scan 标签表示spring bean组件自动扫描器,通过属性base-package扫描对应包下的javabean或者子包中被注解的javaBean文件 。
<?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: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 ">
<context:component-scan base-package="com.xt.spring.ioc.anno"></context:component-scan>
</beans>
业务层
package com.xt.spring.ioc.anno.service;
import org.springframework.stereotype.Service;
@Service
public class StuService {
}
Dao层
package com.xt.spring.ioc.anno.dao;
import org.springframework.stereotype.Repository;
@Repository
public class StuDao {
}
IOCTest
package com.xt.spring.ioc.anno;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xt.spring.ioc.anno.dao.StuDao;
public class IOCTest {
private ApplicationContext ioc;
@Before
public void iocInit(){
ioc = new ClassPathXmlApplicationContext("spring/applicationContext-anno.xml");
}
@Test
public void iocTest(){
StuDao stuDao = ioc.getBean("stuDao",StuDao.class);
}
}
综上,不用在配置文件中配置bean,只需要标注需要扫描的bean。
当然注解也有自己的作用,倘若想要改名的话,可以直接在注解后面加上括号(stuDao1)@Repository("stuDao1")
,这时就获取不到stuDao,想要获取就要采取stuDao1进行获取,如果没有(”“),默认采用类名首字母小写。
倘若不想在bean上面加注解,能否扫描呢?
stuAction没有注解,那么如何获取到呢?配置文件:
<context:component-scan base-package="com.xt.spring.ioc.anno">
<context:include-filter type="regex" expression=".*Action"/>
<!-- 比方说想要扫描类名结尾是action的,采用.*Action,*代表前面的字母,action代表以action结尾
include表示扫描进来,exclude表示去除-->
</context:component-scan>
annotation是采用注解的方式,regex表示采用正则表达式方式,类似模糊查询。
这种方式只作了解。
怎么将Dao,Service注入到Action中?之前可通过配置文件,那么现在怎么办?
——使用 @Autowired 自动装配 Bean
@Autowired
private StuDao stuDao;
配置文件中不必再配置
<context:component-scan base-package="com.xt.spring.ioc.anno">
<context:include-filter type="regex" expression=".*Action"/>
</context:component-scan>
倘若Dao有两个实现类StudentDaoJdbcImpl,StudentDaoMybatisImpl,这时就会报错,那该如何解决呢?
使用两个注解@Autowired,@Qualifier,名称加类型结合使用
@Autowired
@Qualifier("stuJdbcDao")//注入的bean的id
private StuDao stuDao;
目前,是通过声明属性的形式向bean中注入一个bean,还可以通过set方法,通过参数注入进去。
private StuDao stuDao;
@Autowired @Qualifier("stuJdbcDao")
public void setStuDao(StuDao stuDao) {
this.stuDao = stuDao;
}
如果想要有就注入,没有就不注入不报错,这个时候可设置Autowired中的属性required=false
综上:
1)@Autowired 注解自动装配具有兼容类型的单个 Bean属性
2)构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
3)默认情况下, 所有使用 @Authwired 注解的属性都需要被设置。 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false。
4)默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时(有多个实现类), 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称。
5) @Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配。
6)@Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.。
7)@Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值