文章目录
- 一、Spring注解原理解析
- 1. 使用xml配置扫描组件的原理解析
- 2. 使用配置类扫描组件的原理解析
一、Spring注解原理解析
1. 使用xml配置扫描组件的原理解析
使用@Component等注解配置完毕后,要配置组件扫描才能使注解生效
⚫ xml配置组件扫描:
<context:component-scan base-package="com.itheima"/>
配置类配置组件扫描:
@Configuration
@ComponentScan("com.itheima")
public class AppConfig {
}
使用xml方式配置组件扫描,而component-scan是一个context命名空间下的自定义标签,所以要找到对应的命名空间处理器NamespaceHandler 和 解析器,查看spring-context包下的spring.handlers文件
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
查看 ContextNamespaceHandler类的 init方法
public void init() {
this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
}
关于自定义命名空间的原理在之前章节已经分析过 文章地址
将ComponentScanBeanDefinitionParser进行了注册,对其源码进行跟踪,最终将标注的@Component的类,生成对应的BeanDefiition进行了注册
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute("base-package");
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ",; \t\n");
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 重点:扫描"base-package"包下的所有加了@Component注解的bean,生成对应的BeanDefiition注册到BeanDefiitionMap中
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
}
核心:ClassPathBeanDefinitionScanner中的doScan方法
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
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);
// 重点:扫描"base-package"包下的所有加了@Component注解的bean,生成对应的BeanDefiition注册到BeanDefiitionMap中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}
2. 使用配置类扫描组件的原理解析
使用配置类配置组件扫描,AnnotationConfigApplicationContext容器在进行创建bean时,内部注册了几个Bean后处理器,从new AnnotationConfigApplicationContext()入手查看源码
// 注解方式去加载Spring的核心配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
AnnotationConfigApplicationContext源码:
// 首先会执行AnnotationConfigApplicationContext构造方法
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 调用注解方式的BeanDefinitionReader
this.reader = new AnnotatedBeanDefinitionReader(this);
...
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
...
// 该工具类注册了各种关于注解配置的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public abstract class AnnotationConfigUtils {
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
...
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 向容器中注册ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、
// CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory后处理器
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
...
}
}
这里主要分析ConfigurationClassPostProcessor后处理器,ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor,而BeanDefinitionRegistryPostProcessor是一个bean工厂后处理器(BeanFactoryPostProcessor),可以向容器中注册BeanDefinition,所以ConfigurationClassPostProcessor 会重写postProcessBeanDefinitionRegistry方法向容器中注册BeanDefinition
经过一系列源码调用,最终也指定到了ClassPathBeanDefinitionScanner 的doScan 方法(与xml方式终点一致)
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
...
// 该方法内部最终会执行到ClassPathBeanDefinitionScanner的doScan方法
processConfigBeanDefinitions(registry);
}
}
xml方式与注解方式扫描组件执行过程殊途同归,最终都是通过ClassPathBeanDefinitionScanner 的doScan方法,扫描"base-package"包下的所有加了@Component注解的bean,生成对应的BeanDefiition注册到BeanDefiitionMap中,后续就可以进入到Spring Bean的生命周期创建对应的Bean