讲解之前首先了解Spring从配置上下文环境到最后注入bean的整个过程
- 1.首先是Spring加载上下文环境,即将所有的bean都放入容器中
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol1.xml");
Coder coder = (Coder) ctx.getBean("javaer4");
- 2.然后从上下文环境中寻找加载的bean,一般来说我们已经在XML文件中通过配置
<bean>
配置好了需要寻找的bean。
<bean id="song1" class="com.springinaction.springidol.Song1" />
- 3.然后注入寻找到的bean依赖,通过前面讲的@Autowired或者@Inject
我们前文中其实讲的都是第三步,即注入bean时的一些简化XML的方法,现在我们讲一下第二步,即如何简化寻找bean的配置方法。想要寻找bean,必先定义bean,一般我们都是提前在XML文件中配置好了bean,现在如果我们不在XML中配置bean,而是在需要成为bean的那个类上加上某种注解,然后在XML中只配置一个范围,告诉容器在这个范围内找我们需要的bean,这样是不是简单很多了呢?
前文在讲自动注入的时候,在XML中加了<context:annotation-config>
来使用自动注入功能,现在我们使用另一个元素 <context:component-scan>
,这个元素首先能实现<context:annotation-config>
的所有功能,更重要的是它是为了让Spring上下文自动寻找这个元素限定的范围中的bean并且自动声明bean,而不需要再使用<bean>
来配置。
具体加入XML文件中的代码如下:
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan
base-package="com.springinaction.springidol">
</context:component-scan>
<context:component-scan>
元素工作原理是搜索一个包,寻找其中可以自动注解成Spring容器中的bean的类; base-package属性告诉<context:component-scan>
应当从那个包开始寻找。
那么,<context:component-scan>
是如何知道哪些类能成为Spring容器的bean呢?下面揭晓答案。
1 用于自动搜索的注解bean方式
<context:component-scan>
搜索bean的默认方式是搜索被以下几种注解方式注解的类。
- @Component——这是一种通用的注解方式,指明该类是一个Spring组件
- @Controller——指明该类定义了一个SpringMVC的控制器
- @Repository——指明该类定义了一个数据仓库
- @Service——指明该类定义了一个服务
- 任何使用了自定义注入的类必须使用@Component方式注解。
还是通过一个具体的实例来说明:程序员在听歌。
首先给出主体类SongJavaer2.java
@Component("javaer")
public class SongJavaer2 implements Coder{
@Inject
private Song songJay;
public void setSongJay(Song songJay) {
this.songJay = songJay;
}
public void perform() {
System.out.println("Trigl is writing " + " blogs.");
System.out.println("While listening...");
songJay.play();
}
}
注意这里的注解方式@Component(“javaer”),括号里面的内容相当于bean的名字,即在XML中配置bean时候的id。
然后给出要注入的依赖类Song1.java
@Component
public class Song1 implements Song {
public void play() {
System.out.println("是他就是他,是他就是他,我们的英雄,小哪吒!......");
System.out.println();
}
}
这里的注解@Component没有括号中的内容,此时bean的id是默认名字,即对应首字母小写的类名,如该类名是Song1,那么默认bean名字就是song1.
XML文件配置
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan
base-package="com.springinaction.springidol">
</context:component-scan>
<!-- Bean declarations go here -->
</beans>
main主函数进行测试
public class MainTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol1.xml");
Coder coder = (Coder) ctx.getBean("javaer");
coder.perform();
}
}
控制台输出为:
Trigl is writing blogs.
While listening...
是他就是他,是他就是他,我们的英雄,小哪吒!......
2 过滤component-scans
使用<context:component-scan>
已经很方便了,然而我们还是需要在类上加上@Component才可以,那能否更简化一下呢,例如不用在类上加@Component也可以找到?答案是可以的,但是仅限于实现一个接口的哪些类,通过添加 <context:include-filter>
和<context:exclude-filter>
就可以实现将某些继承于同一方法的类自动注解(取消自动注解)。
例如上面例子的很多类都是实现的Song接口,我们只要用如下方式就可以将其自动注解,而不需要在类上再加@Component
<context:component-scan
base-package="com.springinaction.springidol">
<context:include-filter type="assignable"
expression="com.springinaction.springidol.Song"/>
</context:component-scan>
<context:include-filter>
的type和expression属性共同为了自动注解某一接口的实现类而起作用。在上面定义的情况下,所有实现Song接口的类都将被自动注解成为Spring的bean,bean的id就是默认名字。
除了这种情况,type属性的其他取值如下:
过滤类型(type) | 描述 |
---|---|
anotation | 默认的过滤方式,必须在类上加上注解,然后过滤器才能搜索到 |
assignable | 过滤器搜索expression属性指定的接口的实现类,在这些实现类上不需要加注解 |
aspectj | 过滤器搜索与expression属性指定的AspectJ表达式相匹配的类,在这些匹配的类上不需要加注解 |
custom | 使用自定义的org.springframework.core.type.TypeFilter的实现类,该类由expression属性指定 |
regex | 过滤器扫描类的名称与expression属性指定的正则表达式相匹配的那些类 |
还是举一个实例来说明:程序员在听歌
主体类SongJavaer2
@Component("javaer")
public class SongJavaer2 implements Coder{
@Inject
@Named("song1")
private Song songJay;
public void setSongJay(Song songJay) {
this.songJay = songJay;
}
public void perform() {
System.out.println("Trigl is writing " + " blogs.");
System.out.println("While listening...");
songJay.play();
}
}
@Named(“song1”)指明依赖的bean,因为实现Song接口的bean有很多
依赖类Song1.java
public class Song1 implements Song {
public void play() {
System.out.println("是他就是他,是他就是他,我们的英雄,小哪吒!......");
System.out.println();
}
}
这个类实现了Song接口,在下面的XML中将会配置,所以这里就不需要加上注解@Component,自动会声明一个bean,bean的id是默认的song1
XML配置扫描过滤器
<context:component-scan
base-package="com.springinaction.springidol">
<context:include-filter type="assignable"
expression="com.springinaction.springidol.Song"/>
</context:component-scan>
main主方法进行测试
public class MainTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol1.xml");
Coder coder = (Coder) ctx.getBean("javaer");
coder.perform();
}
}
控制台输出结果为:
Trigl is writing blogs.
While listening...
是他就是他,是他就是他,我们的英雄,小哪吒!......
OVER