开启自动检测
开启自动检测Bean有两种方式:
XML配置
<context:annotation-config>
虽然消除了<property>
和<constructor-arg>
元素,但我们仍需使用<bean>
元素显示定义Bean。
<context:component-scan>
除了完成与<context:annotation-config>
一样的工作还可以自动检测Bean和定义Bean。在Spring XML中配置:
1 | <context:component-scan base-package="com.spring.entity"> |
base-package指定了扫描的路径。
Java配置
1 | import org.springframework.context.annotation.ComponentScan; |
@ComponentScan
会扫描与该类相同包下的所有带有@Component
注解的类。
如果想明确指出扫描路径,可以配置value:
1 | "com.spring") (basePackages= |
也可以配置多个扫描路径:
1 | "com.spring.entity","com.spring.dao"}) (basePackages={ |
除了指定扫描路径,我们也可以指定扫描的类型:
1 | (basePackageClasses={Piano.class,Guitar.class}) |
为自动检测标注Bean
注解类型:
@Component
—— 通用的构造型注解,标识该类为Spring组件。
@Controller
—— 标识将该类定义为Spring MVC Controller组件。
@Repository
—— 标识将该类定义为数据仓库。
@Service
—— 标识将该类定义为服务。
通过标注这些注解,Spring才知道哪些类要被注册为Spring Bean。如,使用@Component
标注Guitar类:
1 |
|
Spring扫描com.spring.entity
包时,会发现使用@Component
注解所标注的Guitar,并自动将其注册为Spring Bean。Bean的ID默认为无限定首字母小写类名,也就是guitar。
我们也可以显式设定ID:
1 | "kenny") ( |
也可以使用@Named("kenny")
代替@Component("kenny")
,但一般我们还是使用@Component("kenny")
比较直观。
然后实例化kenny Bean:
1 | public class Play { |
输出:
1 | 唱:May Rain |
现在在XML中没有任何<bean>
元素,也实现了和先前一样的效果。在这个过程中,遇到了两个问题:
1 | Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: |
通过查阅资料,发现有位老外给出了解释:
Note that the Java 8 bytecode level (-target 1.8, as required by -source 1.8) is only fully supported as of Spring Framework 4.0. In particular, Spring 3.2 based applications need to be compiled with a maximum of Java 7 as the target, even if they happen to be deployed onto a Java 8 runtime. Please upgrade to Spring 4 for Java 8 based applications.
于是将jdk改为1.7版本。修改后又遇到异常:
1 | Exception in thread "main" java.lang.UnsupportedClassVersionError: |
原来是jdk版本和jvm版本不一致所致。右键项目–>properties–>java compiler –> Enable project specific settings –>将compiler compliance level设置为1.7,至此问题都解决了。
过滤组件扫描
<context:component-scan>
默认扫描指定路径下通过@Component
标注的Bean。假如现在我们只要把Instrument所派生的类注册为Spring Bean,我们不得不去查看所有java代码,一个一个的给Instrument派生类添加@Component
注解,假如有第三方实现了Instrument,其源码我们还看不到,这时候添加@Component
注解就变得非常困难甚至不可能。幸好,我们还可以给<context:component-scan>
元素添加过滤行为:通过为其配置<context:include-filter>
和<context:exclude-filter>
子元素。比如:
1 | <context:component-scan base-package="com.spring.entity"> |
其中,过滤器类型有5种:
过滤器类型 | 描述 |
---|---|
annotation | 过滤器扫描使用指定注解所标注的那些类,通过expression属性指定要扫描的注解 |
assignable | 过滤器扫描派生于expression属性所指定类型的那些类 |
aspectj | 过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类 |
custom | 使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression 属性指定 |
regex | 过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的类 |
com.spring.entity.SkipIt
自定义限定器:
1 | ({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE}) |
com.spring.entity
目录下有三个类派生于Instrument:Piano,Saxophone,Guitar。现在用@SkipIt
标注Piano和Guitar类:
1 |
|
1 |
|
Saxophone不做任何标注:
1 | public class Saxophone implements Instrument{ |
实例化kenny,输出:
1 | 唱:May Rain |
非常方便!