@ComponentScan注解分析

@ComponentScan注解分析

  • @ComponentScan注解
  • @ComponentScan解析
    • 例子

@ComponentScan注解

SpringBean容器的作用就是管理我们创建的对象(Bean),方式就是在类上加@Component注解(不止一种),并且需要一个包扫描工具去读取这些配置了注解的类,因此需要添加@ComponentScan注解完成扫描工作。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

	/**
	 * 指定需要扫描的包
	 */
	@AliasFor("basePackages")
	String[] value() default {};

	@AliasFor("value")
	String[] basePackages() default {};
	
	/**
	* 指定具体扫描的类
	*/
	Class<?>[] basePackageClasses() default {};

	/**
	 * 扫描出来的bean的名字生成器,通过实现BeanNameGenerator接口自定义生成器,默认是AnnotationBeanNameGenerator
	 */
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	/**
	 * The {@link ScopeMetadataResolver} to be used for resolving the scope of detected components.
	 */
	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

	/**
	 * Indicates whether proxies should be generated for detected components, which may be
	 * necessary when using scopes in a proxy-style fashion.
	 * 

The default is defer to the default behavior of the component scanner used to * execute the actual scan. *

Note that setting this attribute overrides any value set for {@link #scopeResolver}. * @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode) */ ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; /** * Controls the class files eligible for component detection. *

Consider use of {@link #includeFilters} and {@link #excludeFilters} * for a more flexible approach. */ String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN; /** * 默认过滤器可以扫描@Component、@Repository、@Service、@Controller注解 */ boolean useDefaultFilters() default true; /** * 匹配过滤器 */ Filter[] includeFilters() default {}; /** * 排除过滤器 */ Filter[] excludeFilters() default {}; /** * 是否懒加载模式 */ boolean lazyInit() default false; @Retention(RetentionPolicy.RUNTIME) @Target({}) @interface Filter { /** * The type of filter to use. */ FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class<?>[] value() default {}; /** * The class or classes to use as the filter. * 自定义的TypeFilter可以实现几个aware接口,BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware。 */ @AliasFor("value") Class<?>[] classes() default {}; /** * 如果type设置为FilterType.ASPECTJ或者FilterType.REGEX,此参数需要设置 */ String[] pattern() default {}; } }

public enum FilterType {

	/**
	 * Filter candidates marked with a given annotation.
	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
	 */
	ANNOTATION,

	/**
	 * Filter candidates assignable to a given type.
	 * @see org.springframework.core.type.filter.AssignableTypeFilter
	 */
	ASSIGNABLE_TYPE,

	/**
	 * Filter candidates matching a given AspectJ type pattern expression.
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * Filter candidates matching a given regex pattern.
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 */
	REGEX,

	/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM

}

@ComponentScan解析

注解的解析处理方法:ComponentScanAnnotationParser#parse(AnnotationAttributes componentScan, final String declaringClass);

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
		Assert.state(this.environment != null, "Environment must not be null");
		Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");
		
		//解析器首先就是找@ComponentScan的useDefaultFilters属性,如果为true则只加载@Component注解标注的类
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
		//获取注解的各个属性
		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
		//设置Bean名称生成器
		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
				BeanUtils.instantiateClass(generatorClass));

		ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
		if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
			scanner.setScopedProxyMode(scopedProxyMode);
		}
		else {
			Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
			scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
		}

		scanner.setResourcePattern(componentScan.getString("resourcePattern"));
		
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
			//类型过滤器的添加
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addIncludeFilter(typeFilter);
			}
		}
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addExcludeFilter(typeFilter);
			}
		}

		boolean lazyInit = componentScan.getBoolean("lazyInit");
		if (lazyInit) {
			scanner.getBeanDefinitionDefaults().setLazyInit(true);
		}

		Set<String> basePackages = new LinkedHashSet<String>();
		String[] basePackagesArray = componentScan.getStringArray("basePackages");
		for (String pkg : basePackagesArray) {
			String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
			basePackages.addAll(Arrays.asList(tokenized));
		}
		for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}

@ComponentScan注解分析_第1张图片
useDefaultFilters属性默认情况下是true,其实就是匹配@Component注解标注的类。

@ComponentScan.Filter 解释

@ComponentScan.Filterclasses()实现aware的几个增强接口是由BeanDefinitionRegistryPostProcessor的实现类ConfigurationClassPostProcessor处理的。
@ComponentScan注解分析_第2张图片
自定义的TypeFilter可以实现几个aware接口,BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware。
@ComponentScan注解分析_第3张图片

最终执行扫描的方法如下:
@ComponentScan注解分析_第4张图片
上图中findCandidateComponents(basePackage)方法过滤条件的执行,代码如下:
@ComponentScan注解分析_第5张图片
因此自定义类型过滤器只需要实现TypeFilter接口即可,并且还可以实现上述BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware这几个增强接口。

例子

三个mvc常用的注解,都是@Component

@Controller
public class ControllerTest {}
@Repository
public class DaoTest {}
@Service
public class ServiceTest {}
@Configuration
@ComponentScan(value = "xiangxue.spring.mvc", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, value = {TypeFilterUsage.class})                    //自定义扫描规则
}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),     //指定注解类型
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {ControllerTest.class})},           //指定扫描的类
        useDefaultFilters = false,nameGenerator = BeanNameGeneratorUsage.class)        //默认情况下扫描@Component注解
public class ComponentScanUsage {
    public static void main(String[] args) {
        ApplicationContext app = new AnnotationConfigApplicationContext(ComponentScanUsage.class);
    }
}
/**
 * 自定义扫描规则,需要实现TypeFilter接口
 * 允许实现的几个接口:
 * BeanClassLoaderAware, BeanFactoryAware,EnvironmentAware, ResourceLoaderAware
 */
public class TypeFilterUsage implements TypeFilter, BeanClassLoaderAware, BeanFactoryAware,EnvironmentAware, ResourceLoaderAware {

    /**
     * Determine whether this filter matches for the class described by
     * the given metadata.
     * @param metadataReader the metadata reader for the target class
     * @param metadataReaderFactory a factory for obtaining metadata readers
     * for other classes (such as superclasses and interfaces)
     * @return whether this filter matches
     * @throws IOException in case of I/O failure when reading metadata
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        System.out.println("----->"+className);
        //当类包含Test字符, 则匹配成功,返回true
        if(className.contains("Test")){
            return true;
        }
        return false;
    }

    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("setEnvironment");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory");
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("setResourceLoader");
    }
}
public class BeanNameGeneratorUsage implements BeanNameGenerator {

    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    	//将类名以DaoTest结尾的类BeanName设为customDaoTest
        if (definition.getBeanClassName().endsWith("DaoTest")) {
            return "customDaoTest";
        }
        return definition.getBeanClassName();
    }
}

最终获取的BeanDefinitionNames:

componentScanUsage
customDaoTest
xiangxue.spring.mvc.ServiceTest

ControllerTest被忽略了

你可能感兴趣的:(Spring)