『SpringBoot 源码分析』run() 方法执行流程:(3)刷新应用上下文-处理 @ComponentScan 注解

『SpringBoot 源码分析』run() 方法执行流程:(3)刷新应用上下文-处理 @ComponentScan 注解

  • 基于 2.2.9.RELEASE
  • 问题:当方法进行了注释标记之后,springboot 又是怎么注入到容器中并创建类呢?
  1. 首先创建测试主程序
java 复制代码
package com.lagou;

@SpringBootApplication//标注在类上说明这个类是`SpringBoot`的主配置类
public class SpringBootMytestApplication{

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMytestApplication.class, args);
	}
}
  1. 创建测试 Controller
java 复制代码
package com.lagou.controller;

@RestController
public class TestController {

	@RequestMapping("/test")
	public String test(){
		System.out.println("源码环境构建成功...");
		return "源码环境构建成功";
	}
}

处理 @ComponentScan 注解

  1. 准备好上下文以及上下文环境之后,可以继续来看看 springboot 究竟是如何把主类所在的类路径下相关的类通过 @ComponentScan 注册到 IOC 容器中。首先先走到 refreshContext() 方法,然后调用 ApplicationContextrefresh()
java 复制代码
public class SpringApplication {
	...
	public ConfigurableApplicationContext run(String... args) {
		...
		try {
			// 将运行时参数封装
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 构造应用上下文环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 处理需要忽略的 Bean
			configureIgnoreBeanInfo(environment);
			// 打印 banner
			Banner printedBanner = printBanner(environment);
			// 刷新应用上下文前的准备阶段
			context = createApplicationContext();
			// 实例化 SpringBootExceptionReporter.class,用来支持报告关于启动的错误
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 刷新应用上下文前的准备阶段
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 1. 刷新应用上下文
			refreshContext(context);
			...
		}
		catch (Throwable ex) {
			...
		}
		...
	}

	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		// 2. spring 的核心方法,刷新上下文
		((AbstractApplicationContext) applicationContext).refresh();
	}
}
  1. 接着 ApplicationContext 调用父类的 refresh()
java 复制代码
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
	...
	@Override
	public final void refresh() throws BeansException, IllegalStateException {
		try {
			// 1. 调用父类 refresh() 方法
			super.refresh();
		}
		catch (RuntimeException ex) {
			stopAndReleaseWebServer();
			throw ex;
		}
	}
}
  1. refresh() 中,首先对上下文进行预处理,设置一些必要的参数,然后获取 IOC 容器,并对 IOC 容器进行一些参数进行设置,然后调用工厂处理器注册相关的 bean 进入上下文
java 复制代码
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
		
	private final Object startupShutdownMonitor = new Object();
	...
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1. 上下文设置一些必要的参数
			prepareRefresh();

			// 2. 获取 IOC 容器
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 3. 对 IOC 容器进行一些参数设置
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// 4. 调用工厂处理器,注册 bean 到 IOC 容器
				invokeBeanFactoryPostProcessors(beanFactory);
				...
			} catch (BeansException ex) {
				...
			}
			...
		}
	}
	
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		// 5. 对 IOC 容器调用 beanFactoryPostProcessors 来处理  		
		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)
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}
}
  1. 通过后置处理器注册的委派类 PostProcessorRegistrationDelegate 调用 invokeBeanFactoryPostProcessors() 的逻辑相对复杂一些,我们直接跳过,只关注问题本身,走到下面的一句话
java 复制代码
final class PostProcessorRegistrationDelegate {
	...
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
		
		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();
		
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			// 1. 调用 bean 注册处理器,处理类的注册			
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			...
		}
		...
	}

	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			// 2. 其中 postProcessors 只有一个类,即为	ConfigurationClassPostProcessor 		
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}
}
  • 其中,配置类最关键的对象是 ConfigurationClassPostProcessor 后置处理器
  1. 这时候就会交由 ConfigurationClassPostProcessor 来注册 bean 到 IOC 容器中
java 复制代码
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	
	private final Set<Integer> registriesPostProcessed = new HashSet<>();
	...
	@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);
		// 1. 注册 bean 到 IOC 容器中
		processConfigBeanDefinitions(registry);
	}
}
  1. 当调用 processConfigBeanDefinitions() 时,首先会创建 ConfigurationClassParser 用于解析 @Configuration
java 复制代码
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	
	private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
	private ProblemReporter problemReporter = new FailFastProblemReporter();
	@Nullable
	private Environment environment;
	private ResourceLoader resourceLoader = new DefaultResourceLoader();
	private BeanNameGenerator componentScanBeanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
	...
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		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);
				}
			}
			// 把主类封装进 BeanDefinitionHolder 中
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

		// Sort by previously determined @Order value, if applicable
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 1. 创建解析器,用于解析 @Configuration 标注的类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
		
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		
		do {
			// 2. 开始解析候选类
			parser.parse(candidates);
			...
		}
		while (!candidates.isEmpty());
		...
	}
}
  • 其中,这里的 candidates 属性也就只有主类
  1. 接下来会遍历 candidates 属性,解析主类的注解
java 复制代码
class ConfigurationClassParser {

	private static final Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
			(className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."));
	...
	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					// 1. 解析主类配置,其中 getBeanName() 为 SpringBootMytestApplication
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}

		this.deferredImportSelectorHandler.process();
	}

	protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
		processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
	}
}
  1. 再走进一层嵌套中,遇到 do 开头的方法,才是真正处理的时候
java 复制代码
class ConfigurationClassParser {
	...
	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			// 1. 真正处理 @Configuration 的方法,其中 sourceClass 为 com.lagou.SpringBootMytestApplication
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}
}
  1. 接下来会根据不同的注解,执行不同的处理方法,这里主要关注处理 @ComponentScan 注解的位置,首先会判断 sourceClass 是否标注了 @ComponentScan 注解,主类 @SpringBootApplication 是肯定包含这个注解。然后通过 ComponentScanAnnotationParser 来进行解析
java 复制代码
class ConfigurationClassParser {

	private final ComponentScanAnnotationParser componentScanParser;
	private final ConditionEvaluator conditionEvaluator;
	private final Environment environment;
	...
	@Nullable
	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
			
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

		// Process any @PropertySource annotations
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 1. 扫描主类 @ComponentScan 注解里面的配置属性
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// 2. 解析 @ComponentScan 的注解的属性,然后把扫描到的相关类转化为 BeanDefinition
				Set<BeanDefinitionHolder> 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();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		...
	}
}
  1. parse() 主体逻辑就是首先创建 ClassPathBeanDefinitionScanner 扫描器,然后判断主类的 @ComponentScan 注解是否标注了 basePackages 属性,没有的话就把主类所在的包放进去,然后扫描所有的 @Component 类,封装成 BeanDefinition
  • 重点:所以这里就是为什么主类所在的包,以及其子包的类都能扫出来
java 复制代码
class ComponentScanAnnotationParser {
	
	private final BeanNameGenerator beanNameGenerator;
	private final ResourceLoader resourceLoader;
	private final Environment environment;
	private final BeanDefinitionRegistry registry;
	...
	// declaringClass 为 com.lagou.SpringBootMytestApplication
	public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
		// 1. 创建 BeanDefinition 扫描器
		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<String> basePackages = new LinkedHashSet<>();
		// 2. 尝试查看注解有没添加 basePackages 属性
		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()) {
			// 3. 没有就获取类所在的包名,这里是 com.lagou			
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		// 4. 扫描对应的包,把所有相关的 @Component 的类封装成 BeanDefinition 返回
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}
}
  • 其中,componentScan 包含的相关属性如下
  1. doScan() 先通过 basePackages 属性,找到所有候选 Components,然后把它们注册到 IOC 容器中并返回
java 复制代码
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
	
	private final BeanDefinitionRegistry registry;
	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
	...
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		// 1. basePackages 为 com.lagou
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			// 2. 根据 basePackage 找到所有候选的 Components
			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);
					// 3. 将候选 Components 注册进 IOC 容器
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		// 4. 返回 beanDefinitions
		return beanDefinitions;
	}
}
  • 其中,findCandidateComponents() 会调用嵌套方法 scanCandidateComponents() 。它会把 basePackage 属性拼接起来,形成 classpath*:com/lagou/**/*.class 路径,扫描所有的类,并返回
java 复制代码
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
	
	static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
	private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
	...

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 1. 拼接的路径为 classpath*:com/lagou/**/*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 2. 得到已经扫描出来的源
			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 {
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						// 先判断 resource 是不是候选的 component
						if (isCandidateComponent(metadataReader)) {
							//  封装成通用 BeanDefinition
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		// 3. 返回所有扫描出来的候选 components
		return candidates;
}
  • (续)
    • 扫描出来的 resources 属性如下
  • (续)
    • 最后的候选 components 属性(只有 com.lagou.config.MyDataSourceConfigcom.lagou.controller.TestController )如下
  • 其中,registerBeanDefinition() 会调用 BeanDefinitionReaderUtils 来注册扫描出来的类
java 复制代码
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
	...
	protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
		// 1. 注册扫描出来的类。这里先注册 com.lagou.config.MyDataSourceConfig,后注册 com.lagou.controller.TestController
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
	}
}
  • (续)
    • BeanDefinitionReaderUtils 又会通过 BeanDefinitionRegistry (其实就是我们一开始创建的上下文转换强转过来的)调用 registerBeanDefinition() 方法进行注册
java 复制代码
public abstract class BeanDefinitionReaderUtils {
	...
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		// 1. 通过 BeanDefinitionRegistry 注册扫描出来的类,这里是先注册 com.lagou.config.MyDataSourceConfig,后注册 com.lagou.controller.TestController
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
}
  • (续)
    • 最后会把这些扫描出来的类,放到 beanDefinitionMap 属性中
java 复制代码
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	
	/** List of bean definition names, in registration order. */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
	...
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					// 1. 把对应的 beanDefinition 注册到 beanDefinitionMap 中
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}
}
  1. 返回完 ComponentScans 注解扫描的类之后,会判断候选类是不是有 @Configuration 标记,有的话,会继续深度调用 processConfigurationClass() ,继续扫描所有候选类,注册进 beanDefinitionMap
java 复制代码
class ConfigurationClassParser {

	private final ComponentScanAnnotationParser componentScanParser;
	private final ConditionEvaluator conditionEvaluator;
	private final Environment environment;
	...
	@Nullable
	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
			
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

		// Process any @PropertySource annotations
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 扫描处理所有 @ComponentScan 注解
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// 解析 @ComponentScan 的注解,然后把相关对象
				Set<BeanDefinitionHolder> 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();
					}
					// 1. 判断扫描的类是不是用  @Configuration 标记
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						// 2. 是的话继续解析该配置类 
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		...
	}

	protected final void parse(@Nullable String className, String beanName) throws IOException {
		Assert.notNull(className, "No bean class name for configuration class bean definition");
		MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
		// 3. 形成递归调用解析
		processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
	}
}
  1. 直到这里我们就能够明白如何把主类所在的类路径下相关的类通过 @ComponentScan 注册到 IOC 容器中,像相关的 @Import@ImportResource 注册,也是在 processConfigurationClass() 这个方法里解析,下节再解析
  2. 总结
相关推荐
救救孩子把10 分钟前
深入理解 Java 对象的内存布局
java
落落落sss12 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节18 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭25 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
我行我素,向往自由31 分钟前
速成java记录(上)
java·速成
一直学习永不止步37 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
邵泽明37 分钟前
面试知识储备-多线程
java·面试·职场和发展
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript