Spring ComponentScan的扫描过程解析

网友投稿 270 2022-08-20


Spring ComponentScan的扫描过程解析

目录XML中的扫描过程ComponentScanBeanDefinitionParser.parse()ComponentScanBeanDefinitionParser#configureScannerClassPathBeanDefinitionScanner构造方法中会注入默认的Filter。ClassPathBeanDefinitionScanner#doScanClassPathScanningCandidateComponentProvider#scanCandidateComponentsregisterAnnotationConfigProcessors注解的扫描过程ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistryConfigurationClassPostProcessor#processConfigBeanDefinitionsConfigurationClassParser#doProcessConfigurationClassComponentScanAnnotationParser#parse总结

XML中的扫描过程

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/context https://springframework.org/schema/context/spring-context.xsd"

default-lazy-init="false">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/context https://springframework.org/schema/context/spring-context.xsd"

default-lazy-init="false">

xml中使用自定义标签context实现,最终会调用到ComponentScanBeanDefinitionParser.parse()方法进行解析。

ComponentScanBeanDefinitionParser.parse()

// org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse

public BeanDefinition parse(Element element, ParserContext parserContext) {

// 获得base-package指定的包名

String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);

basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);

// base-package中可能有多个,用逗号分隔,转换为数组

String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,

ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

// Actually scan for bean definitions and register them.

// 创建扫描器

ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);

// 开始扫描

Set beanDefinitions = scanner.doScan(basePackages);

// 注册了一些组件

// ConfigurationClassPostProcessor

// AutowiredAnnotationBeanPostProcessor

// CommonAnnotationBeanPostProcessor

// EventListenerMethodProcessor

// DefaultEventListenerFactory

registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

return null;

}

ComponentScanBeanDefinitionParser#configureScanner

创建扫描器ClassPathBeanDefinitionScanner

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {

boolean useDefaultFilters = true;

if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {

useDefaultFilters = Boolean.parseBoolean(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));

}

// Delegate bean definition registration to scanner class.

// ClassPathBeanDefinitionScanner构造方法中添加了默认的includeFilters为@Component

ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);

scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());

scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {

scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));

}

try {

parseBeanNameGenerator(element, scanner);

}

catch (Exception ex) {

parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());

}

try {

parseScope(element, scanner);

}

catch (Exception ex) {

parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());

}

parseTypeFilters(element, scanner, parserContext);

return scanner;

}

怎么知道扫描哪些注解呢?

ClassPathBeanDefinitionScanner构造方法中会注入默认的Filter。

protected void registerDefaultFilters() {

// 只扫描@Component注解了的类,而@Sevice、@Configuration、@Controller等注解都被@Component修饰

this.includeFilters.add(new AnnotationTypeFilter(Component.class));

ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

try {

this.includeFilters.add(new AnnotationTypeFilter(

((Class extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));

logger.trace("jsR-250 'javax.annotation.ManagedBean' found and supported for component scanning");

}

catch (ClassNotFoundException ex) {

// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.

}

try {

this.includeFilters.add(new AnnotationTypeFilter(

((Class extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));

logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");

}

catch (ClassNotFoundException ex) {

// JSR-330 API not available - simply skip.

}

}

在源码中只会扫描@Component注解,而@Sevice、@Configuration、@Controller等注解都被@Component修饰,最终都会被扫描到。

ClassPathBeanDefinitionScanner#doScan

开始扫描:

// org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

protected Set doScan(String... basePackages) {

Assert.notEmpty(basePackages, "At least one base package must be specified");

Set beanDefinitions = new LinkedHashSet<>();

for (String basePackage : basePackages) {

// 查找basePackage下所有被@Component注解修饰了的类

Set candidates = findCandidateComponents(basePackage);

for (BeanDefinition candidate : candidates) {

// 上面findCandidateComponents只是为BD设置了几个属性,BD的其他属性并没有初始化,所以需要遍历一次初始化属性并注册到registry

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

// 注册到registry

registerBeanDefinition(definitionHolder, this.registry);

}

}

}

return beanDefinitions;

}

ClassPathScanningCandidateComponentProvider#scanCandidateComponents

查找basePackage下所有被@Component注解修饰了的类:

// org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents

private Set scanCandidateComponents(String basePackage) {

Set candidates = new LinkedHashSet<>();

try {

// basePackage=com.morris.spring..service

// packageSearchPath=classpath*:com/morris/spring/service/**/*.class

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +

resolveBasePackage(basePackage) + '/' + this.resourcePattern;

// 获取basePackage下所有的class文件

Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

boolean traceEnabled = logger.isTraceEnabled();

boolean debugEnabled = logger.isDebugEnabled();

for (Resource resource : resources) {

if (traceEnabled) {

logger.trace("Scanning " + resource);

}

if (resource.isReadable()) {

try {

// 使用ASM将class文件的内容封装为MetadataReader对象

// 注意这里用的不是反射,反射会加载类,占用堆空间

MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

// 判断类是否包含@Component注解

if (isCandidateComponent(metadataReader)) {

// 封装为BD

ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

sbd.setSource(resource);

if (isCandidateComponent(sbd)) {

if (debugEnabled) {

logger.debug("Identified candidate component class: " + resource);

}

candidates.add(sbd);

}

... ...

return candidates;http://

}

registerAnnotationConfigProcessors

注册了多种重要的组件:

public static Set registerAnnotationConfigProcessors(

BeanDefinitionRegistry registry, @Nullable Object source) {

DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);

if (beanFactory != null) {

if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {

beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);

}

if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {

beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());

}

}

Set beanDefs = new LinkedHashSet<>(8);

// BeanFactoryPostProcessor

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// BeanPostProcessor

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.

if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.

if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition();

try {

def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,

AnnotationConfigUtils.class.getClassLoader()));

}

catch (ClassNotFoundException ex) {

throw new IllegalStateException(

"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);

}

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// BeanFactoryPostProcessor

if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));

}

if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));

}

return beanDefs;

}

扫描的最终结果就是将类上面有@Component注解的类构建为一个BeanDefinition中,Spring容器中有两个集合来存放这些BeanDefinition:

beanDefinitionNames:List,存放所有的BeanDefinition对应的namebeanDefinitionMap:Map,存放所有的BeanDefinition

注解的扫描过程

注解扫描的使用:

package com.morris.spring.demo.annotation;

import com.morris.spring.demo.service.CityService;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.morris.spring.service")

public class ComponentScanDemo {

public static void main(String[] args) {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanDemo.class);

CityService cityService = applicationContext.getBean(CityService.class);

cityService.city();

}

}

使用@ComponentScan注解指定包的扫描,扫描过程将由ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry完成。

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {

int registryId = System.identityHashCode(registry);

if (this.registriesPostProcessed.contains(registryId)) {

throw new IllegalStateException(

"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);

}

if (this.factoriesPostProcessed.contains(registryId)) {

throw new IllegalStateException(

"postProcessBeanFactory already called on this post-processor against " + registry);

}

this.registriesPostProcessed.add(registryId);

// 重点

processConfigBeanDefinitions(registry);

}

ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

List configCandidates = new ArrayList<>();

String[] candidateNames = registry.getBeanDefinitionNames();

// 先收集有@Configuration、@Component、@ComponentScan、@Import、@ImportResource、@Bean的BD

for (String beanName : candidateNames) {

BeanDefinition beanDef = registry.getBeanDefinition(beanName);

if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {

if (logger.isDebugEnabled()) {

logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);

}

}

else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

// 进来需要@Component、@ComponentScan、@Import、@ImportResource、@Bean

configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

}

}

... ...

// Parse each @Configuration class

ConfigurationClassParser parser = new ConfigurationClassParser(

this.metadataReaderFactory, this.problemReporter, this.environment,

this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set candidates = new LinkedHashSet<>(configCandidates);

Set alreadyParsed = new HashSet<>(configCandidates.size());

do {

// 开始解析

parser.parse(candidates);

parser.validate();

ConfigurationClassParser#doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(

ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)

throws IOException {

... ...

// Process any @ComponentScan annotations

// 处理@ComponentScan注解,扫描包下带有@Component的注解,与xml中自定义标签context:component-scan的扫描流程一致

Set componentScans = AnnotationConfigUtils.attributesForRepeatable(

sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

if (!componentScans.isEmpty() &&

!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {

for (AnnotationAttributes componentScan : componentScans) {

// The config class is annotated with @ComponentScan -> perform the scan immediately

Set scannedBeanDefinitions =

this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

// Check the set of scanned definitions for any further config classes and parse recursively if needed

for (BeanDefinitionHolder holder : scannedBeanDefinitions) {

BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();

if (bdCand == null) {

bdCand = holder.getBeanDefinition();

}

// checkConfigurationClassCandidate这个里面会特殊处理@Configutation为full

if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {

parse(bdCand.getBeanClassName(), holder.getBeanName());

}

}

}

}

... ...

return null;

}

ComponentScanAnnotationParser#parse

public Set parse(AnnotationAttributes componentScan, final String declaringClass) {

// 解析@ComponentScan注解,构建ClassPathBeanDefinitionScanner

// 构建方法中会添加默认的includeFilters为@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);

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

}

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

}

可以发现注解的扫描最后会调用ClassPathBeanDefinitionScanner#doScan(),与XML中的扫描是同一个方法。

总结

XML的扫描过程发生在obtainFreshBeanFactory(),也就是创建BeanFactory时,而注解的扫描过程发生在invokeBeanFactoryPostProcessors()。XML的扫描会在obtainFreshBeanFactory()时注入ConfigurationClassPostProcessor,而注解的扫描是在创建AnnotationConfigApplicationContext实例时注入ConfigurationClassPostProcessor,如果xml扫描到的类带有@ComponentScan注解,那么还会继续在invokeBeanFactoryPostProcessors()阶段继续扫描。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringCloud Gateway读取Request Body方式
下一篇:使用SpringMVC访问Controller接口返回400BadRequest
相关文章