SpringBoot超詳細(xì)分析啟動(dòng)流程
Springboot啟動(dòng)類
@SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
SpringBootApplication注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {
@SpringBootApplication注解上標(biāo)注了@EnableAutoConfiguration,表示TestApplication是引導(dǎo)類。
Springboot的啟動(dòng)方法中傳入了兩個(gè)參數(shù),引導(dǎo)類,和程序參數(shù)。
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); }
調(diào)用run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
run方法中有兩步,創(chuàng)建SpringApplication和執(zhí)行SpringApplication的run方法。
1、創(chuàng)建SpringApplication
SpringApplication的構(gòu)造器
public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
private ResourceLoader resourceLoader; private Set<Class<?>> primarySources; public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { //將resourceLoader賦值成員變量,此處是null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //將引導(dǎo)類賦值成員變量 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //判斷web類型,賦值成員變量 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //加載初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //加載監(jiān)聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //獲得引導(dǎo)類 this.mainApplicationClass = deduceMainApplicationClass(); }
1.1、判斷web類型
//org.springframework.boot.WebApplicationType#deduceFromClasspath static WebApplicationType deduceFromClasspath() { //WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler"; //JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } //SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
1.2、加載上下文初始化器
利用spi加載 ApplicationContextInitializer 的實(shí)現(xiàn)類
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); }
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { //獲取classloader ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates //獲取配置文件中接口實(shí)現(xiàn)類的全限定名 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //初始化 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); //返回 return instances; }
public ClassLoader getClassLoader() { if (this.resourceLoader != null) { return this.resourceLoader.getClassLoader(); } return ClassUtils.getDefaultClassLoader(); }
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 { 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; }
將初始化好的上下文初始化器設(shè)置到成員變量
//private List<ApplicationContextInitializer<?>> initializers; public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<>(initializers); }
1.3、加載監(jiān)聽器
將初始化好的監(jiān)聽器設(shè)置到成員變量
//private List<ApplicationListener<?>> listeners; public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<>(listeners); }
1.4、獲得引導(dǎo)類類型
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { //獲取main方法的類 if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
2、執(zhí)行SpringApplication的run方法啟動(dòng)Springboot
public ConfigurableApplicationContext run(String... args) { //啟動(dòng)停止監(jiān)聽器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); //Spring上下文 ConfigurableApplicationContext context = null; //錯(cuò)誤導(dǎo)出 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //運(yùn)行時(shí)監(jiān)聽器 SpringApplicationRunListeners listeners = getRunListeners(args); //啟動(dòng)運(yùn)行時(shí)監(jiān)聽器 listeners.starting(); try { //生成ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //準(zhǔn)備environment ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = printBanner(environment); //創(chuàng)建Spring上下文 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //準(zhǔn)備上下文 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新上下文 refreshContext(context); //上下文刷新后 afterRefresh(context, applicationArguments); //停止 停止監(jiān)聽器 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //停止運(yùn)行時(shí)監(jiān)聽器 listeners.started(context); //執(zhí)行回調(diào) 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、準(zhǔn)備environment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment //創(chuàng)建environment ConfigurableEnvironment environment = getOrCreateEnvironment(); //配置environment configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
2.1.1、創(chuàng)建environment
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(); } }
這里根據(jù)web類型創(chuàng)建不同的environment
2.1.2、配置environment
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { //轉(zhuǎn)換服務(wù) ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); } configurePropertySources(environment, args); configureProfiles(environment, args); }
配置PropertySources
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { MutablePropertySources sources = environment.getPropertySources(); if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties)); } if (this.addCommandLineProperties && args.length > 0) { String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; if (sources.contains(name)) { PropertySource<?> source = sources.get(name); CompositePropertySource composite = new CompositePropertySource(name); composite.addPropertySource( new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args)); composite.addPropertySource(source); sources.replace(name, composite); } else { sources.addFirst(new SimpleCommandLinePropertySource(args)); } } }
主要為了在PropertySources添加一個(gè)SimpleCommandLinePropertySource。
配置profiles
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) { Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }
將profile添加到environment
2.2、打印Banner
private Banner.Mode bannerMode = Banner.Mode.CONSOLE; private Banner printBanner(ConfigurableEnvironment environment) { //無需打印 if (this.bannerMode == Banner.Mode.OFF) { return null; } ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(getClassLoader()); SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner); if (this.bannerMode == Mode.LOG) { return bannerPrinter.print(environment, this.mainApplicationClass, logger); } return bannerPrinter.print(environment, this.mainApplicationClass, System.out); }
2.3、創(chuàng)建Spring上下文
//DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." //+"web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; //DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." //+"boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"; //DEFAULT_CONTEXT_CLASS = "org.springframework.context." // + "annotation.AnnotationConfigApplicationContext"; protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { 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); }
2.4、準(zhǔn)備上下文
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); //ApplicationContext的后置處理 postProcessApplicationContext(context); //應(yīng)用初始化器 applyInitializers(context); //運(yùn)行時(shí)監(jiān)聽器的準(zhǔn)備上下文監(jiān)聽 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans //獲取beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //將程序入?yún)⒆?cè)bean springApplicationArguments beanFactory.registerSingleton("springApplicationArguments", applicationArguments); //將banner注冊(cè)bean springBootBanner if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } //設(shè)置BeanDefinition是否允許重寫 if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } //初始化允許懶加載,設(shè)置BeanfactorypostProcessor if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources //獲取source Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); //運(yùn)行時(shí)監(jiān)聽器,上下文加載完成 listeners.contextLoaded(context); }
2.4.1、ApplicationContext的后置處理
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { //注冊(cè) beanNameGenerator if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } //注冊(cè) resourceLoader if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader()); } } //設(shè)置 ConversionService if (this.addConversionService) { context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); } }
//org.springframework.boot.convert.ApplicationConversionService#getSharedInstance public static ConversionService getSharedInstance() { ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance; if (sharedInstance == null) { synchronized (ApplicationConversionService.class) { sharedInstance = ApplicationConversionService.sharedInstance; if (sharedInstance == null) { sharedInstance = new ApplicationConversionService(); ApplicationConversionService.sharedInstance = sharedInstance; } } } return sharedInstance; }
2.4.2、應(yīng)用初始化器
protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
執(zhí)行所有實(shí)現(xiàn)了 ApplicationContextInitializer 接口的類的initialize方法。
2.4.3、獲取sources
public Set<Object> getAllSources() { Set<Object> allSources = new LinkedHashSet<>(); if (!CollectionUtils.isEmpty(this.primarySources)) { allSources.addAll(this.primarySources); } if (!CollectionUtils.isEmpty(this.sources)) { allSources.addAll(this.sources); } return Collections.unmodifiableSet(allSources); }
這里組裝了引導(dǎo)類和自定義的source
2.4.4、加載
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } //創(chuàng)建BeanDefinitionLoader BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } //加載,spring的邏輯,這里會(huì)將引導(dǎo)類注冊(cè) loader.load(); }
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) { return new BeanDefinitionLoader(registry, sources); }
2.5、刷新上下文
private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { //注冊(cè)鉤子 關(guān)閉SpringBoot容器 context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } }
刷新
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); //執(zhí)行spring容器的刷新 ((AbstractApplicationContext) applicationContext).refresh(); }
2.6、上下文刷新后
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }
這里是一個(gè)空實(shí)現(xiàn),應(yīng)該是作為模板擴(kuò)展吧。
2.7、執(zhí)行回調(diào)
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); 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); } } }
這里會(huì)調(diào)用所有實(shí)現(xiàn)了ApplicationRunner,CommandLineRunner的接口的實(shí)現(xiàn)類的run方法。
到此這篇關(guān)于SpringBoot超詳細(xì)分析啟動(dòng)流程的文章就介紹到這了,更多相關(guān)SpringBoot啟動(dòng)分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?BigDecimal類的一般使用、BigDecimal轉(zhuǎn)double方式
這篇文章主要介紹了Java?BigDecimal類的一般使用、BigDecimal轉(zhuǎn)double方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01淺析Java中Apache BeanUtils和Spring BeanUtils的用法
這篇文章主要介紹了Java中Apache BeanUtils和Spring BeanUtils的用法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11Spring項(xiàng)目中swagger用法與swagger-ui使用
這篇文章主要介紹了Spring項(xiàng)目中swagger用法與swagger-ui使用,通過圖文并茂的形式給大家介紹了編寫springboot項(xiàng)目的方法及導(dǎo)入spring-fox依賴的代碼詳解,需要的朋友可以參考下2021-05-05一文詳解Java?etcd的應(yīng)用場(chǎng)景及編碼實(shí)戰(zhàn)
etcd?是一個(gè)高度一致的分布式鍵值存儲(chǔ)系統(tǒng)。本文旨在幫助大家理解etcd,從宏觀角度俯瞰etcd全局,掌握etcd的基本操作技能,需要的可以參考一下2022-08-08Spring?Data?JPA系列JpaSpecificationExecutor用法詳解
這篇文章主要為大家介紹了Spring?Data?JPA系列JpaSpecificationExecutor用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09利用spring aop實(shí)現(xiàn)動(dòng)態(tài)代理
這篇文章主要為大家詳細(xì)介紹了利用spring aop實(shí)現(xiàn)動(dòng)態(tài)代理的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03JavaWeb項(xiàng)目實(shí)戰(zhàn)之表白墻和在線相冊(cè)
這篇文章主要給大家介紹了關(guān)于JavaWeb項(xiàng)目實(shí)戰(zhàn)之表白墻和在線相冊(cè)的相關(guān)資料,JavaWeb表白墻是一款基于JavaWeb技術(shù)開發(fā)的表白墻應(yīng)用,用戶可以在上面發(fā)布表白信息,也可以查看其他用戶的表白信息,需要的朋友可以參考下2023-03-03