严格的说,实际分为自动检测和自动装配两方面。
先说自动检测,自动检测就是允许Spring自动检测与定义Bean。这就意味着,不使用<bean/>,你也能实现Spring中大多数的Bean的定义和装配。
为启用这一功能,你得引入context命名空间。
<?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="org.chen.auto">
</context:component-scan>
</beans>
并使用context:component-scan,并在base-package指出在哪些包下的类能被检测。
问题来了,如果你要使多个包下的类都能被检测怎么办?谷歌 “context:component-scan multiple package”,答案是:
<context:component-scan base-package="x.y.z.service, x.y.z.controller" />
就是用都逗号分隔。
那么Spring会为哪些类注册成Bean呢?默认的,<context:component-scan>会查找使用构造型(stereotype)注解所注解的类,包括:
- @Component
- @Controller
- @Repository
- @Service
- 使用@Component标注的自定义注解
package org.chen.auto;
import org.springframework.stereotype.Component;
@Component("my-guitar")
public class Guitar implements Instrument {
public void play() {
System.out.println("play guitar ... ");
}
}
上面的Guitar类,使用了@Component注解,默认其ID是无限定类名,即guitar,当然你可以在使用注解时自定义。
这样就完成了自动检测和注册。
但是,如果需要把一个包下面的所有类写上个@Component也是够烦的。Spring为我们提供了过滤组件的扫描。
<context:include-filter /> 和 <context:exclude-filter />,分别是包含和排除。
比如,
如果我们使用,
<context:component-scan
base-package="org.chen.auto">
<context:include-filter type="assignable" expression="org.chen.auto.Instrument"/>
</context:component-scan>
表明所有实现Instrument的类会被检测并注册(相当于自己加上了@Component)。
type是过滤类型,
基于注解的过滤方式是最常用的。
下面说说自动装配。
@Autowired注解和@Inject能完成类似的工作。不同的是,@Inject是Java语言自带的,推荐用它,javax.inject是JavaEE版本的,如果你使用的是Java SE版本,需要手动添加到build path,如果你使用的是Maven,可添加下面的依赖:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Inject可以用来自动装配熟悉、方法和构造器。
由于@Inject是按类型装配的,所以如果容器里有多个类型满足,则会报错。我们这时可以使用@Named来限定(默认使用Bean的ID)。
@Component
public class TestBean {
@Inject
@Named("pianeo")
private Instrument instrument;
public void say(){
System.out.println("test bean is saying ...");
instrument.play();
}
}
文章的最后,给出自定义注解的方法,
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
如果要写出@Component,即
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface MyAnnotation {}
其中,@Target是目标,表示该注解能用在何处。包括:
- ElementType.TYPE (class, interface, enum)
- ElementType.FIELD (instance variable)
- ElementType.METHOD
- ElementType.PARAMETER
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
- ElementType.ANNOTATION_TYPE (on another annotation)
- ElementType.PACKAGE (remember package-info.java)
@Retention表示你将保持这个注解多久,
这是来自Oracle的文档的截图。有源码,.Class文件,运行时三种。