概述
我的源码地址:https://github.com/chenchaofan1995/spring
看@ComponentScan注解解析的源码时,一般都要明确下面几个问题?(末尾有测试代码。)
1:那个接口对@ComponentScan进行解析?
答:ComponentScanAnnotationParser类的parse接口。
2:该接口的构造函数都需要些什么参数,并这些参数都是干什么的?
答:ComponentScanAnnotationParser的构造函数需要如下参数。
a:BeanDefinitionRegistry接口:该接口是将扫描到的bean定义添加进bean定义容器中。。
b:BeanNameGenerator接口:扫描到的bean定义是需要bean名称。
c:ResourceLoader接口:该接口是资源加载器。主要获取包下的资源。
d:Environment接口:扫描到的bean定义可能需要一些配置属性,而配置属性统一存储Environment对象里。
3:parse() 接口需要哪些参数?
答:需要@ComponentScan的注解属性值和被@ComponentScan注解标记的类名。
下面看看parse()接口内部逻辑。(配置代码➕断点查看)
第一步:创建扫描包下bean的扫描器(scanner)。
第二步:从@ComponentScan的注解属性里获取属性值,并赋值给scanner扫描器。
第三步:调用scanner.doScan()接口,开始真正的扫描,描包下的bean,并返回BeanDefinition。
public class ComponentScanAnnotationParser {
/**
*该对象存储所有的环境变量
*/
private final Environment environment;
/**
* 资源加载器
*/
private final ResourceLoader resourceLoader;
/**
* bean的名称生成器
*/
private final BeanNameGenerator beanNameGenerator;
/**
* 该对象具有bean定义的注册功能
*/
private final BeanDefinitionRegistry registry;
public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
/**
*该对象存储所有的环境变量
*/
this.environment = environment;
/**
* 资源加载器
*/
this.resourceLoader = resourceLoader;
/**
* bean的名称生成器
*/
this.beanNameGenerator = beanNameGenerator;
/**
* 该对象具有bean定义的注册功能
*/
this.registry = registry;
}
/**
*
* @param componentScan @ComponentScan的所有注解属性
* @param declaringClass
* @return
*/
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
/**
* 第一步:创建扫描包下bean的扫描器(scanner)
*/
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
/**
* 第二步:从@ComponentScan的注解属性里获取属性值,并赋值给scanner扫描器
* 1:添加Bean的名称生成器
*/
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
/**
* 2:添加代理模式:基本不用,可忽略
*/
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));
}
/**
* 3:添加配置资源的正则表达式
*/
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
/**
* 4:添加包含过滤器
*/
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
/**
* 5:添加排除过滤器
*/
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
/**
* 6:是否延迟加载
*/
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
/**
* 7:添加指定扫描的包
*/
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
/**
* 8:添加指定扫描的包
*/
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
/**
* 9:添加一个默认的排除过滤器,主要用于排除程序启动的配置类。如果启动类也在扫描的包下,将会引起重复。因为扫描包的时也会将启动类扫描进来。
*/
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
/**
*第三步:调用scanner.doScan()接口,开始真正的扫描,描包下的bean,并返回BeanDefinition
*/
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
}
ClassPathBeanDefinitionScanner类的doScan()接口分析逻辑。
第一步:获取包下的所有BeanDefinition
第二步:下面的代码是对bean定义做一些额外的处理
第三步:注册BeanDefinition到IOC的指定容器里
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
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) {
/**
* 第一步:获取包下的所有BeanDefinition
*/
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
/**
* 第二步:下面的代码是对bean定义做一些额外的处理
*/
for (BeanDefinition candidate : candidates) {
/**
* Bean的作用域
*/
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
/**
* 生成Bean名称
*/
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
/**
* 如果是注解类型的BeanDefinition,需要处理一些通用的注解属性。
* 主要包括下面这些注解处理:@Lazy、@Primary、@DependsOn、@Role、@Description
*/
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到IOC的指定容器里
*/
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}
该测试代码是为了测试ComponentScanAnnotationParser的parser()方法。注意需要修改ComponentScanAnnotationParser类的访问权限为public
@ComponentScan("interfaceTest.ComponentScanParser")
public class ComponentScanParserTest {
public static void main(String[] args) {
ComponentScanParserTest componentScanParserTest = new ComponentScanParserTest();
componentScanParserTest.parse();
}
public void parse() {
/**
* 将ComponentScanParserTest声明成一个BeanDefinition
*/
AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(ComponentScanParserTest.class);
/**
* 获取@ComponentScan注解解析器
*/
ComponentScanAnnotationParser componentScanAnnotationParser = this.getComponentScanAnnotationParser();
/**
* 获取类上的注解属性值
*/
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(beanDefinition.getMetadata().getAnnotationAttributes(ComponentScan.class.getName(), false));
/**
* 根据注解属性值将包下的bean转换成BeanDifiniton
*/
Set<BeanDefinitionHolder> beanDefinitionHolders = componentScanAnnotationParser.parse(annotationAttributes, ComponentScanParserTest.class.getName());
System.out.println(beanDefinitionHolders);
}
/**
* 获取ComponentScan注解解析器
*
* @return ComponentScanAnnotationParser:ComponentScan注解解析器
*/
public ComponentScanAnnotationParser getComponentScanAnnotationParser() {
/**
* spring源码就是通过ComponentScan注解解析器解析@ComponentScan注解的。
*/
ComponentScanAnnotationParser componentScanAnnotationParser = new ComponentScanAnnotationParser(
new StandardEnvironment(),
new DefaultResourceLoader(),
new AnnotationBeanNameGenerator(),
new DefaultListableBeanFactory()
);
return componentScanAnnotationParser;
}
}
最后
以上就是重要小白菜为你收集整理的第四章:@ComponentScan注解源码的分析的全部内容,希望文章能够帮你解决第四章:@ComponentScan注解源码的分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复