Spring-scan 扫描包路径

Spring 如何使用@ComponentScan(“包路径”) 注解

在使用Spring 注解方式开发的开始时候都会创建一个AnnotationConfigApplicationContext 对象,Xml方式开发则会创建一个ClassPathXmlApplicationContext对象,今天讲解的是注解方式的扫描包路径

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

在AnnotationConfigApplicationContext后面都会添加一个配置类
例如:上面的AppConfig.class
在配置类中都会看到一个@ComponentScan(“指定路径”)注解 ,Spring是如何通过该注解进行扫描指定路径?接下来一一解析

AnnotationConfigApplicationContext 构造方法中有三个方法,其中扫描就是在refresh方法中实现的

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		// 1. 父类创建BeanFactory
		// 2. 生成AnnotatedBeanDefinitionReader
		// 3. 生成ClassPathBeanDefinitionScanner
		this();

		// 利用reader把componentClasses注册为一个BeanDefinition
		register(componentClasses);

		// 调用AbstractApplicationContext的refresh()方法,模板模式,会启动ApplicationContext
		// 为什么叫refresh,而不叫start?
		refresh();
	}

构造方法中在new AnnotatedBeanDefinitionReader 中会添加一个org.springframework.context.annotation.internalConfigurationAnnotationProcessor 这个就是 ConfigurationClassPostProcessor的别名,ConfigurationClassPostProcessor可以理解为一个插件,提前准备这个类,在refresh 方法中可以得到使用

public AnnotationConfigApplicationContext() {
		// 在执行这个构造方法之前,会先执行父类的构造方法,会初始化一个beanFactory = new DefaultListableBeanFactory()

		// 生成并注册5个BeanDefinition
		// 1.ConfigurationClassPostProcessor
		// 2.AutowiredAnnotationBeanPostProcessor
		// 3.CommonAnnotationBeanPostProcessor
		// 4.EventListenerMethodProcessor
		// 5.DefaultEventListenerFactory
		this.reader = new AnnotatedBeanDefinitionReader(this);

		// 注册默认的includeFilter
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

refresh 这个包含了Spring启动的全部流程,今天只解析扫描相关的代码,其他的代码后续更新再说
注重解释一下invokeBeanFactoryPostProcessors方法

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 刷新BeanFactory,得到一个空的BeanFactory-Default
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  // co

			// Prepare the bean factory for use in this context.
			// 准备BeanFactory
			// 1. 设置BeanFactory的类加载器、表达式解析器、类型转化注册器
			// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
			// 3. 记录ignoreDependencyInterface
			// 4. 记录ResolvableDependency
			// 5. 添加三个单例Bean
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 子类可以对BeanFactory进行进一步初始化
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  //BeanDefinitionRegistryPostProcessor ,BeanFactoryPostProcessors

				// Register bean processors that intercept bean creation.
				// 从BeanFactory找出扫描得到得BeanPostProcessor,实例化并注册到BeanFactory中
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 初始化MessageSource,如果配置了一个名字叫做“messageSource”的BeanDefinition
				// 就会把这个Bean创建出来,并赋值给ApplicationContext的messageSource属性
				// 这样ApplicationContext就可以使用国际化的功能了
				initMessageSource();

				// Initialize event multicaster for this context.
				// 设置ApplicationContext的applicationEventMulticaster
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 执行子类的onRefresh方法
				onRefresh();

				// Check for listener beans and register them.
				// 注册Listener
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 完成beanFactory的初始化(实例化非懒加载的单例bean)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 发布事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

invokeBeanFactoryPostProcessors方法中的invokeBeanFactoryPostProcessors执行bean工厂后置处理器

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		//执行bean工厂后置处理器
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		// 关于LoadTimeWeaver看这篇文章了解即可,https://www.cnblogs.com/wade-luffy/p/6073702.html
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

下面的invokeBeanFactoryPostProcessors只抽取了代码的一部分,首先会通过org.springframework.context.annotation.internalConfigurationAnnotationProcessor别名,再通过beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)找到ConfigurationClassPostProcessor,然后在invokeBeanDefinitionRegistryPostProcessors中回调ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry方法

	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
			// 首先,先执行实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

processConfigBeanDefinitions 方法准备开始扫描

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

		// 寻找配置类对应的BeanDefinition然后进行处理
		// 比如开始扫描
		processConfigBeanDefinitions(registry);
	}

后面的代码会解析ComponentScans 注解,获得路径,然后根据路径进行扫描

		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

向下跟代码会跟到一个return scanner.doScan(StringUtils.toStringArray(basePackages)); 这才是真正的扫描

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		// 这是Spring中的Assert,大家开发时也可以用
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			// 扫描包路径得到BeanDefinition,得到的BeanDefinition是空的,还没有解析类上所定义的注解信息
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				// 得到Scope的信息,并设置
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 得到beanName
				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并注册到registry中
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

findCandidateComponents(basePackage); 中addCandidateComponentsFromIndex方法中有一个支持快速扫描的机制由Spring 提供 ,在META-INF/spring.components创建一个这样的文件配置如下:
左侧为要扫描的类 右侧为相对应的注解,这样Spring 会直接扫描该文件


example.scannable.DefaultNamedComponent=org.springframework.stereotype.Component
example.scannable.NamedComponent=org.springframework.stereotype.Component
example.scannable.StubFooDao=org.springframework.stereotype.Component
example.scannable.NamedStubDao=org.springframework.stereotype.Component
example.scannable.ServiceInvocationCounter=org.springframework.stereotype.Component
example.scannable.sub.BarComponent=org.springframework.stereotype.Component

代码流程图

AnnotationConfigApplicationContext  
	-> this();
    -> this.reader = new AnnotatedBeanDefinitionReader(this)(生成并注册5BeanDefinition其中有一个ConfigurationClassPostProcessor)
	->refresh()
	->invokeBeanFactoryPostProcessors(beanFactory);
	->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
	->invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	->postProcessor.postProcessBeanDefinitionRegistry(registry);
	->ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry方法
	->processConfigBeanDefinitions(registry);
	->parser.parse(candidates);
	->parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
	->processConfigurationClass(new ConfigurationClass(metadata, beanName));
	->sourceClass = doProcessConfigurationClass(configClass, sourceClass);
	->this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
	->scanner.doScan(StringUtils.toStringArray(basePackages));
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值