1. Component @Component 使用此注解会被Spring加载到IOC容器中 2. ComponentScan @ComponentScan 扫描带 @Component 注解 3 注解的派生性 @Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
/**
* Explicitly specify the name of the Spring bean definition associated with the
* {@code @Configuration} class. If left unspecified (the common case), a bean
* name will be automatically generated.
* The custom name applies only if the {@code @Configuration} class is picked
* up via component scanning or supplied directly to an
* {@link AnnotationConfigApplicationContext}. If the {@code @Configuration} class
* is registered as a traditional XML bean definition, the name/id of the bean
* element will take precedence.
* @return the explicit component name, if any (or empty String otherwise)
* @see AnnotationBeanNameGenerator
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Respositry 此三个注解以及相关注解内部实现了@Component, 因此它们具有Component的特性会被加载到Spring IOC容器中,它们对于Spring在物理存储是没有区别的,都属于IOC容器的Bean。
4. 内部原理
Spring加载@Component实现原理
首先我们看看Spring程序的入口
public class SpringAnnotationDemo {
public static void main(String[] args) {
//创建Spring Context上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
}
}
现在绝大部分的上下文都是Annotation上下文,我们观察一下AnnotationConfigApplicationContext,构造方法
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
//AnnotatedBeanDefinitionReader是一个读取注解的Bean读取器,这里将this传了进去。
this.reader = new AnnotatedBeanDefinitionReader(this);
//扫描注解真正的核心再此
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
....
}
1.构造AnnotationConfigApplicationContext对象时,同事初始化IOC容器,其实是调用父(GenericApplicationContext)构造方法。IOC容器在这里初始化
2.构造一个reader解析Bean使用的解析器。此处我们不重点关注此类。scanner继承 ClassPathScanningCandidateComponentProvider
我们重点关注此方法 ClassPathBeanDefinitionScanner()构造方法
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
//我们要使用的类过滤
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
registerDefaultFilters();是我们重点关注的方法,属于Scanner成员变量构造函数一个方法
/**
* Register the default filter for {@link Component @Component}.
* This will implicitly register all annotations that have the
* {@link Component @Component} meta-annotation including the
* {@link Repository @Repository}, {@link Service @Service}, and
* {@link Controller @Controller} stereotype annotations.
*
Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
* JSR-330's {@link javax.inject.Named} annotations, if available.
*
*/
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
上面的解释,此方法默认的过滤会留下带 @Component注解的Bean。
在进行报扫描。解析,注册Bean会根据此includeFilters集合进行过滤。