相关文章 SpringIOC源码:@Configuration配置类解析过程
@ComponentScan的使用
@ComponentScan
只会扫描有以下四种注解中某一注解的类,并管理他们把他们加载到上下文中
@Component
:基本注解,标识了一个受Spring管理的组件,实际上只会扫描@Component,只是其他3个都继承于他
@Repository:
标识持久层组件
@Service
:标识服务层(业务层)组件
@Controller
:标识表现层组件
他们可以混用,因为Spring还没有聪明到能判断我们写的代码是那一层的,但最好那一层的注解,就用那一层,因为未来有可能有别的寓意
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写(如UserService其默认id就是:userService)。也可以在注解中通过value属性值标识组件的名称
@ComponentScan的属性
//定义包路径
String[] value() default {}
String[] basePackages() default {}
//指定dean生成器,默认BeanNameGenerator
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
//处理与检测到的bean的scope范围,默认AnnotationScopeMetadataResolver
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class
//是否为检测到的组件生成代理
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
//控制符合组件检测条件的类文件 默认是包扫描下的 **/*.class
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
//是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
boolean useDefaultFilters() default true;
//扫描到的类是都开启懒加载 ,默认是不开启的
boolean lazyInit() default false
//包扫描过滤与包括设置
Filter[] includeFilters() default {}
Filter[] excludeFilters() default {}
Filter信息说明
FilterType.ANNOTATION//注解类型 默认
FilterType.ASSIGNABLE_TYPE//指定固定类
FilterType.ASPECTJ//ASPECTJ类型
FilterType.REGEX//正则表达式
FilterType.CUSTOM//自定义类型
说明excludeFilters是过滤规则,是在基础规则上的进一步排除,includeFilters是包括,他和基础规则设置冲突,
基础规则会覆盖他,所以当我要使用includeFilters时应该使用useDefaultFilters=false
禁用基础规则或者不定义
案例
@ComponentScan(
value ={"hello”},
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}
)
源码解析
@ComponentScan注解注解解析发生在配置类解析1阶段,其解析类是ComponentScanAnnotationParser
class ConfigurationClassParser {
//调用ConfigurationClassParser构造器时会实例化ComponentScanAnnotationParser对象
private final ComponentScanAnnotationParser componentScanParser;
private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//处理内部类
//处理@PropertySource注解
//处理@ComponentScan注解
//读取@ComponentScan注解信息,组装成AnnotationAttributes信息放到集合中
//至于为什么是集合,因为@ComponentScans可以一次声明多个@ComponentScan
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
//如果读取到了
if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
//循环处理
for (AnnotationAttributes componentScan : componentScans) {
//利用@ComponentScan解析器ComponentScanAnnotationParser,获取扫描到的类,并注册到Spring中
//具体详情看下面
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//检查扫描的定义集以获取任何进一步的配置类,并在需要时递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//递归调用processConfigurationClass方法
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理任何@Import注释
// 处理任何@ImportResource注释
// 处理单个@Bean方法
// 处理接口上的默认方法
}
1、读取@ComponentScan注解信息,组装成AnnotationAttributes信息放到集合中
2、循环处理AnnotationAttributes对象,利用ComponentScanAnnotationParser解析器解析他,获取扫描到的类,并注册到Spring中
3、检查扫描的定义集,循环他们,再次进行一阶段解析,防止其中还有配置类
下面再来具体了解下ComponentScanAnnotationParser是怎么解析@ComponentScan注解信息组装成的AnnotationAttributes
class ComponentScanAnnotationParser {
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//忽略代码,这里都是提取@ComponentScan注解的具体信息,然后利用ClassPathBeanDefinitionScanner装载他们
//利用注册器ClassPathBeanDefinitionScanner注册扫描到的类
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
ClassPathBeanDefinitionScanner作用就是将指定包下的类通过一定规则过滤后 将Class 信息包装成 BeanDefinition 的形式注册到IOC容器中。
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private final BeanDefinitionRegistry registry;
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
@Nullable
private String[] autowireCandidatePatterns;
/**
* 用于为bean定义生成bean名称的策略接口
*/
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
/**
* 解决bean定义范围的策略接口
*/
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册当前BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}