从这一章开始,我们逐步抛弃xml格式的配置,讲述如何使用java注解和java代码来配置bean,这一部分分成了三个章节。这一章,讲述如何使用注解在java类上定义bean;下一章,讲述如何通过注解配置bean之间的依赖,第三章讲述如何使用java代码来定义bean。
定义bean的注解
目前Spring提供了@Component, @Service, @Controller,@Repository四个bean定义的注解。最基础的的是@Component,其他几个都是基于它定义的,分别用在特定的场景:@Service用于service类,@Controller用于web mvc的控制器,@Repository用于DAO类。
从bean的定义、初始化、装配这个层面讲,这几个注解没有本质区别;不同的注解在特定的场景下有特定的附加功能,比如对@Repository注解的bean,Spring会执行自动的数据库异常转换;spring web mvc只会对@Controller执行url映射。
你还可以通过组合的方式,创建自定义的注解,比如@RestController就是@Controller和@ResponseBody的组合。这种组合的方式可以对原始注解的属性进行定制。
@Service
@Scope("singleton")
@Qualifier("Action")
public class SimpleMovieLister {
}
上面通过@Service定义了一个bean,并且通过注解定义了它的scope和qualifier。
Bean的命名规则
你可以直接在注解里面设置bean的名字,类似:
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
否则的话,Spring依据类名自动生成bean name,规则是:将第一个字母变为消息,如果类名的前两个字母都是大写,则不变换。
通过实现BeanNameGenerator接口,还可以使用自定义的bean name生成规则,定义方式如下:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
从java包扫描Bean定义
接下来,我们还得告诉容器去发现这些通过注解定义的bean,一句简单的配置即可:
<beans>
<context:component-scan base-package="org.example"/>
</beans>
这个定义告诉容器,请递归扫描org.example
这个包名下的所有类,从而找出那些被@Component及相关注解定义的Bean。
我们还可以通过include-filte和exclude-filter来添加扫描过滤条件:
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
上面的配置,意味着只扫描org.example
下面,类名以*stub.*Respository
结尾,且没有被@Repository注解的类。
ComponentScan过滤器
过滤类型 | 示例 | 描述 |
---|---|---|
annotation (default) | org.example.SomeAnnotation | 类型存在该注解 |
assignable | org.example.SomeClass | 类型是SomeClass的子类或实现了SomeClass接口 |
aspectj | org.example…*Service+ | 类型与该AspectJ表达式匹配 |
regex | org.example.Default.* | 类名与该正则表达式匹配,匹配的规则请查询文档 |
custom | org.example.MyTypeFilter | 自定义的过滤器,实现了TypeFilter接口 |
注:还可以对component-scan添加一个use-default-filters=false属性,这样依赖,默认的扫描规则就全失效了,即被@Component注解的类型也不会被发现。
生成编译时Bean索引
一般来说bean的扫描非常快,不会影响性能,但如果是一个非常庞大的系统,为了提升启动时间,可以在编译时为每个jar生成一份Bean的静态索引。这样,Spring启动的时候,就不需要扫描指定包名的类,直接读取这个索引文件即可。
这是一个编译功能,需要使用一个maven插件,它在jar下面生成一个META-INF/spring.components文件:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.1.9.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
注意:如果要使用这个功能,那就要保证所有的bean被包含在索引文件里面。