组件扫描
组件扫描(component scanning
): Spring
能够从 classpath
下自动扫描, 侦测和实例化具有特定注解的组件.
- @Component: 基本注解, 标识了一个受 Spring 管理的组件
- @Repository: 标识持久层组件
- @Service: 标识服务层(业务层)组件
- @Controller: 标识表现层组件
对于扫描到的组件, Spring
有默认的命名策略: 使用非限定类名, 第一个字母小写。 也可以在注解中通过 value 属性值标识组件的名称。
当在组件类上使用了特定的注解之后, 还需要在 Spring
的配置文件中声明 <context:component-scan>
:
- base-package
属性指定一个需要扫描的基类包,Spring
容器将会扫描这个基类包里及其子包中的所有类
.
- 当需要扫描多个包时, 可以使用逗号分隔
.
- 如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern
属性过滤特定的类,示例:
<context:component-scan base-package="annotation" resource-pattern="service/*.class">
</context:component-scan>
<context:include-filter>
子节点表示要包含的目标类<context:exclude-filter>
子节点表示要排除在外的目标类<context:component-scan>
下可以拥有若干个<context:include-filter>
和<context:exclude-filter>
子节点
<context:include-filter>
和 <context:exclude-filter>
子节点支持多种类型的过滤表达式:
注意
<context:include-filter>
需要use-default-filters="false"
配合使用
<!-- 除去该包下的所有继承或拓展 UserService的类 -->
<context:component-scan base-package="annotation">
<context:exclude-filter type="assignable"
expression="annotation.service.UserService"/>
</context:component-scan>
<!-- 只包含用Service这个注解标示的类 -->
<context:component-scan base-package="annotation" use-default-filters="true">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Service"/>
</context:component-scan>
组件装配
<context:component-scan>
元素还会自动注册 AutowiredAnnotationBeanPostProcessor
实例, 该实例可以自动装配具有 @Autowired
和 @Resource
、@Inject
注解的属性.
使用 @Autowired 自动装配 Bean
- 构造器, 普通字段(即使是非
public
), 一切具有参数的方法都可以应用@Autowired
注解 - 默认情况下, 所有使用
@Autowired
注解的属性都需要被设置. 当Spring
找不到匹配的Bean
装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置@Authwired
注解的required
属性为false
- 默认情况下, 当
IOC
容器里存在多个类型兼容的Bean
时, 通过类型的自动装配将无法工作. 此时可以在@Qualifier
注解里提供Bean
的名称.Spring
允许对方法的入参标注@Qualifiter
已指定注入Bean
的名称
@Autowired
@Qualifier("userService")
private UserService userService;
//or like this
@Autowired
@Qualifier("userService")
public void setUserService( UserService userService) {
this.userService = userService;
}
//or like this
@Autowired
public void setUserService(@Qualifier("userService") UserService userService) {
this.userService = userService;
}
@Autowired
注解也可以应用在数组类型的属性上, 此时Spring
将会把所有匹配的Bean
进行自动装配.@Autowired
注解也可以应用在集合属性上, 此时Spring
读取该集合的类型信息, 然后自动装配所有与之兼容的Bean
.@Autowired
注解用在java.util.Map
上时, 若该Map
的键值为String
, 那么Spring
将自动装配与之Map
值类型兼容的 Bean, 此时 Bean 的名称作为键值
泛型依赖注入
Spring 4.x 中可以为子类注入子类对应的泛型类型的成员变量的引用.
来看一个栗子:
public class BaseService<T> {
@Autowired
protected BaseRepository<T> baseRepository;
public void add() {
System.out.println(this.getClass().getSimpleName());
System.out.println(baseRepository);
}
}
public class BaseRepository<T> {
}
@Service
public class UserService extends BaseService<User> {
}
@Repository
public class UserRepository extends BaseRepository<User>{
}
public class User {
}
@Test
public void test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("generic-di.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.add();
}
//输出
UserService
generic.di.UserRepository@64f6106c
我们从输出中可以看出,IOC注入的是泛型的子类。