文章目录

  • 一、Spring注解原理解析
  • 1. 使用xml配置扫描组件的原理解析
  • 2. 使用配置类扫描组件的原理解析


一、Spring注解原理解析

1. 使用xml配置扫描组件的原理解析

springEL解析 spring解析注解原理_springEL解析

使用@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;
	}
}

springEL解析 spring解析注解原理_java_02


springEL解析 spring解析注解原理_spring boot_03

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);
		...
	}
}

springEL解析 spring解析注解原理_spring boot_04

这里主要分析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

springEL解析 spring解析注解原理_spring boot_05