main方法进入 1 2 3 4 5 6 7 8 @SpringBootApplication public class DemoApplication { public static void main (String[] args) { SpringApplication.run(DemoApplication.class, args); } }
底下的方法分为两步:new SpringApplication(primarySources):创建SpringApplication和run():启动SpringApplication。
创建SpringApplication 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @SuppressWarnings({ "unchecked", "rawtypes" }) 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(); }
setInitializers:设置初始化器 它是在IOC容器之前的回调。它的使用方式有三种:
运行SpringApplication之前手动添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ApplicationContextInitializerDemo implements ApplicationContextInitializer { @Override public void initialize (ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializerDemo#initialize run..." ); } } @SpringBootApplication public class DemoApplication { public static void main (String[] args) { SpringApplication springApplication = new SpringApplication (DemoApplication.class); springApplication.addInitializers(new ApplicationContextInitializerDemo ()); springApplication.run(args); } }
application.properties中配置context.initializer.classes=com.example.demo.ApplicationContextInitializerDemo
spring.factories中配置 在工程的 resources 目录下新建 “META-INF” 目录,并在下面创建一个 spring.factories 文件。在文件内声明:org.springframework.context.ApplicationContextInitializer=com.example.demo.ApplicationContextInitializerDemo
内置Initializer spring-boot 和 spring-boot-autoconfigure 包下的 spring.factories 里面对于 ApplicationContextInitializer 的配置:
1 2 3 4 5 6 org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ // 报告IOC容器的一些常见的错误配置 org.springframework.boot.context.ContextIdApplicationContextInitializer,\ // 设置Spring应用上下文的ID org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ // 加载 application.properties 中 context.initializer.classes 配置的类 org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer // 将内置servlet容器实际使用的监听端口写入到 Environment 环境属性中
1 2 3 4 org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ // 创建一个 SpringBoot 和 ConfigurationClassPostProcessor 共用的 CachingMetadataReaderFactory 对象 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener // 将 ConditionEvaluationReport 写入日志
setListeners:设置监听器 用于监听IOC容器中发布的各种事件,到后续看IOC容器的刷新过程时可以看到。
1 2 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
内置Listener 1 2 3 4 5 6 7 8 9 10 11 org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ // 应用上下文加载完成后对缓存做清除工作 org.springframework.boot.builder.ParentContextCloserApplicationListener,\ // 监听双亲应用上下文的关闭事件并往自己的子应用上下文中传播 org.springframework.boot.context.FileEncodingApplicationListener,\ // 检测系统文件编码与应用环境编码是否一致,如果系统文件编码和应用环境的编码不同则终止应用启动 org.springframework.boot.context.config.AnsiOutputApplicationListener,\ // 根据 spring.output.ansi.enabled 参数配置 AnsiOutput org.springframework.boot.context.config.ConfigFileApplicationListener,\ // 从常见的那些约定的位置读取配置文件 org.springframework.boot.context.config.DelegatingApplicationListener,\ // 监听到事件后转发给 application.properties 中配置的 context.listener.classes 的监听器 org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ // 对环境就绪事件 ApplicationEnvironmentPreparedEvent 和应用失败事件 ApplicationFailedEvent 做出响应 org.springframework.boot.context.logging.LoggingApplicationListener,\ // 配置 LoggingSystem。使用 logging.config 环境变量指定的配置或者缺省配置 org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener // 使用一个可以和 SpringBoot 可执行jar包配合工作的版本替换 LiquibaseServiceLocator
确定主配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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) { } return null ; }
源码很简单,从 deduceMainApplicationClass 方法开始往上爬,哪一层调用栈上有main方法,方法对应的类就是主配置类,就返回这个类。
run():启动SpringApplication
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch (); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList <>(); configureHeadlessProperty(); 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(); 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); return context; } catch (Throwable var9) { this .handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9); throw new IllegalStateException (var9); } }
getRunListeners:获取SpringApplicationRunListeners 依然是SPI机制,取spring.factories中所有SpringApplicationRunListener。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public interface SpringApplicationRunListener { void starting () ; void environmentPrepared (ConfigurableEnvironment environment) ; void contextPrepared (ConfigurableApplicationContext context) ; void contextLoaded (ConfigurableApplicationContext context) ; void started (ConfigurableApplicationContext context) ; void running (ConfigurableApplicationContext context) ; void failed (ConfigurableApplicationContext context, Throwable exception) ; }
后续IOC启动过程中会常出现这些SpringApplicationRunListeners的身影,我们可以多加留意。 默认情况下加载的listeners有一个,类型为EventPublishingRunListener。
回到 run 方法中:
1 2 3 4 5 6 7 8 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments (args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
在 prepareEnvironment 之前,run方法中调用了:listeners.starting() ,已经开始了事件回调。
2.2 prepareEnvironment:准备运行时环境 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private ConfigurableEnvironment prepareEnvironment (SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this .isCustomEnvironment) { environment = new EnvironmentConverter (getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
createApplicationContext:创建IOC容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext" ; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext" ; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext" ; 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); }
可以发现都是创建的基于Annotation的 ApplicationContext。
注意,BeanFactory 在这里已经被创建了:
1 2 3 public GenericApplicationContext () { this .beanFactory = new DefaultListableBeanFactory (); }
对三种类型的运行时环境、IOC容器的类型归纳一下:
Servlet - StandardServletEnvironment - AnnotationConfigServletWebServerApplicationContext
Reactive - StandardReactiveWebEnvironment - AnnotationConfigReactiveWebServerApplicationContext
None - StandardEnvironment - AnnotationConfigApplicationContext
prepareContext:初始化IOC容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments" , applicationArguments); if (printedBanner != null ) { beanFactory.registerSingleton("springBootBanner" , printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this .allowBeanDefinitionOverriding); } Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray(new Object [0 ])); listeners.contextLoaded(context); }
postProcessApplicationContext:IOC容器的后置处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static final String CONFIGURATION_BEAN_NAME_GENERATOR = "org.springframework.context.annotation.internalConfigurationBeanNameGenerator" ; 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()); } } if (this .addConversionService) { context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); } }
它设置了几个组件:
如果beanNameGenerator不为空,则把它注册到IOC容器中。BeanNameGenerator是Bean的name生成器,指定的 CONFIGURATION_BEAN_NAME_GENERATOR在修改首字母大写后无法从IDEA索引到,暂且放置一边。
ResourceLoader和ClassLoader,这些都在前面准备好了
ConversionService,用于类型转换的工具,前面也准备好了,并且还做了容器共享
applyInitializers:执行Initializer 这个方法会获取到所有 Initializer,调用initialize方法。 而这些 Initializer,其实就是刚创建 SpringApplication 时准备的那些 ApplicationContextInitializer。见1.1
加载、注册主启动类 等预处理工作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected void load (ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } 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); } loader.load(); }
将启动类包装为BeanDefinition注册到IOC容器中,调用BeanDefinitionReaderUtils的registerBeanDefinition方法。
refreshContext:刷新容器 1 2 3 4 5 6 7 8 9 10 11 private void refreshContext (ConfigurableApplicationContext context) { refresh(context); if (this .registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { } } }
它直接调了refresh方法(注意此时还是 SpringApplication,没有进到真正的IOC容器),后面又注册了一个关闭的钩子。 作用是监听JVM关闭时销毁IOC容器和里面的Bean。
下面我们来看IOC容器启动时最核心的refresh方法:
这个方法很长,也很重要,分为十三步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { try { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { } finally { resetCommonCaches(); } } }
其中主要有三个逻辑,我们慢慢看:
invokeBeanFactoryPostProcessors:执行容器扩展点 onRefresh: finishBeanFactoryInitialization: 文章作者: 米兰
原始链接: https://blog.milanchen.site/posts/springboot-starts-ioc.html
版权声明: 转载请声明出处