springboot源码: springboot初始化过程

1. new SpringApplication()

在springboot种执行这一行操作的时候,SpringApplication.run(DemoApplication.class, args);运行如下代码,初始化SpringApplication对象。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 初始化spring里面的工厂:获取 META-INF/spring.factories 对应的资源
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// getSpringFactoriesInstances初始化监听器实例,
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 获取主函数的位置,并且得到它的class
		this.mainApplicationClass = deduceMainApplicationClass();
	}

1.1 getSpringFactoriesInstance调用SpringFactoriesLoader.loadFactoryNames,让后在loadFactoryNames种调用loadSpringFactories

在springboot配置文件中定义了启动需要使用的Run Listeners和 Application Listeners。然后由getSpringFactoriesInstance完成了对这些Listenners的实例化。

loadSpringFactories代码如下:

public static final String FACTORIES_RESOURCE_LOCATION ="META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactorie(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = cache.ge(classLoader);
	if (result != null) {
		return result;
	}
	try {
		// 获取 META-INF/spring.factories 对应的资源
		Enumeration<URL> urls = (classLoader != null ?
				classLoader.getResource(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResource(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			// 读取文件内容
			Properties properties =PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySe()) {
				String factoryClassName = ((String)entry.getKey()).trim();
				for (String factoryName :StringUtils.commaDelimitedListToStringArray(String) entry.getValue())) {
					// 获取 factoryClassName 对应的多个valu(多个value用逗号分隔)
					result.add(factoryClassName,factoryName.trim());
				}
			}
		}
		// 缓存已经读取到的内容
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to loadfactories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

这里有9个监听器
在这里插入图片描述

2. SpringApplication.run()

然后调用SpringApplication.run方法

/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();//StopWatch主要是用来统计每项任务执行时长
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		// 1.获取在new Application对象时创建的Listeners:
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();// 2.开启listener,并找到相应的接收者完成初始化日志和参数
		try {
			// 设置参数:在springboot启动时传入agrs校验和他的操作方法封装起来
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 3 .环境初始化
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			// 4. 创建spring的aplicationContxt容器
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 5. 将启动需要的参数,listeners,environment等加入容器
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 6. 
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

2.1 SpringApplication.run中调用的getRunListeners

SpringApplication中的getRunListeners调用了

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		// 调用getSpringFactoriesInstances,注意传入参数是SpringApplicationRunListener.class
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
	
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 调用createSpringFactoriesInstances
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		// 排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
	
	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				// 将listener反射加载到内存 
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				// 含有内部类
				Assert.isAssignable(type, instanceClass);
				// 获取构造器
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				// 反射出实例
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

反射过程中触发EventPublishingRunListener的构造函数,因为EventPublishingRunListenerSpringApplicationRunListener.class的一个子类,并且它内部有一个内部类SimpleApplicationEventMulticaster

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		// 将application这个启动类传入,通过启动类获取了前面从配置文件中读取出来的listeners
		// 内部类将所有listeners接收到了
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

SimpleApplicationEventMulticaster的继承关系如下:
在这里插入图片描述

2.2 启动所有listener

listeners.starting()实际上是调用了EventPublishingRunListener的startings方法。

在这里插入图片描述
EventPublishingRunListener中的starting方法

	@Override
	public void starting() {
		// 调用multicastEvent:这里发送一个事件ApplicationStartingEvent。不能够传入参数为启动类,其启动类中的参数
		//发送事件由EventPublishingRunListener的内部类SimpleApplicationEventMulticaster的multicastEvent方法完成,
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}
	
	@Override
	public void multicastEvent(ApplicationEvent event) {
		// 调用multicastEvent
		multicastEvent(event, resolveDefaultEventType(event));
	}
	
	// 将启动项目的事件发送给所有的listeners
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

2.3 SpringApplication.run中调用的prepareEnvironment

读取配置文件就是在此处:

private ConfigurableEnvironment prepareEnvironment(
		SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// 1.创建Environment对象:前面将environment已经被设置了servlet类型,所以这里创建的是环境对象是StandardServletEnvironment。
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	//配置环境数据 
  	// **commandLineArgs**属性从启动参数中解析, 格式"--name=value"
 	 // 配置profiles. 有效的profile(通过**spring.profiles.active**配置) 和 通过SpringApplication.profiles()指定的额外profile
	configureEnvironment(environment,applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	// 2. 发布ApplicationEnvironmentPreparedEvent事件到所有的listeners上
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverte(getClassLoader())
				.convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

2.3.1 getOrCreateEnvironment创建环境类

Environment接口提供了4种实现方式,StandardEnvironmentStandardServletEnvironmentMockEnvironmentStandardReactiveWebEnvironment,分别代表普通程序、Web程序、测试程序的环境、响应式web环境。

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
			return new StandardServletEnvironment();
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}

2.3.2 prepareEnvironment中调用了listeners.environmentPrepared(environment);

environmentPrepared发布的时间会被onApplicationEnvironmentPreparedEvent这个监听器接收到,然后就会加载EnvironmentPostProcessor对象。除了上面3.1.1中的"META-INF/spring.factories"文件中的listener,还有ConfigFileApplicationListener

实际上ConfigFileApplicationListeneronApplicationEnvironmentPreparedEvent方法中,将自身添加到EnvironmentPostProcessor对象列表中。

ConfigFileApplicationListener监听到ApplicationEnvironmentPreparedEvent事件之后开始读取本地配置文件

private void onApplicationEnvironmentPreparedEvent(
		ApplicationEnvironmentPreparedEvent event) {
	// 将自身添加到EnvironmentPostProcessor对象列表中
	List<EnvironmentPostProcessor> postProcessors =loadPostProcessors();
	postProcessors.add(this);
	AnnotationAwareOrderComparator.sort(postProcessors);
	// 调用所有EnvironmentPostProcessor 的postProcessEnvironmen方法
	for (EnvironmentPostProcessor postProcessor :postProcessors) {
		postProcessor.postProcessEnvironmen(event.getEnvironment(),
				event.getSpringApplication());
	}
}

List<EnvironmentPostProcessor> loadPostProcessors() {
	return SpringFactoriesLoader.loadFactorie(EnvironmentPostProcessor.class,
			getClass().getClassLoader());
}

其中ConfigFileApplicationListenerpostProcessEnvironmen方法就是调用addPropertySources

在getOrCreateEnvironment中得到的环境变量会被加入到其父类AbstractEnvironment定义的对象MutablePropertySources中,MutablePropertySources对象中定义了一个属性集合:

private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();

ConfigFileApplicationListener中收到消息加入到了propertySourceList中

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
	}
	
	protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		// 加载properties和yml
		new Loader(environment, resourceLoader).load();
	}

如图:在new Loader(environment, resourceLoader).load();这一行执行的时候才会出现在propertySourceList中间出现OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'} 。并加载其中的内容
在这里插入图片描述

2.4 创建容器context = createApplicationContext();

根据webApplicationType进行判断的,上一篇已经讲述了该变量如何赋值的过程。因为该类型为SERVLET类型。故是DEFAULT_WEB_CONTEXT_CLASS

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

2.6 报告错误信息

这里还是以同样的方式获取 spring.factories文件中的指定类:

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);

2.7 SpringApplication.run种调用prepareContext

其中SpringApplication.run方法的调用的预处理过程如下:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		// 设置容器环境,包括各种变量
		context.setEnvironment(environment);
		// 执行前置处理器
		postProcessApplicationContext(context);
		//执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
		applyInitializers(context);
		// 发送容器已经准备好的事件,通知各监听器
		listeners.contextPrepared(context);
		// 打印log
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// 注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// bean工厂注册单例对象
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		// 注册banner为单例对象
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		// 设置beanFactory是否可以被重写
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// context种添加LazyInitializationBeanFactoryPostProcessor这种类型的工厂
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		// 加载运行所需要的资源
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 加载我们的启动类,将启动类注入容器
		load(context, sources.toArray(new Object[0]));
		// 发布容器已加载事件
		listeners.contextLoaded(context);
	}

2.7.1 容器的后置处理

这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。之所以这样做,是springBoot留给我们的扩展处理方式

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				((GenericApplicationContext) context)
						.setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				((DefaultResourceLoader) context)
						.setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
	}

2.7.2 加载启动指定类

load(context, sources.toArray(new Object[0]));

这里会将我们的启动类加载spring容器beanDefinitionMap中,为后续springBoot 自动化配置奠定基础,springBoot为我们提供的各种注解配置也与此有关。
这里参数即为我们项目启动时传递的参数:SpringApplication.run(SpringBootApplication.class, args);
由于我们指定了启动类,所以上面也就是加载启动类到容器。

2.7.3 listeners.contextLoaded(context);

通知监听器context加载成功。

listeners.contextLoaded(context);

2.8 刷新容器

执行到这里,springBoot相关的处理工作已经结束,接下的工作就交给了spring。refresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键。

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

			// Tell the subclass to refresh the internal bean factory.
			// 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
			 * 设置SPEL表达式#{key}的解析器
			 * 设置资源编辑注册器,如PerpertyEditorSupper的支持
			 * 添加ApplicationContextAwareProcessor处理器
			 * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
			 * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
			 */

			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				/**
				 * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
				 */
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				/**
				 * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
				 * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
				 */
				invokeBeanFactoryPostProcessors(beanFactory);// 初始化bean

				// Register bean processors that intercept bean creation.
				/**
				 * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
				 * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
				 */
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				/**
				 * 初始化上下文中的资源文件,如国际化文件的处理等
				 */
				initMessageSource();

				// Initialize event multicaster for this context.
				/**
				 * 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
				 */
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				/**
				 * 给子类扩展初始化其他Bean
				 */
				onRefresh();

				// Check for listener beans and register them.
				/**
				 * 在所有bean中查找listener bean,然后注册到广播器中
				 */
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				/**
				 * 设置转换器
				 * 注册一个默认的属性值解析器
				 * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
				 * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
				 */
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/**
				 * 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
				 * spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
				 * 启动所有实现了Lifecycle接口的类
				 * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
				 * ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
				 * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
				 */
				finishRefresh();
			}

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

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

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

				// Propagate exception to caller.
				throw ex;
			}

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

2.9 刷新容器后的扩展接口

	protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
	}

参考文献:
https://juejin.im/post/5cb7264af265da03751699b1
https://www.iteye.com/blog/tanliwei-2422300
https://blog.csdn.net/woshilijiuyi/article/details/82219585

发布了275 篇原创文章 · 获赞 42 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_35688140/article/details/102722795