Springboot源码分析第一弹 - 自动装配实现

Springboot就不用多了吧,解放Java开发双手的神器。
最显著的特点就是,去配置化,自动装配,自动配置。让开发人员只需要注重业务的开发
今天就来了解一下自动装配的源码是怎么实现的

预先准备

  • 直接引用springboot包2.5.6的
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
</parent>
  • 再贴一下以前的MVC扫描包的web.xml配置
<!-- 一般applicationContext里面会有扫描包路径配置 -->
<context:component-scan base-package="com.demo.xxx"></context:component-scan>

以前是有入口指定扫描路径,但是springboot又没有这个配置,确也能扫描出来是怎么实现的,来一探究竟吧!

流程概括

  1. 入口肯定是run方法,参数传入的是当前的启动类
  2. 在容器初始化之前传入的启动类注册到容器中去,然后再刷新容器refresh()
  3. 在容器注册阶段完成后,就是将所有的需要加载类注册到BeanDefinitionMap了
  4. 然后在上下文中调用注册bean的处理器回调,在springboot包中解析bean
  5. 关注点在注册类,解析该类时得到扫描路径即当前路径 ‘.’ ,也就说明了springboot项目默认扫描到启动类那一层,扫描我们手写的代码后注册到容器,但是所需依赖还是没有想容器注册的
  6. 启动类上有@Import注解,解析时会一并处理,然后获取import的类的回调来获取需要自动装配的类
  7. 在回调类中解析需要自动装载的类,通过读取包内文件目录下META-INF/spring.factories的配置中获取对应key的值
  8. 最终想容器注册,自动装配流程到此完结

源码分析

上面流程中可以分为三步,一步一步分析。

1.向容器注册启动类

  • 入口就是run()方法,直接到源码中去
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args){
	//primarySource 启动类
	return run(new Class<?>[] { primarySource }, args);
}
  • 接下来run一直往下到SpringApplication#run()
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;
	configureHeadlessProperty();
	//获取需要注册的监听
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting(bootstrapContext, this.mainApplicationClass);
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		//环境和配置 后面会讲到
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		configureIgnoreBeanInfo(environment);
		//打印启动banner
		Banner printedBanner = printBanner(environment);
		//创建web容器
		context = createApplicationContext();
		//设置web容器的启动类 DefaultApplicationStartup
		context.setApplicationStartup(this.applicationStartup);
		//为容器初始化之前做一些准备 ### 我们主要先看这里
		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
		//初始容器
		refreshContext(context);
		//初始化完成
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		//容器创建完成的通知
		listeners.started(context);
		//回调callRuners 即实现了CommandLineRunner接口的回调
		callRunners(context, applicationArguments);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		//容器已启动的通知
		listeners.running(context);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
  • 先看容器加载前的处理
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
	SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
   	//容器的一些设置
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
   	//向容器注册一些单列bean
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
   	//这块是重点 getAllSources()里返回的是run方法里面传入的xxx.class,其实就是启动类
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
   	//从上面得知这里传入的sources其实就是启动类 接下来看这里是怎么加载的 ###
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}
  • 这里拿到的是启动类,那么load的就是class,一直往下到BeanDefinitionLoader#load(Class<?> source)
private void load(Class<?> source) {
	if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
		// Any GroovyLoaders added in beans{} DSL can contribute beans here
		GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
		((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
	}
	//return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
	//不是空的类 不是Groovy闭包 也不是匿名类 就直接向容器注册
	if (isEligible(source)) {
		//也就是说先将
		this.annotatedReader.register(source);
	}
}

//this.annotatedReader.register(source)接下来 会注册到IOC容器中去
AnnotatedBeanDefinitionReader
-> registerBean(componentClass)
-> doRegisterBean
-> BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

到这里第一个点就完成,本意就是把启动类注册到容器中去,然后在上下文中回调中用大到该类完成扫描业务代码,因为没有地方配置让spring扫描哪些包名下的类,类似完成web.xml中的component-scan配置

2.向容器注册业务类

  • 接下来回到最开始的SpringApplication#run,找到以下代码
//容器刷新前
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//重点看这个 刷新容器  ###
refreshContext(context);
//一直往下 接下来到这里
protected void refresh(ApplicationContext applicationContext) {
	Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
	((AbstractApplicationContext) applicationContext).refresh();
}
//接下来又到 AbstractApplicationContext.refresh() IOC名场面了
//多的就不说了 直接看这个
// Invoke factory processors registered as beans in the context.
// 在上下文中调用注册为bean的工厂处理器 就是回调
invokeBeanFactoryPostProcessors(beanFactory);

//往下到这里
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  • 接下来到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(),只贴关键代码
public static void invokeBeanFactoryPostProcessors(
	ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {
		 //省略部分代码
           ......
		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        //调用实现类   
        //这里还要注意一下 断点调试spring包实现了这个类的只有一个 					
        //就是ConfigurationClassPostProcessor  
		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);
        //针对于注册的bean进行回调 接下来看这里  ###
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		
	//省略部分代码
	......
}

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

	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
				.tag("postProcessor", postProcessor::toString);
		//开始对实现了BeanDefinitionRegistryPostProcessor接口的bean进行回调		
		postProcessor.postProcessBeanDefinitionRegistry(registry);
		postProcessBeanDefRegistry.end();
	}
}
  • 经过断点调试,会到spring-context-5.3.12.jar包下的ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
  • 需要注意的一个点,前面已经说到手动注册了启动类,那么candidateNames里面肯定会有启动类。其他的类我们忽略,主要看启动类的扫描和加载
//一直往下到这里
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);
			}
		}
        //判断是否加了 @Configuration 这个注解
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            //满足就加到list中 这里的启动类肯定是加了这个注解的 可以自己进行验证
			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<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
        //开始解析带有@Configuration注解的类 ###先看这个
		parser.parse(candidates);
		parser.validate();
		//得到解析出来需要加载的类
		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);

		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		//把需要加载的类注册到容器中去
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

	//省略部分代码
        ......
}
  • 先看下parser.parse(candidates);做了什么,到ConfigurationClassParser#parse()
ublic void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
               //启动类注解了@Configuration 属于注解annotation definition
			if (bd instanceof AnnotatedBeanDefinition) {
                //接下来走这里 ##
				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);
		}
	}
	//分析完parse后 在来分析这个process
	this.deferredImportSelectorHandler.process();
}
  • 一直往下到真正干活的类,ConfigurationClassParser#doProcessConfigurationClass 解析核心类
protected final SourceClass doProcessConfigurationClass(
	ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
	throws IOException {
	//解析 @Component 注解
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		processMemberClasses(configClass, sourceClass, filter);
	}

	//@PropertySource注解
	// 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注解 扫描对应的包路径
	//@SpringBootApplication上面有该注解,也可以自己指定
	// Process any @ComponentScan annotations
	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) {
			// The config class is annotated with @ComponentScan -> perform the scan immediately
			//查找ComponentScan注解是否有使用value
			//接下来先看看怎么扫描的 ####
			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());
				}
			}
		}
	}
	//@Import注解 先分析完扫描 下一步再重点看这里 ###
	// Process any @Import annotations
	processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
	//@ImportResource 注解
	// Process any @ImportResource annotations
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		String[] resources = importResource.getStringArray("locations");
		Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}
	//@Bean 注解的方法
	// Process individual @Bean methods
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// Process default methods on interfaces
	processInterfaces(configClass, sourceClass);

	// Process superclass, if any
	if (sourceClass.getMetadata().hasSuperClass()) {
		String superclass = sourceClass.getMetadata().getSuperClassName();
		if (superclass != null && !superclass.startsWith("java") &&
				!this.knownSuperclasses.containsKey(superclass)) {
			this.knownSuperclasses.put(superclass, configClass);
			// Superclass found, return its annotation metadata and recurse
			return sourceClass.getSuperClass();
		}
	}

	// No superclass -> processing is complete
	return null;
}
  • @ComponentScan 指定扫描包路径,ConfigurationClassParser#doProcessConfigurationClass
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
-> ComponentScanAnnotationParser.parse

//到这个方法
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	//省略部分代码
	......

	Set<String> 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()) {
		//接下来看这里
		//public static String getPackageName(String fqClassName) {
           //Assert.notNull(fqClassName, "Class name must not be null");
           //int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
           //return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
           //}
		// 然后发现了 private static final char PACKAGE_SEPARATOR = '.';
		//那么拿到的就是启动类的包名路径,这也验证了springboot 项目默认扫描到启动类那一层
		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()
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	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) {
				//回调 因为此时容器已经处理回调这一步 所以新注册的bean需要自己回调
				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);
				//向容器注册 这里就不多说了
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}
  • 接下来到ClassPathScanningCandidateComponentProvider#findCandidateComponents -> scanCandidateComponents
//这不就是混熟悉的读流了
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		//resourcePattern = **/*.class class后缀
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		//读流		
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			try {
				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
				//满足注解的 @Component  其实所有需要加载的注解 都实现了@Component
				if (isCandidateComponent(metadataReader)) {
					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
					sbd.setSource(resource);
					if (isCandidateComponent(sbd)) {
						if (debugEnabled) {
							logger.debug("Identified candidate component class: " + resource);
						}
						//把对应路径下的class文件扫描到list中 然后向容器中注册
						candidates.add(sbd);
					}
					.... //省略部分代码
	return candidates;
}

到这里为止,已经把我们自己写的业务代码注册到容器中了,但是springboot框架需要依赖的bean还是没有注册的,接下来看下自动装配怎么实现的吧

3.向容器注册所需依赖的自动装配的类

  • 我们回到ConfigurationClassParser.doProcessConfigurationClass方法中
//找到这行对 @import注解的解析
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

//接下来到processImports这个方法里面  找到这一部分 只有加了@Import注解的才会进来
for (SourceClass candidate : importCandidates) {
	if (candidate.isAssignable(ImportSelector.class)) {
		// Candidate class is an ImportSelector -> delegate to it to determine imports
		Class<?> candidateClass = candidate.loadClass();
		ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
				this.environment, this.resourceLoader, this.registry);
		Predicate<String> selectorFilter = selector.getExclusionFilter();
		if (selectorFilter != null) {
			exclusionFilter = exclusionFilter.or(selectorFilter);
		}
         //这里只有是DeferredImportSelector的实现才走这里
         //所以找启动类上的注解,只有@EnableAutoConfiguration里面有引入
         //@Import(AutoConfigurationImportSelector.class)
         //DeferredImportSelector 继承了 ImportSelector
		if (selector instanceof DeferredImportSelector) {
            //接下来走这里 ###
			this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
		}
		else {
			String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
			Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
			processImports(configClass, currentSourceClass, importSourceClasses, false);
		}
	}
	...//省略部分代码
	
}

  • 接下来到ConfigurationClassParser#handler方法,到内部类DeferredImportSelectorHandler
//贴一下该类的两个方法
private class DeferredImportSelectorHandler {

	@Nullable
	private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

	public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
		DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
		//只有在process 也就是处理中的时候为null 本地变量锁的用法
		if (this.deferredImportSelectors == null) {
			DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
			handler.register(holder);
			//递归
			handler.processGroupImports();
		}
		else {
			//正常不会为null 添加到这个list
			this.deferredImportSelectors.add(holder);
		}
	}

	public void process() {
		List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
		this.deferredImportSelectors = null;
		try {
			if (deferredImports != null) {
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
				deferredImports.forEach(handler::register);
				//根据已添加的ImportSelector的类进行回调 接下来走这里 ###
				handler.processGroupImports();
			}
		}
		finally {
			this.deferredImportSelectors = new ArrayList<>();
		}
	}
}

上面通过解析已经拿到所有用@Import引入并且实现了DeferredImportSelector的类集合

  • 再次回到ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
//找到该该方法的最后一行代码
this.deferredImportSelectorHandler.process();
//到上面内部类DeferredImportSelectorHandler#process,接下来走这行代码
handler.processGroupImports();

public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		Predicate<String> exclusionFilter = grouping.getCandidateFilter();
		//先看getImports() ###
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				//这里又是处理import注解的方法,但是走的判断不一样
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
								configurationClass.getMetadata().getClassName() + "]", ex);
			}
		});
	}
}
  • ConfigurationClassParser#getImports()
public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
		//获取需要自动加载的类 ###		
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
		deferredImport.getImportSelector());
	}
	//经过处理后 返回所需的自动装置的类
	return this.group.selectImports();
}
  • 这个group会到AutoConfigurationImportSelector的内部类AutoConfigurationGroup#process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
			() -> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));
	//解析需要自动装配的类  接下来看怎么找到需要解析的类 ### 				
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(annotationMetadata);
	//保存 在下面的selectImports 进行处理后返回		
	this.autoConfigurationEntries.add(autoConfigurationEntry);
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}
	
	//获取到自动装配的类的后续 等下就不贴了
	@Override
	public Iterable<Entry> selectImports() {
		if (this.autoConfigurationEntries.isEmpty()) {
			return Collections.emptyList();
		}
		//需要排除的classname
		Set<String> allExclusions = this.autoConfigurationEntries.stream()
				.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
	    //需要自动装配的classname的list集合
		Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
				.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
				.collect(Collectors.toCollection(LinkedHashSet::new));
		//移除		
		processedConfigurations.removeAll(allExclusions);
		//排序并封装
		return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
				.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
				.collect(Collectors.toList());
	}
}
//getgetAutoConfigurationEntry -> getCandidateConfigurations
//到AutoConfigurationImportSelector
//通过classLoader获取指定key需要自动装配的类
List<String> configurations = 
//getSpringFactoriesLoaderFactoryClass return EnableAutoConfiguration.class;
//这里的key也就是自动装配EnableAutoConfiguration类路径
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
		getBeanClassLoader());	


public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	ClassLoader classLoaderToUse = classLoader;
	if (classLoaderToUse == null) {
		classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
	}
	//key明就是EnableAutoConfiguration类路径
	//org.springframework.boot.autoconfigure.EnableAutoConfiguration
	String factoryTypeName = factoryType.getName();
	//这里从缓存中获取对应类加载器的自动装配的内容 然后再取出key的值 默认返回空list
	return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

  • 接下来SpringFactoriesLoader #loadSpringFactories,获取所有需要自动装置的类存入缓存

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
	//先从缓存获取
	Map<String, List<String>> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	result = new HashMap<>();
	try {
		//String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        //从路径得知应该是去指定文件里面读取 接下来我们看下对应的文件
		Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				String[] factoryImplementationNames =
						StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
				for (String factoryImplementationName : factoryImplementationNames) {
					result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
							.add(factoryImplementationName.trim());
				}
			}
		}

		// Replace all lists with unmodifiable lists containing unique elements
		result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
				.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
		//保存到对应类加载器的map key是对应的类加载器		
		cache.put(classLoader, result);
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
	return result;
}
  • 这里只引人了springboot包,所以找一下spring-boot-autoconfigure包目录下的META-INF/spring.factories的文件,找到对应的key
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
......
  • 反正对应需要自动装配的类之后,接下来回到ConfigurationClassParser#processGroupImports
public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		Predicate<String> exclusionFilter = grouping.getCandidateFilter();
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				//会继续走到扫描加载类 递归的做法 ###
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
								configurationClass.getMetadata().getClassName() + "]", ex);
			}
		});
	}
}
  • 接下来回到ConfigurationClassParser#processImports,因为此时已经不是ImportSelector,找到这个else
else {
	// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
	// process it as an @Configuration class
	//不是ImportSelector的实现类的走向
	this.importStack.registerImport(
			currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
	//加载到本地Map存储	
	processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
//processConfigurationClass最后
//存储到本地map					
this.configurationClasses.put(configClass, configClass);	

需要自动装配的类已经都存在本地的map中了,接下来应该就是晚容器中注册了

  • 再回到ConfigurationClassPostProcessor#processConfigBeanDefinitions
  • 前面的代码其实都是在分析parser.parse(candidates);,接下来走到后面这行
parser.parse(candidates);
parser.validate();
//public Set<ConfigurationClass> getConfigurationClasses() {
//		return this.configurationClasses.keySet();
//	}
//取出存储需要注册的类 return this.configurationClasses.keySet();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);

// 取出reader 没有就创建
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//向容器注册
this.reader.loadBeanDefinitions(configClasses);

到这里,整个自动装配的流程就结束了,源码比较绕,需要很有耐心看
以上就是本章的全部内容了。

上一篇:SpringMvc源码分析第六弹 - 基于SpringMvc源码后的手写高仿版
下一篇:Springboot源码分析第二弹 - 自动配置实现

东隅已逝,桑榆非晚

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值