Spring是如何启动的
标签: 后端
upupor   192   0 2020-08-17 10:39 
最新一次编辑的原因:

下面这段代码是Upupor网站的后端服务启动代码,我之前一直很好奇Spring是如何启动并对外提供服务的,Spring做了哪些工作?现在就从启动代码开始,一步一步开始跟着源码看看发生了些什么

@MapperScan("com.upupor.dao.mapper")
@SpringBootApplication(scanBasePackages = "com.upupor")
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 21600)
@EnableAsync
@Slf4j
public class UpuporAppApplication {
    public static void main(String[] args) {
    	// 先进入 run 方法
        SpringApplication.run(UpuporAppApplication.class, args);
    }
}

run(Class<?>[] primarySources, String[] args)方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		// 这里是新建了一个SpringApplication的应用程序,并把启动类作为参数,加上外界的args参数进来,进行启动前的
		// 物料准备工作
        return (new SpringApplication(primarySources)).run(args);
}

下面看下SpringApplication的有参构造

    // 有参构造
    public SpringApplication(Class<?>... primarySources) {
    	// 调用下面的 构造函数
        this((ResourceLoader)null, primarySources);
    }
    // SpringApplication 启动的有参构造
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    	// 资源
        this.sources = new LinkedHashSet();
        // 广告栏Banner样式,默认是控制台输出
        this.bannerMode = Mode.CONSOLE;
        // 日志
        this.logStartupInfo = true;
        // 添加命令行属性
        this.addCommandLineProperties = true;
        / 添加转换服务
        this.addConversionService = true;
        // 是否进行Headless的配置,可以理解为获取一些系统的基本参数
        this.headless = true;
        // 注册关机钩子
        this.registerShutdownHook = true;
        // 额外资料
        this.additionalProfiles = new HashSet();
        // 是否是自定义环境
        this.isCustomEnvironment = false;
        // 懒加载
        this.lazyInitialization = false;
        // 资源加载器
        this.resourceLoader = resourceLoader;
        // 断言校验
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // [重点]拿到资源
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        // [重点] WEB应用程序类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 从类路径开始
        // [重点] 初始化器
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // [重点] 监听器
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        // [重点] 主应用程序类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

看完了SpringApplication类的构造,Spring的预备工作也准好了,接下来就看看run方法吧

/**
* 静态帮助类可用于运行Spring程序从指定的资源文件并使用默认的设置和用户提供的参数
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
}

/**
* 运行Spring应用程序,创建和刷新一个新的应用程序上下文
*/
public ConfigurableApplicationContext run(String... args) {
		// 启动计时器
		StopWatch stopWatch = new StopWatch();
		// 开始计时
		stopWatch.start();
		
		// 可配置的应用程序上下文
		ConfigurableApplicationContext context = null;
		// 初始化SpringBoot异常报告器
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		// 配置Headless的配置,可以理解为获取一些系统的基本参数
		configureHeadlessProperty();
		// 获取Spring应用程序启动的监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 启动监听器
		listeners.starting();
		try {
			// 应用程序参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 根据监听器及应用程序参数进行环境的准备工作
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 配置忽略Bean信息
			configureIgnoreBeanInfo(environment);
			// 打印Banner
			Banner printedBanner = printBanner(environment);
			// [重点] 创建应用程序上下文,这里是根据 webApplicationType 来创建对应的应用程序
			context = createApplicationContext();
			// 异常报告器
			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);
			// [重点]此时开始运行程序(call回调)
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
		    // 如果处理有异常,将异常上报给 exceptionReporters
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			// 监听器运行,监听整个上下文
			listeners.running(context);
		}
		catch (Throwable ex) {
			// 如果处理有异常,将异常上报给 exceptionReporters
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

prepareContext(context, environment, listeners, applicationArguments, printedBanner) 源码

	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]));
	listeners.contextLoaded(context);
}

postProcessApplicationContext方法

/**
 * Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
 * apply additional processing as required.
 * @param context the application context
 */
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
	// 根据Bean的名称生成
	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());
		}
	}
	// 添加转换服务
	if (this.addConversionService) {
		context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
	}
}

refreshContext,刷新上下文

private void refreshContext(ConfigurableApplicationContext context) {
	refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}

afterRefresh,无任何实现

/**
 * Called after the context has been refreshed.
 * @param context the application context
 * @param args the application arguments
 */
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

callRunners,方法

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	// 初始化运行者
	List<Object> runners = new ArrayList<>();
	// 从前面准备好的context上下文中,根据Type获取Beans
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	// 排序
	AnnotationAwareOrderComparator.sort(runners);
	// 运行
	for (Object runner : new LinkedHashSet<>(runners)) {
		// 应用程序
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		// 命令行
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

本作品系原创,采用《署名-非商业性使用-禁止演绎4.0 国际》许可协议.转载请说明出处
本文链接:https://www.upupor.com/u/20081710397867799552 复制分享

无评论内容,快来评论吧