springboot启动过程源码学习笔记

	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();//确定程序的类型,见下文
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

deduceFromClasspath()

	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

	static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}

org.springframework.boot.WebApplicationType WEB应用程序的类型有三种

  • NONE
  • Servlet
  • Reactive
    三种情况。

ClassUtils.isPresent(String className, @Nullable ClassLoader classLoader)方法的作用:通过检查类的全限定名称,看对应类是否存在。
上面的代码也就是对tomcat和glassfish还有reactive 进行了判断。判断的过程,如果reactive存在,而其他两种都不存在,则认为当前的这个web程序是reactive ,如果SERVLET_INDICATOR_CLASSES 内的类其中一个不存在判断为都不是,如果上述条件都不满足,也就是SERVLET_INDICATOR_CLASSES存在同时 reactive不存在的情况下,成为被判断为是SERVLET程序。

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

该方法是获取实现了ApplicationContextInitializer接口的工厂类实例,这些工程类的实例的列表都存储在了META-INF/spring.factories文件中,或者运行环境下的META-INF/spring.factories中,通过classLoader获取的所有jar和classpath下的对应文件,文件中包含的内容清单如下,每一个工厂类都通过键值对的形式,等号前面是接口,后面是实现类的集合,通过用逗号隔开。例如以下的应用上下文的实现类。在这个地方仅仅只是将所有的工厂类的进行了收集还没有初始化。需要初始化就需要调用方法initialize。后面的获取监听器的方法也是一样的。

# springboot.jar中的
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

#springboot-autoconfiguration中的
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

ApplicationListener

这个接口的作用是当应用有对应的事件时进行处理。该接口在实现时需要同时实现一个ApplicationEvent接口来定义事件。

程序一直运行到这里的时候还没有初始化服务 this.mainApplicationClass = deduceMainApplicationClass();这里仅仅是通过运行方法栈堆,找到当前运行线程中main方法定义的类。

接下来着重看一下 public ConfigurableApplicationContext org.springframework.boot.SpringApplication.run(String… args) 方法。代码块看起来还是非常的清晰的。

public ConfigurableApplicationContext run(String... args) {
		//首先定义了一个计时器,记录了系统从初始化前到初始化结束所用的时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();//针对awt设置的headless
		SpringApplicationRunListeners listeners = getRunListeners(args);//初始化了一个时间监听器
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();//根据应用类型初始化自动配置的上下文类型,AnnotationConfigServletWebServerApplicationContext是servlet的通过注解自动配置的初始化应用上下文
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);//初始化一个异常报告类实例
			/**
			* 初始化所有的初始化工厂类,监听器,应用启动参数,版纳图打印,环境变量,完成应用启动前的准备工作
			**/
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			/**
			* 调用工厂类的初始化方法,扫描组件,注册监听器,完成依赖注入部分
			**/
			refreshContext(context);
			/**
			* 该方法当前为空,
			**/
			afterRefresh(context, applicationArguments);
			/**
			* 停止计时
			**/
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			/**
			* 开始监听
			**/
			listeners.started(context);
			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;
	}

准备工作

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);//真正初始化调用类的方法的时候
		listeners.contextPrepared(context);//监听器的初始化
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		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]));//初始化Bean对象定义的工厂类,配置环境,配置资源加载器
		listeners.contextLoaded(context);//SpringApplicationRunListener加载
	}

springboot为我们提供了一个启动应用程序的框架,通过工厂类和监听器的定义,我们可以将应用制作成一个个插件,就可以无缝的移植进入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值