@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.
	 * <p>The default is defer to the default behavior of the component scanner used to
	 * execute the actual scan.
	 * <p>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.
	 * <p>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));
	}

图1
useDefaultFilters属性默认情况下是true,其实就是匹配@Component注解标注的类。

@ComponentScan.Filter 解释

@ComponentScan.Filterclasses()实现aware的几个增强接口是由BeanDefinitionRegistryPostProcessor的实现类ConfigurationClassPostProcessor处理的。
在这里插入图片描述
自定义的TypeFilter可以实现几个aware接口,BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware。
在这里插入图片描述

最终执行扫描的方法如下:
在这里插入图片描述
上图中findCandidateComponents(basePackage)方法过滤条件的执行,代码如下:
在这里插入图片描述
因此自定义类型过滤器只需要实现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被忽略了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值