当前位置:   article > 正文

SpringBoot3框架_springboot3 classloader

springboot3 classloader

传送门

SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口

一、前言

由于面试问到的比较多,而且做java开发这块还是需要真正掌握的。
现有笔记尚硅谷雷锋阳老师的:SpringBoot3全栈指南,是我目前见过的最好笔记了。
参考视频尚硅谷雷锋阳老师的:SpringBoot零基础教程,面试&加薪必会,视频是24小时31分钟的高质量教程。
参考代码:https://gitee.com/leifengyang/spring-boot-3

本文以SpringBoot3.1.2中Spring对应版本是6.0.11为例。

下面文章不定期更新中…

二、面试回答总结

最经典的20个Spring Boot面试题,95%以上会被问到,不服来战

三、源码解析(简单版)

1、SpringBoot创建Spring上下文

在这里插入图片描述
10和11行代码的区别,10行传了args参数,java -jar xxx.jar --k1=v1这种的时候,就是有效果的,否则像11行那样,是没有效果的。

我们来看一个SpringBoot3的启动类案例,并跟着这个案例深入

@SpringBootApplication
public class JdkNewFeaturesDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(JdkNewFeaturesDemoApplication.class, args);// 断点进入run方法
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);// 断点进入run方法
	}
  • 1
  • 2
  • 3
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);// 分两部分,断点进入第一部分new,断点进入第二部分run
	}
  • 1
  • 2
  • 3

ConfigurableApplicationContext 类是容器上下文,但是不是最终容器上下文,SpringApplication非Spring容器上下文。
一般最终Spring容器上下文是AnnotationConfigServletWebServerApplicationContext。
在这里插入图片描述
在这里插入图片描述

我们断点进入第一部分new的代码

	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details). The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param resourceLoader the resource loader to use
	 * @param primarySources the primary bean sources
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;// 资源加载器
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// primarySources启动类
		this.webApplicationType = WebApplicationType.deduceFromClasspath();// 判断web的上下文是servlet上下文还是reactive上下文,reactive是响应式编程(webflux),当然SpringBoot默认是servlet
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//(断点进入设置初始化器) 设置初始化器,就是将实现了ApplicationContextInitializer接口的实现类实例化并缓存一下,这边会加载到META-INF/spring.factories(该文件就是自动装配。主要是接口和实现类的对应,一个接口有多个实现类值,Key-Values的对应)
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 设置监听器,将实现了ApplicationListener接口的实现类实例化
		this.mainApplicationClass = deduceMainApplicationClass();// 调用main方法的类返回出来赋值到这里,目的是解析这个类以及类上的注解。
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

我们断点进入设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))

	private <T> List<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, null);// 断点持续进入
	}
	
	private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {
		return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
		// 第一部分forDefaultResourceLocation这边会加载到META-INF/spring.factories(该文件就是自动装配。主要是接口和实现类的对应,一个接口有多个实现类值,Key-Values的对应)
		// 第二部分load,断点持续进入
	}

	public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver,
			@Nullable FailureHandler failureHandler) {

		Assert.notNull(factoryType, "'factoryType' must not be null");
		List<String> implementationNames = loadFactoryNames(factoryType);// 加载到对应类的实现名字,也就是实现了ApplicationContextInitializer接口的实现类
		logger.trace(LogMessage.format("Loaded [%s] names: %s", factoryType.getName(), implementationNames));
		List<T> result = new ArrayList<>(implementationNames.size());
		FailureHandler failureHandlerToUse = (failureHandler != null) ? failureHandler : THROWING_FAILURE_HANDLER;
		for (String implementationName : implementationNames) {
			// 将这些实现名字做一个实例化
			T factory = instantiateFactory(implementationName, factoryType, argumentResolver, failureHandlerToUse);
			if (factory != null) {
				result.add(factory);
			}
		}
		AnnotationAwareOrderComparator.sort(result);
		return result;// 这类比一个缓存,以后获取的时候方便
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

我们返回到开始,断点进入第二部分run的代码

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 创建一个启动上下文,非Spring容器上下文,做一些启动方面相关的处理,只是在boot工程启动时间的临时上下文,内置多播器
		ConfigurableApplicationContext context = null;
		// 根据系统变量java.awt.headless的值来设置java.headless.mode,缺省值是true,
		// 在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式。
		// 默认为true,因为大部分的boot项目都不需要外设交互,一旦启动成功就不需要操作。
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);// 拿到一些监听器
		listeners.starting(bootstrapContext, this.mainApplicationClass);// 监听器开始工作,发布ApplicationStartingEvent事件
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 获取命令行参数
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 准备环境
			Banner printedBanner = printBanner(environment);// 打印banner
			// 【核心】创建一个Spring上下文,不执行refresh方法,一般最终Spring容器上下文是AnnotationConfigServletWebServerApplicationContext
			context = createApplicationContext();// 断点进入创建Spring容器上下文
			context.setApplicationStartup(this.applicationStartup);// 设置记录步骤的记录器
			// 这里会将一些早期事件注册给多播器,并发布一个事件
			// 【核心】准备上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 断点进入准备上下文
			// 【核心】刷新容器,真正执行了refresh方法
			refreshContext(context);// 断点进入刷新容器
			afterRefresh(context, applicationArguments);// 刷新后处理
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);// 广播启动完成事件
			callRunners(context, applicationArguments);// 执行所有的runner,runner机制,实现对应接口,在SpringBoot启动后能做一些初始化工作,比如Redis预热
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
				listeners.ready(context, timeTakenToReady);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

我们断点进入context = createApplicationContext();// 断点进入创建Spring容器上下文

	protected ConfigurableApplicationContext createApplicationContext() {
		return this.applicationContextFactory.create(this.webApplicationType);// DefaultApplicationContextFactory是成员变量就赋值好的默认上下文工厂,webApplicationType类型是SERVLET(根据配置决定的)
	}

	// 断点进入DefaultApplicationContextFactory的create方法
	// 实际上走的ServletWebServerApplicationContextFactory的create方法(SpringBoot默认是servlet,所以一般是走这个实现类的create方法)
	@Override
	public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
		try {
			return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
					this::createDefaultApplicationContext);// 断点进入getFromSpringFactories
		}
		catch (Exception ex) {
			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
					+ "you may need a custom ApplicationContextFactory", ex);
		}
	}

	// 断点进入getFromSpringFactories方法
	private <T> T getFromSpringFactories(WebApplicationType webApplicationType,
			BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
			// 循环ApplicationContextFactory的实现类,一般有三个,在spring.factories中可以看到(不同jar包这个文件内容不一样)
			// DefaultApplicationContextFactory、ReactiveWebServerApplicationContextFactory、ServletWebServerApplicationContextFactory
		for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
				getClass().getClassLoader())) {
			T result = action.apply(candidate, webApplicationType);// 判断哪个工厂能满足条件,这边一般返回了子类,返回的就是最终的Spring容器上下文,比如SpringBoot默认是servlet而非reactive,返回的就是AnnotationConfigServletWebServerApplicationContext
			if (result != null) {
				return result;
			}
		}
		return (defaultResult != null) ? defaultResult.get() : null;
	}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

我们返回到上一级ConfigurableApplicationContext的run方法代码中, 断点进入准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);// 设置环境
		postProcessApplicationContext(context);// 上下文的后置处理,设置了消息转化器
		addAotGeneratedInitializerIfNecessary(this.initializers);// aot相关
		applyInitializers(context);// 调用之前设置的初始化器,执行一些方法
		listeners.contextPrepared(context);// ApplicationcontextInitializedEvent事件
		bootstrapContext.close(context);// 关闭启动上下文
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 从上下文拿到默认的bean工厂,下面给工厂设置一些参数
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
			autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);// 设置是否允许循环引用,默认是没有开启循环引用的。
			if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
				listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);// 设置BeanDefinition是否可以被覆盖,默认false没有开启。
			}
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// 添加一些BeanFactory的后置处理器,PropertySourceOrder是优先级高的那批后置处理器。
		if (!AotDetector.useGeneratedArtifacts()) {
			// Load the sources
			Set<Object> sources = getAllSources();// 加载资源,BeanDefinition
			Assert.notEmpty(sources, "Sources must not be empty");
			load(context, sources.toArray(new Object[0]));
		}
		listeners.contextLoaded(context);// 发布上下文加载相关的事件
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

我们返回到上一级ConfigurableApplicationContext的run方法代码中, 断点进入
refreshContext(context);// 断点进入刷新容器

	private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			shutdownHook.registerApplicationContext(context);// shutdownHook是钩子
		}
		refresh(context);// 断点持续进入
	}
	
	protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();// 断点持续进入
	}

	// ServletWebServerApplicationContext的refresh方法(servlet进入这个)
	@Override
	public final void refresh() throws BeansException, IllegalStateException {
		try {
			super.refresh();// 就会调用到父类的AbstractApplicationContext的refresh方法,真正刷新。父类的refresh方法中预留的让子类调用的扩展点,有被SpringBoot重写。比如refresh方法里面的onRefresh方法,就被子类启动了tomcat。
		}
		catch (RuntimeException ex) {// 抛异常,如果SpringBoot上下文启动失败
			WebServer webServer = this.webServer;// 能获取到webServer
			if (webServer != null) {
				webServer.stop();// 会将webServer停止掉
			}
			throw ex;
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2、SpringBoot的自动装配

我们回到最开始,持续进入看@SpringBootApplication注解,可以看到重要的@EnableAutoConfiguration注解

@SpringBootApplication// 持续点进去
public class JdkNewFeaturesDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(JdkNewFeaturesDemoApplication.class, args);// 断点进入run方法
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)// 点进去,引入一个Selector,这个Selector返回的字符串数组,里面所有的全限定名称bean都会加载到Spring容器中。
public @interface EnableAutoConfiguration {

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

AutoConfigurationImportSelector点进去可以看到重要的selectImports方法

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		// 【核心】获取到自动装配的健值对
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 断点进入
		// 将键值对里面的Configurations拿到,返回字符串数组,进而加载到Spring容器中。
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

	// 断点进入
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}		
		// annotationMetadata就是启动类com.zt.JdkNewFeaturesDemoApplication相关的一些东西,是元数据
		AnnotationAttributes attributes = getAttributes(annotationMetadata);// attributes为exclude和excludeName,后面主要用于排除一些bean
		// 【核心】获取候选的配置类,SpringBoot3.1.2版本有146个XxxAutoConfiguration自动装配配置类。
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 断点进入
		// 进行筛选去重过滤
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);// 最后得到25个
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);// key是25个List<String>,value是空的Set<String> 
	}

	// 断点进入
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		// 【核心】加载AutoConfiguration.class作为key的所有资源
		List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())// 断点进入
			.getCandidates();
		Assert.notEmpty(configurations,
				"No auto configuration classes found in "
						+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

断点进入
List configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
【核心】加载AutoConfiguration.class作为key的所有资源

	// annotation这个就是AutoConfiguration.class
	public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
		Assert.notNull(annotation, "'annotation' must not be null");
		ClassLoader classLoaderToUse = decideClassloader(classLoader);
		// 格式化LOCATION,格式化后的字符串为
		// META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
		// 这个imports文件就在自动装配spring-boot-autoconfigure的jar包里面,路径就是上面路径
		// 里面是Spring支持的所有的自动装配相关的配置类,注意都是XxxAutoConfiguration配置类
		String location = String.format(LOCATION, annotation.getName());
		Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
		List<String> importCandidates = new ArrayList<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			importCandidates.addAll(readCandidateConfigurations(url));
		}
		return new ImportCandidates(importCandidates);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

难点:
SpringBoot3.1.2版本有146个XxxAutoConfiguration自动装配配置类是在Spring的refresh方法中哪一步加载进入的呢?

答案是refresh的12个方法中第5个方法:
方法5之前beanFactory对象的beanDefinitionMap属性只有6个,也就是有6个基本的BeanDefinition;
invokeBeanFactoryPostProcessors(beanFactory);// 5、执行BeanFactoryPostProcessor的方法;
方法5之后,beanDefinitionMap就有146个了。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 记录每一步执行的工具类

			// Prepare this context for refreshing.
			prepareRefresh();// 1、准备刷新容器上下文

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 2、获取BeanFactory;默认实现是DefaultListableBeanFactory,在创建容器的时候创建的,beanFactory 里面有个beanDefinitionMap属性,存放BeanDefinition。

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);// 3、BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器,BeanPostProcessor和XXXAware自动装配等)

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);// 4、BeanFactory准备工作完成后进行的后置处理工作(留给子类实现,空方法)

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);// 5、执行BeanFactoryPostProcessor的方法;

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);// 6、注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();// 7、初始化MessageSource组件(做国际化功能;消息绑定,消息解析);

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster(); // 8、初始化事件多播器

				// Initialize other special beans in specific context subclasses.
				onRefresh();// 9、子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器

				// Check for listener beans and register them.
				registerListeners(); // 10、注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean,这些监听器是注册到ApplicationEventMulticaster中的

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);// 11、实例化所有的非懒加载单例bean(最最核心方法)

				// Last step: publish corresponding event.
				finishRefresh();// 12、完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
			}

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

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

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

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

一路判断invokeBeanFactoryPostProcessors(beanFactory)中哪一行代码导致的beanDefinitionMap突然变多,会发现
ConfigurationClassPostProcessor这个processor是优先级最高的被执行的processor(实现了PriorityOrdered接口)。
在我Spring6源码解析的文章中有详细的讲解。(见传送门)

	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
		// for循环第一个就是ConfigurationClassPostProcessor
		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
					.tag("postProcessor", postProcessor::toString);
			// ConfigurationClassPostProcessor类里面的postProcessBeanDefinitionRegistry方法执行后,
			// 这里就将剩余的BeanDefinition(XxxAutoConfiguration)注册进入了,beanDefinitionMap就有146个了
			// 有了XxxAutoConfiguration这些BeanDefinition,其余的通过条件判断注解等等条件,普通的BeanDefinition也就注册进去了
			postProcessor.postProcessBeanDefinitionRegistry(registry);
			postProcessBeanDefRegistry.end();
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来就是看ConfigurationClassPostProcessor何时进入的容器,ConfigurationClassPostProcessor是在最初始的beanDefinitionMap的6个里面的。
接下来我们就要看SpringBoot的run方法来分析了

其中context = createApplicationContext();// 【核心】创建一个Spring上下文,不执行refresh方法

我们仔细回顾一下这一步

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 创建一个启动上下文,非Spring容器上下文,做一些启动方面相关的处理,只是在boot工程启动时间的临时上下文,内置多播器
		ConfigurableApplicationContext context = null;
		// 根据系统变量java.awt.headless的值来设置java.headless.mode,缺省值是true,
		// 在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式。
		// 默认为true,因为大部分的boot项目都不需要外设交互,一旦启动成功就不需要操作。
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);// 拿到一些监听器
		listeners.starting(bootstrapContext, this.mainApplicationClass);// 监听器开始工作,发布ApplicationStartingEvent事件
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 获取命令行参数
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 准备环境
			Banner printedBanner = printBanner(environment);// 打印banner
			// 【核心】创建一个Spring上下文,不执行refresh方法,一般最终Spring容器上下文是AnnotationConfigServletWebServerApplicationContext
			context = createApplicationContext();// 断点进入创建Spring容器上下文
			context.setApplicationStartup(this.applicationStartup);// 设置记录步骤的记录器
			// 这里会将一些早期事件注册给多播器,并发布一个事件
			// 【核心】准备上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 断点进入准备上下文
			// 【核心】刷新容器,真正执行了refresh方法
			refreshContext(context);// 断点进入刷新容器
			afterRefresh(context, applicationArguments);// 刷新后处理
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);// 广播启动完成事件
			callRunners(context, applicationArguments);// 执行所有的runner,runner机制,实现对应接口,在SpringBoot启动后能做一些初始化工作,比如Redis预热
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
				listeners.ready(context, timeTakenToReady);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

我们断点进入context = createApplicationContext();// 断点进入创建Spring容器上下文

	protected ConfigurableApplicationContext createApplicationContext() {
		return this.applicationContextFactory.create(this.webApplicationType);// DefaultApplicationContextFactory是成员变量就赋值好的默认上下文工厂,webApplicationType类型是SERVLET(根据配置决定的)
	}

	// 断点进入ServletWebServerApplicationContextFactory的create方法(SpringBoot默认是servlet,所以一般是走这个实现类的create方法)
	@Override
	public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
		return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext();
	}

	private ConfigurableApplicationContext createContext() {
		if (!AotDetector.useGeneratedArtifacts()) {
		// 【核心】构造这个最终Spring容器上下文的时候,创建了初始的beanDefinitionMap中的BeanDefinition
			return new AnnotationConfigServletWebServerApplicationContext();// 断点进入
		}
		return new ServletWebServerApplicationContext();
	}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

我们断点进入
return new AnnotationConfigServletWebServerApplicationContext();

	public AnnotationConfigServletWebServerApplicationContext() {
		// 这边注册了5个
		this.reader = new AnnotatedBeanDefinitionReader(this);// 断点进入
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
  • 1
  • 2
  • 3
  • 4
  • 5

断点进入
this.reader = new AnnotatedBeanDefinitionReader(this);

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));// 点this断点进入
	}

	// 点this断点进入
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);// 条件计算器,做条件注解相关的一些工具
		// 注册AnnotationConfig的处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);// 断点进入
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

断点进入
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

	public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);	// 断点进入
	}
	
	// 断点进入
	// 主要注入了5个bean
	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// BeanDefinition的持有者
		// ConfigurationClassPostProcessor的注册
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);// 转为BeanDefinition
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for Jakarta Annotations support, and if present add the CommonAnnotationBeanPostProcessor.
		if ((jakartaAnnotationsPresent || jsr250Present) &&
				!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

ConfigurationClassPostProcessor就是此时进入的容器。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/504827
推荐阅读
  

闽ICP备14008679号