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.
	 * <p>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}.
	 * <p>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.
	 * <p>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集合进行过滤。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐