IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot -- SpringBoot的启动整体过程 | 自动配置类解析注册过程 | Spring5 源码解析 -> 正文阅读

[Java知识库]SpringBoot -- SpringBoot的启动整体过程 | 自动配置类解析注册过程 | Spring5 源码解析

基础环境: ?spring-boot :2.3.3.RELEASE、jdk1.8

1. SpringBoot启动类注解@SpringBootApplication:

?标注@SpringBootApplication的类就是SpringBoot的主配置类,启动该类来启动应用,这是一个组合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

?主要关注自动配置类注解@EnableAutoConfiguration,这也是个组合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

?这里主要关注@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)
`
对于@AutoConfigurationPackage,也是一个组合注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)

?至此,可以看见整个@SpringBootApplication会引入两个@Import,要留意下AutoConfigurationImportSelector.class

2. SpringBoot的启动:

启动主配置类即可启动SpringBoot项目,启动过程是怎样的,下面来看看,先进入启动类的run方法,会调用到此处:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

?在构造函数中会进行一些参数赋值,值得注意的是,此时开始预解析META-INF/spring.factories文件的配置类名

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	// web应用类型,通常默认SERVLET
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// 设置用于容器初始化的ApplicationContextInitializer
	// 初次调用时,getSpringFactoriesInstances会进行META-INF/spring.factories文件的配置类名的解析
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// 同理是设置用于容器初始化的ApplicationListener
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

?2.1. getSpringFactoriesInstances:

?该方法会调用SpringFactoriesLoader.loadFactoryNames方法进行预解析配置类名

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	// 会获取默认类加载器,Launcher类型
	ClassLoader classLoader = getClassLoader();
	// 获取类型为type的配置类名,本次为获取ApplicationContextInitializer类型的配置类名
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	// 通过默认构造方法创建对应配置类名的实例
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	// 对实例进行调用排序
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

?2.1.1. SpringFactoriesLoader.loadFactoryNames:

?该方法会调用loadSpringFactories来解析META-INF/spring.factories文件的配置类名

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	// 参数传递过来的类的完全限定名,即ApplicationContextInitializer类的完全限定名
	String factoryTypeName = factoryType.getName();
	// loadSpringFactories方法来解析配置类名;getOrDefault获取key为factoryTypeName的配置类名
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	// 从缓存cache(key:类加载器;value: result)中获取默认类加载器对应的value
	MultiValueMap<String, String> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}
	// 初次启动调用,缓存获取不到值,开始解析META-INF/spring.factories文件的配置类名
	try {
		// 类加载器不为null,取所有类路径下的META-INF/spring.factories
		Enumeration<URL> urls = (classLoader != null ?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		// 循环遍历有META-INF/spring.factories文件的jar包,将里面的键值对封装到result,结构相当于 Map<Stirng,LinkedList>
		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();
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					result.add(factoryTypeName, factoryImplementationName.trim());
				}
			}
		}
		// 写入缓存,方便后续调用
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

?像自动配置类名就是从spring-boot-autoconfigure这个jar包META-INF/spring.factories文件解析出来

在这里插入图片描述

?2.2. SpringApplication#run:

public ConfigurableApplicationContext run(String... args) {
	... ... ...
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		// 上面设置一些环境吧应该,没怎么关注
		configureIgnoreBeanInfo(environment);
		// 这里控制台会打印输出那个Spring启动图
		Banner printedBanner = printBanner(environment);
		// 创建ApplicationContext即ioc容器
		context = createApplicationContext();
		// 像上面2.1那样,会从缓存中获取SpringBootExceptionReporter类型实例
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 对context进行一些预处理,主要是一些赋值
		// 这里会将主配置类封装成BeanDefinition再注册到ApplicationContext中,详情可参考文末参考链接1
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// 刷新context容器,重点方法
		refreshContext(context);
	... ...
}

?2.3. AbstractApplicationContext#refresh:

?上述refreshContext方法会刷新上下文,即context容器,方法最后会调用refresh方法:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 刷新前准备,初始化properties等
        prepareRefresh();

        // 获取ApplicationContext中组合的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 主要给beanFactory赋值,比如类加载器,ApplicationContextAwareProcessor后置处理器等等
        prepareBeanFactory(beanFactory);

        try {
            // 允许在上下文的子类中对bean factory进行后处理
            postProcessBeanFactory(beanFactory);

            // 调用Bean工厂的后置处理器,重点方法
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);

            // 初始化消息源
            initMessageSource();

            // 初始化事件广播
            initApplicationEventMulticaster();

            // 初始化特殊的Bean,比如tomcat
            onRefresh();

            // 注册监听器
            registerListeners();

            // 实例化所有的(non-lazy-init)单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // 发布刷新完毕事件
            finishRefresh();
        }
        ... ... ... 
}

?2.4. invokeBeanFactoryPostProcessors:

?通过委托模式调用PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
	... ... ...
}

?2.4.1. invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

  • 这个方法会实例化和调用所有postProcessBeanDefinitionRegistry
  • 还有其父类BeanFactoryPostProcessor的postProcessBeanFactory方法
  • 注意:BeanDefinitionRegistryPostProcessor优先于BeanFactoryPostProcessor执行,BeanFactoryPostProcessor优先于bean实例化执行;
public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	Set<String> processedBeans = new HashSet<>();
	// ioc容器创建时beanFactory为DefaultListableBeanFactory
	// DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,所以true
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		// 循环已经注册过的beanFactoryPostProcessors
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			// 如果是子类BeanDefinitionRegistryPostProcessor,就执行postProcessBeanDefinitionRegistry方法
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// 用于保存本初要执行的BeanDefinitionRegistryPostProcessor
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// 找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean的beanName
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 判断这个ppName的bean是否实现了PriorityOrdered
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				// 满足条件会通过getBean获取对应ppName的实例,添加到currentRegistryProcessors
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				// 将ppName添加到processedBeans,表名这个ppName的bean调用过postProcessBeanDefinitionRegistry方法
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		// 调用postProcessBeanDefinitionRegistry方法,重点方法		
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();
		... ... ...
		// 下面省略了两次查找postProcessorNames及调用postProcessBeanDefinitionRegistry方法的逻辑,与上面类似
		// 也省略对父类BeanFactoryPostProcessor查找和调用的逻辑,也类似
		// 省略的内容可以见文末参考链接2
}
  • postProcessorNames查找其实是从beanDefinitionNames中查找符合类型的beanName
  • 容器context创建后,默认的BeanFactory有五个内部托管的beanName,在prepareContext会将主配置类的beanName添加进去
  • 这里实现BeanDefinitionRegistryPostProcessor的只有internalConfigurationAnnotationProcessor

在这里插入图片描述

?这个beanName在getBean时会获取ConfigurationClassPostProcessor对象

在这里插入图片描述

?2.4.2. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

?本次会调用ConfigurationClassPostProcessor的currentRegistryProcessors方法

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
	// 循环遍历传过来的postProcessors,调用postProcessBeanDefinitionRegistry方法
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}

?会通过registryId去重,重复则抛异常,反则调用processConfigBeanDefinitions

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

?2.4.3. processConfigBeanDefinitions(registry);

?方法入参registry就是BeanFactory,就是默认的DefaultListableBeanFactory

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	// 循环遍历candidateNames,也就是beanDefinitionNames,检查出是配置类的beanName
	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);
			}
		}
		// 通过checkConfigurationClassCandidate方法检查出是配置类的beanName
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			// 封装成BeanDefinitionHolder,添加到configCandidates
			// 启动的初次调用只检查出主配置类
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}
	
	... ... ...  // 省略一些校验和排序的逻辑

	// 构建配置类解析器ConfigurationClassParser
	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 {
		// 此时只解析主配置类,因为candidates只有主配置类,这里涉及了自动配置类的中间注册了
		parser.parse(candidates);
		parser.validate();

		// 经过递归解析,符合条件的组件都被解析成ConfigurationClass,包括包扫描和自动配置类的组件
		//添加到ConfigurationClassParser#configurationClasses对象
		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());
		}
		// 将组件的配置类加载成beanDefinitions
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

?checkConfigurationClassCandidate方法有很多检查条件

  • 这里会解析这个bean是不是@Configuration、@Component、@ComponentScan、@Import、@ImportResource标注的或者@Bean标注的方法
public static boolean checkConfigurationClassCandidate(
		BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
	
	... ... ...
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
	// @Configuration默认的proxyBeanMethods为true,及@Configuration(proxyBeanMethods=true)
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}

	... ... ...
	return true;
}


public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
	// Do not consider an interface or an annotation...
	if (metadata.isInterface()) {
		return false;
	}

	// candidateIndicators即@Component、@ComponentScan、@Import、@ImportResource四个注解声明
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// 看是不是@Bean标注的方法
	try {
		return metadata.hasAnnotatedMethods(Bean.class.getName());
	}
	catch (Throwable ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
		}
		return false;
	}
}

?2.5. parser.parse(candidates);

?通过内部parse方法解析主配置类的相关组件信息

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			// 注解的主配置类会执行这个parse方法
			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);
		}
	}

	this.deferredImportSelectorHandler.process();
}

?2.5.1. processConfigurationClass:

?parse方法会调用processConfigurationClass来处理配置类,过程中的配置类会递归调用它

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
	// 通过匹配Conditional等条件注解看是否跳过解析,详情可参考文末参考链接3
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}
	//判断同一个配置类是否重复被嵌套加载,对于主配置类,这里是null,所以跳过
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			return;
		}
		else {
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}


	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		// 核心处理配置类的方法
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);
	// 将处理的配置类添加到configurationClasses
	this.configurationClasses.put(configClass, configClass);
}
?2.5.1.1 doProcessConfigurationClass(configClass, sourceClass, filter);

?核心处理配置类的方法,
·
?包括@Component、@ComponentScan、@Import、@ImportResource以及@Bean一些处理

protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
		throws IOException {

	// @Configuration也是基于@Component的,所以对于主配置类此处成立
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// 处理任何成员(嵌套)类,内部会递归调用doProcessConfigurationClass,主配置类只有一个main方法,此处没什么成立
		// 像AopAutoConfiguration的AspectJAutoProxyingConfiguration等内部配置类便在该方法递归处理
		processMemberClasses(configClass, sourceClass, filter);
	}

	// 处理任何@PropertySource注解,主要是把资源文件读取到上下文环境中去
	// 从上文1中可见,对于主配置类没有@PropertySources注解,跳过
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		... ... ...
	}

	// 处理任何 @ComponentScan 的注解
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		// 添加满足,循环遍历componentScans
		for (AnnotationAttributes componentScan : componentScans) {
			// 这里扫描出basePackages包的所有bean的beanDefinition
			// 默认是启动(主配置)类所在的包,也是在里面处理的
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// 循环遍历,递归处理扫描出的beanDefinition
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					// 递归处理扫描出的beanDefinition,重复2.6之后的流程
					// 比如再解析@Configuration中的@Bean
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	// 处理任何 @Import 注解,包括@ImportSelector,详细逻辑介绍见下文2.5.2
	// getImport会找出主配置类中@Import所有的类
	processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

	// 处理 @ImportResource 注解;对locations参数做处理,然后记录到当前configClass中
	// 当前主配置类没有改注解,跳过
	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 注解的方法;有的话也是封装后记录到configClass的beanMethods属性里
	// 本主配置类不涉及@Bean,跳过
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// 处理接口的default方法;也是封装后记录到configClass的beanMethods属性里
	processInterfaces(configClass, sourceClass);

	// 处理超类,一般就是顶层Object类,一般第二个if不满足
	if (sourceClass.getMetadata().hasSuperClass()) {
		String superclass = sourceClass.getMetadata().getSuperClassName();
		if (superclass != null && !superclass.startsWith("java") &&
				!this.knownSuperclasses.containsKey(superclass)) {
			this.knownSuperclasses.put(superclass, configClass);
			return sourceClass.getSuperClass();
		}
	}

	// 这个配置类没什么好处理的,就返回null
	return null;
}
?2.5.1.2. ConfigurationClassParser#processImports:

?上文1. 中对springboot启动类注解有介绍,可见包含两个@import,继承关系如下

  • AutoConfigurationPackages.Registrar implements ImportBeanDefinitionRegistrar
  • AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware …
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {

	if (importCandidates.isEmpty()) {
		return;
	}

	// 判断是否已经引入过了
	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		// 配置类入栈
		this.importStack.push(configClass);
		try {
			// 循环遍历importCandidates,即@Import的类
			for (SourceClass candidate : importCandidates) {
				// DeferredImportSelector是继承ImportSelector的,所有AutoConfigurationImportSelector是符合的
				if (candidate.isAssignable(ImportSelector.class)) {
					// 获取引入的类类型,即AutoConfigurationImportSelector
					Class<?> candidateClass = candidate.loadClass();
					// 通过构造函数创建AutoConfigurationImportSelector实例对象
					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);
					}
					// AutoConfigurationImportSelector实例显然符合判断
					if (selector instanceof DeferredImportSelector) {
						//初次调用,主要是进行deferredImportSelectors赋值,见下文2.6.1.3				
						this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
					}
					else {
						// 这里应该是版本兼容的,像springboot-2.0.X就是走这里,本版本跳过
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				// AutoConfigurationPackages.Registrar在这里处理,也会生成实例对象
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {

					Class<?> candidateClass = candidate.loadClass();
					ImportBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
					// 添加到configClass的importBeanDefinitionRegistrars属性中
					// 用于后面beanDefinition的注册
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				else {
					// 如果都不是上述两类,则按@Configurationc处理
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					// 递归2.5.1取处理,这里入参将configClass转换成配置类ConfigurationClass
					processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
				}
			}
		}
		... ... ...// catch异常抛出代码省略
		finally {
			// 出栈
			this.importStack.pop();
		}
	}
}
?2.5.1.3 this.deferredImportSelectorHandler.handle

?主要对deferredImportSelectors进行赋值

public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
	// 将主配置类和importSelector封装到DeferredImportSelectorHolder
	DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
	// deferredImportSelectors本身是不等于null的,可能是为了兼容?
	if (this.deferredImportSelectors == null) {
		DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
		handler.register(holder);
		handler.processGroupImports();
	}
	else {
		// 将封装的holder添加到deferredImportSelectors
		this.deferredImportSelectors.add(holder);
	}
}

?2.5.2. this.deferredImportSelectorHandler.process();

?跳过默认选择器处理器取处理

public void process() {
	List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
	this.deferredImportSelectors = null;
	try {
		// deferredImports不为null,里面保存有选择器处理器,见上文2.5.1.3
		if (deferredImports != null) {
			DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
			deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
			// 对DeferredImportSelectorGroupingHandler进行分组(封装),见下文2.5.2.1
			deferredImports.forEach(handler::register);
			// 进行分组后处理,见下文2.5.2.2
			handler.processGroupImports();
		}
	}
	finally {
		this.deferredImportSelectors = new ArrayList<>();
	}
}
?2.5.2.1. deferredImports.forEach(handler::register)

?这是个lambda表达式用法,就是遍历deferredImports,然后调用register方法,将元素作为入参

public void register(DeferredImportSelectorHolder deferredImport) {
	// 获取选择器处理器组类型
	Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
	// 构建组,封装到DeferredImportSelectorGrouping,然后添加到groupings
	DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
			(group != null ? group : deferredImport),
			key -> new DeferredImportSelectorGrouping(createGroup(group)));
	// 将传过来的选择器处理器deferredImport也添加到grouping,就是给对象内部属性this.deferredImports添加值
	grouping.add(deferredImport);
	// 添加到当前	configurationClasses(key:选择器处理器元数据;value:选择器所属配置类)
	this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getConfigurationClass());
}
?2.5.2.2. handler.processGroupImports()

?这里面会获取符合条件@ConditionXXX的的自动配置类名

public void processGroupImports() {
	// 前文每一个选择器封装一个DeferredImportSelectorGrouping,这里就循环遍历组处理
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		Predicate<String> exclusionFilter = grouping.getCandidateFilter();
		// getImports会获取符合条件@ConditionXXX的的自动配置类名,见下文2.5.2.3
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				// 遍历递归处理加载了的配置类,取处理其包含的引入组件;比如@Bean之类
				// 入参将配置类名entry.getImportClassName()封装成ConfigurationClass.Parser.SourceClass
				// 在内部方法入参会将
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			}
			... ... ... //异常捕获抛出
		});
	}
}
?2.5.2.3. grouping.getImports()
public Iterable<Group.Entry> getImports() {
	// 每个选择器处理器都会添加到当前组,在前文2.5.2.1中可见this.deferredImports的添加值
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
	// 当前组循环遍历每一个选择器处理器进行处理,这里会扫描符合条件@ConditionXXX的自动配置类名		
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	// 主要对自动配置类名去重和排序
	return this.group.selectImports();
}
???2.5.2.3.1. this.group.process

??入参为配置类元数据和选择器

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	... ... ... // 省略断言校验
	// getAutoConfigurationEntry获取符合条件的自动配置类名并封装到AutoConfigurationEntry
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(annotationMetadata);
	this.autoConfigurationEntries.add(autoConfigurationEntry);
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}
???2.5.2.3.2.getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	// 获取所有自动配置类名
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	// 去重
	configurations = removeDuplicates(configurations);
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
	checkExcludedClasses(configurations, exclusions);
	configurations.removeAll(exclusions);
	// 过滤不符合@ConditionXXX的配置类名
	configurations = getConfigurationClassFilter().filter(configurations);
	fireAutoConfigurationImportEvents(configurations, exclusions);
	// 过滤后的自动配置类名封装到AutoConfigurationEntry,用于后面组件引入
	return new AutoConfigurationEntry(configurations, exclusions);
}
???2.5.2.3.3.getCandidateConfigurations

?SpringFactoriesLoader.loadFactoryNames在前文2.1.1中就进行了初次调用,并将结果进行缓存

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	// getSpringFactoriesLoaderFactoryClass返回EnableAutoConfiguration.class
	// 该方法从缓存中返回EnableAutoConfiguration类完全限定名对应的value
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
			getBeanClassLoader());
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
			+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

?2.6. this.reader.loadBeanDefinitions(configClasses)

?循环遍历需要引入的组件配置类对象

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
	// 循环遍历需要引入的组件配置类对象,调用loadBeanDefinitionsForConfigurationClass方法
	for (ConfigurationClass configClass : configurationModel) {
		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
	}
}

?2.6.1. loadBeanDefinitionsForConfigurationClass

?主要对不同方式引用的组件进行beanDefinition注册,通过调用registerBeanDefinition方法
·
?最终会将组件包括嵌套的beanDefinition添加到beanDefinitionMap,以及beanDefinitionNames

private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

	// 条件注解判断是否跳过这个配置类,详情可以参考文末参考链接3
	if (trackedConditionEvaluator.shouldSkip(configClass)) {
		String beanName = configClass.getBeanName();
		if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
			// 如果跳过,Spring容器中移除bean的注册
			this.registry.removeBeanDefinition(beanName);
		}
		// 从importRegistry 中也移除
		this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
		return;
	}
	// 如果这是一个通过import机制被导入进来的配置类,将它本身作为一个bean定义注册到容器
	if (configClass.isImported()) {
		registerBeanDefinitionForImportedConfigurationClass(configClass);
	}
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		// 现在把配置类里面@Bean注解的方法作为bean定义注册到容器
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}

	// 从配置类导入的bean定义资源中获取bean定义信息并注册到容器,比如xml
	loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
	// 从配置类导入的ImportBeanDefinitionRegistrar中获取bean定义信息并注册到容器	
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

? 后面会另起一篇文章来介绍不同方式的引入对应的beanDefinition注册

?2.7. ServletWebServerApplicationContext#onRefresh

  • 上文在2.3中介绍了refresh方法,执行完invokeBeanFactoryPostProcessors,会进行后置处理器的注册等等,这里先不做介绍了
  • 这里介绍一下onRefresh方法,这涉及tomcat的启动,主要调用内部方法createWebServer
protected void onRefresh() {
	super.onRefresh();
	try {
		createWebServer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}

?2.7.1. ServletWebServerApplicationContext#createWebServer

?本文这里主要了解内置tomcat怎么启动的

private void createWebServer() {
	WebServer webServer = this.webServer;
	ServletContext servletContext = getServletContext();
	// 默认都为null
	if (webServer == null && servletContext == null) {
		// 获取服务应用工厂,ServletWebServerFactory类型
		// 默认是TomcatServletWebServerFactory,具体是ServletWebServerFactoryAutoConfiguration这个自动配置类的功劳
		ServletWebServerFactory factory = getWebServerFactory();
		// 默认获取tomcat服务容器
		this.webServer = factory.getWebServer(getSelfInitializer());
		... ... ...// 省略
}

?2.7.2. TomcatServletWebServerFactory#getWebServer

public WebServer getWebServer(ServletContextInitializer... initializers) {
	if (this.disableMBeanRegistry) {
		Registry.disableRegistry();
	}
	// 新建了Tomcat
	Tomcat tomcat = new Tomcat();
	File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
	tomcat.setBaseDir(baseDir.getAbsolutePath());
	Connector connector = new Connector(this.protocol);
	connector.setThrowOnFailure(true);
	tomcat.getService().addConnector(connector);
	customizeConnector(connector);
	tomcat.setConnector(connector);
	tomcat.getHost().setAutoDeploy(false);
	configureEngine(tomcat.getEngine());
	for (Connector additionalConnector : this.additionalTomcatConnectors) {
		tomcat.getService().addConnector(additionalConnector);
	}
	prepareContext(tomcat.getHost(), initializers);
	// 以上都是tomcat一些环境配置
	// getTomcatWebServer来初始化TomcatWebServer,会启动Tomcat
	return getTomcatWebServer(tomcat);
}

// 构造函数会初始化,内部会this.tomcat.start();启动tomcat
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
	return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}

?这里可以见的,在springboot中,是先启动springboot,创建了ioc容器,再启动的tomcat
·
?对于传统的xml配置的web应用,往往要先启动tomcat,才能创建ioc容器

?2.8. AbstractApplicationContext#finishBeanFactoryInitialization

?前文介绍了Bean的加载到beanDefinition的注册,但其实并未进行Bean的生命周期(创建-实例化-属性填充-初始化等等)
·
?这个方法内部会循环遍历beanDefinitionNames,再通过getBean进行Bean的生命周期
·
?Bean的生命周期详情可以参考文章进行系列查看

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	... ... ... // 省略一些环境或者其他调用的代码
	// 该方法会将非懒加载又是单例的bean进行生命周期调用
	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}


public void preInstantiateSingletons() throws BeansException {
	... ... ... //省略
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 非抽象&& 单例 && 非懒加载
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				... ... ... // 大部分组件bean不会走这里,这是工厂bean的
			}
			else {
				// 最终调用getBean进行Bean的生命周期调用
				getBean(beanName);
			}
		}
	}
	... ... ... //省略
}

?3. 小结:

?SpringBoot启动会解析主配置(启动)类注解,引入AutoConfigurationImportSelector选择器

  • 然后扫描到包的组件配置类名(@Configuration或者@Component派生的注解标注的Bean),封装成ConfigurationClass
  • 然后通过选择器获取自动配置类名,也封装成ConfigurationClass
  • 然后通过调用registerBeanDefinition方法,对配置类ConfigurationClass进行beanDefinition注册,最终添加到beanDefinitionMap,以及beanDefinitionNames
  • 通过getBean进行组件的Bean生命周期调用

?了解到这里,因为SpringBoot通过很多自动配置类,为我们省去了很多配置步骤
·
?后续打算介绍AopAutoConfiguration这个自动配置类,来加深整个解析、注册的理解,当然不是在这篇文章。

【参考链接】:

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-16 11:36:57  更:2021-08-16 11:37:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 9:43:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码