springboot启动原理

springboot主函数

springboot项目一般都是打包成jar包直接运行main方法启动,当然也可以跟传统的项目一样打包war包放在tomcat里面启动.那么springboot怎么直接通过main方法启动呢?
举个栗子,这是一个简单的main方法启动类:

@EnableAsync
@EnableScheduling
@EnableTransactionManagement
@EnableConfigurationProperties
@EnableCaching
@MapperScan(value = {"com.study.springbootplus.**.mapper"})
@SpringBootApplication
public class SpringBootPlusApplication {

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args);
  }

}

启动类注解详解,自动装配原理

main方法

main方法主要就是看SpringApplication的run方法,这个方法大概就是创建个spring容器,然后创建个web容器(tomcat,jetty等)启动.

run方法点进去,这里一个新建springApplication实例,一个run方法:

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

初始化SpringApplication实例

源码:

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// main方法中的args参数,可接收命令行启动时添加的参数
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 确认spring容器类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//加载ApplicationContextInitializer类,ApplicationContext初始化类
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//加载ApplicationListener类,监听类
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//获取main方法所在类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

SpringApplication.run方法

源码:

public ConfigurableApplicationContext run(String... args) {
//计时
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		//spring容器
		ConfigurableApplicationContext context = null;
		//错误回调
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		//设置一些系统属性
		configureHeadlessProperty();
		//获取启动时监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//启动监听器
		listeners.starting();
		try {
		//获取一些启动参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			//创建运行环境environment
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			//设置一些系统参数
			configureIgnoreBeanInfo(environment);
			//打印banner
			Banner printedBanner = printBanner(environment);
			//创建spring容器
			context = createApplicationContext();
			//获取异常报告,回调
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
					//准备容器
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			//刷新容器
			refreshContext(context);
			//spring容器后置处理
			afterRefresh(context, applicationArguments);
			//计时终止
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			//结束通知
			listeners.started(context);
			//执行runner
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
		//spring容器就绪通知
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		//返回容器
		return context;
	}

getRunListeners方法,starting方法,获取启动监听,和启动

源码:

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].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));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

前面讲过启动的时候会先加载spring会加载所有jar包下的META-INF/spring.factories,然后缓存起来,这里就获取
在这里插入图片描述
返回spirngboot唯一实现SpringApplicationRunListener的接口:EventPublishingRunListener,然后执行starting方法;starting方法就是构建ApplicationStartingEvent,然后获取listener执行,这一块其实还比较复杂.用到了适配器模式:
在这里插入图片描述

prepareEnvironment准备环境

//准备启动参数就不说了
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);


	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		//创建一个environment对象
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		//配置环境 PropertySources Profiles
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//PropertySources
		ConfigurationPropertySources.attach(environment);
		//环境准备
		listeners.environmentPrepared(environment);
		//将环境绑定到oSpringApplication(
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		//配置PropertySources-如果有attach到environment
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

打印banner

createApplicationContext创建容器

	protected ConfigurableApplicationContext createApplicationContext() {
		//获取上下文的类
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
					//判断Web应用类型
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_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);
	}

在这里插入图片描述

prepareContext,准备容器

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
			//设置环境
		context.setEnvironment(environment);
		//处理上下文
		postProcessApplicationContext(context);
		//获取所有ApplicationContextInitializer,执行ApplicationContextInitializer的init方法
		applyInitializers(context);
		//调用SpringApplicationRunListener的contextPrepared,表示容器已经准备
		listeners.contextPrepared(context);
		//日志
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		//获取beanfactory,注册相关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
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		//加载启动类
		load(context, sources.toArray(new Object[0]));
		//调用SpringApplicationRunListener的contextPrepared,表示容器已经loaded事件
		listeners.contextLoaded(context);
	}

refreshContext,afterRefresh刷新容器,刷新容器之后执行方法

就是spring容器的刷新方法

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页