@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));
}
useDefaultFilters属性默认情况下是true,其实就是匹配@Component注解标注的类。
@ComponentScan.Filter 解释
@ComponentScan.Filter
的classes()
实现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被忽略了