SpringBoot 系列文章
关注我
转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/
前言 在 Spring Boot 项目的启动类中常见代码如下:
1 2 3 4 5 6 @SpringBootApplication public class SpringbotApplication { public static void main (String[] args) { SpringApplication.run(SpringbotApplication.class, args); } }
其中也就两个比较引人注意的地方:
@SpringBootApplication
SpringApplication.run()
对于第一个注解 @SpringBootApplication
,我已经在博客 Spring Boot 2.0系列文章(六):Spring Boot 2.0中SpringBootApplication注解详解 中详细的讲解了。接下来就是深入探究第二个了 SpringApplication.run()
。
换个姿势 上面的姿势太简单了,只一行代码就完事了。
1 SpringApplication.run(SpringbotApplication.class, args);
其实是支持做一些个性化的设置,接下来我们换个姿势瞧瞧:
1 2 3 4 5 6 7 8 9 @SpringBootApplication public class SpringbotApplication { public static void main (String[] args) { SpringApplication app = new SpringApplication(SpringbotApplication.class); app.run(args) } }
没错,就是通过一个构造函数,然后设置相关的属性,从而达到定制化服务。有哪些属性呢?
属性对应的 get/set 方法
看到没,还很多呢!
举个例子:你想把 Spring Boot 项目的默认 Banner 换成你自己的,就需要在这里如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static void main (String[] args) { SpringApplication application = new SpringApplication(Springboot2Application.class); application.setBanner((environment, sourceClass, out) -> { System.out.println(" _ _ _\n" + " | | (_) | |\n" + " ____| |__ _ ___ | |__ ___ _ __ __ _\n" + "|_ /| '_ \\ | |/ __|| '_ \\ / _ \\| '_ \\ / _` |\n" + " / / | | | || |\\__ \\| | | || __/| | | || (_| |\n" + "/___||_| |_||_||___/|_| |_| \\___||_| |_| \\__, |\n" + " __/ |\n" + " |___/\n" ); }); application.setBannerMode(Banner.Mode.CONSOLE); application.run(args); }
现在重启项目,你就会发现,控制台的 logo 已经换成你自己的了。
当然了,你可能会觉得这样写有点复杂,嗯嗯,确实,这样硬编码在代码里确实不太友好。你还可以在src/main/resources
路径下新建一个banner.txt
文件,banner.txt
中填写好需要打印的字符串内容即可。
从该类中可以看到在 Spring Boot 2 中引入了个新的 WebApplicationType 和 WebEnvironment。
确实,这也是 Spring Boot 2 中比较大的特性,它是支持响应式编程的。我之前在文章 Spring Boot 2.0系列文章(二):Spring Boot 2.0 新特性详解 中也介绍过,以后有机会会介绍它的,这里我先卖个关子。
SpringApplication 初始化 SpringApplication.run()
的实现才是我们要深入探究的主角,该方法代码如下:
1 2 3 4 5 6 7 8 9 public static ConfigurableApplicationContext run (Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); } public static ConfigurableApplicationContext run (Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
在这个静态方法中,创建 SpringApplication 对象,并调用该对象的 run 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public SpringApplication (Class<?>... primarySources) { this (null , primarySources); } @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 = deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this .mainApplicationClass = deduceMainApplicationClass(); }
首先是进入单个参数的构造方法,然后进入两参数的构造方法(ResourceLoader 为 null),然后进行初始化。
1、deduceWebApplicationType() : 推断应用的类型 ,创建的是一个 SERVLET 应用还是 REACTIVE应用或者是 NONE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework.web.reactive.DispatcherHandler" ;private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework.web.servlet.DispatcherServlet" ;private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet" , "org.springframework.web.context.ConfigurableWebApplicationContext" }; private WebApplicationType deduceWebApplicationType () { if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null ) && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null )) { return WebApplicationType.REACTIVE; } for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null )) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
2、setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)) :初始化 classpath 下的所有的可用的 ApplicationContextInitializer。
1)、getSpringFactoriesInstances()
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 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 = Thread.currentThread().getContextClassLoader(); Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } 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; }
上面的 SpringFactoriesLoader.loadFactoryNames() ,是从 META-INF/spring.factories 的资源文件中,读取 key 为org.springframework.context.ApplicationContextInitializer 的 value。
而 spring.factories 的部分内容如下:
可以看到,最近的得到的,是 ConfigurationWarningsApplicationContextInitializer,ContextIdApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer 这四个类的名字。
2)、setInitializers():
1 2 3 4 5 public void setInitializers ( Collection<? extends ApplicationContextInitializer<?>> initializers) { this .initializers = new ArrayList<>(); this .initializers.addAll(initializers); }
所以,这里 setInitializers() 所得到的成员变量 initializers 就被初始化为ConfigurationWarningsApplicationContextInitializer,ContextIdApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer 这四个类的对象组成的 list。
3、setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)) :初始化 classpath 下的所有的可用的 ApplicationListener。
1)、getSpringFactoriesInstances() 和上面的类似,但是它是从 META-INF/spring.factories 的资源文件中,获取到 key 为 org.springframework.context.ApplicationListener 的 value。
2)、setListeners():
1 2 3 4 public void setListeners (Collection<? extends ApplicationListener<?>> listeners) { this .listeners = new ArrayList<>(); this .listeners.addAll(listeners); }
所以,这里 setListeners() 所得到的成员变量 listeners 就被初始化为 ClearCachesApplicationListener,ParentContextCloserApplicationListener,FileEncodingApplicationListener,AnsiOutputApplicationListener ,ConfigFileApplicationListener,DelegatingApplicationListener,ClasspathLoggingApplicationListener,LoggingApplicationListener,LiquibaseServiceLocatorApplicationListener 这九个类的对象组成的 list。
4、deduceMainApplicationClass() :根据调用栈,推断出 main 方法的类名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 ; }
run 方法背后的秘密 上面看完了构造方法后,已经初始化了一个 SpringApplication 对象,接下来调用其 run 方法,代码如下:
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 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); } 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; }
可变个数参数 args 即是我们整个应用程序的入口 main 方法的参数。StopWatch 是来自 org.springframework.util 的工具类,可以用来方便的记录程序的运行时间。
再来看看 1.5.12 与 2.0.1 版本的 run 方法 有什么不一样的地方?
接下来好好分析上面新版本(2.0.1)的 run 方法的代码并配合比较旧版本(1.5.12)。
1、configureHeadlessProperty() :设置 headless 模式
1 2 3 4 5 6 7 private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless" ;private boolean headless = true ;private void configureHeadlessProperty () { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty( SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this .headless))); }
实际上是就是设置系统属性 java.awt.headless,该属性会被设置为 true。
2、getRunListeners() :加载 SpringApplicationRunListener 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); listeners.started(context); callRunners(context, applicationArguments); } try { listeners.running(context); } private SpringApplicationRunListeners getRunListeners (String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this , args)); }
上面的 getRunListeners() 中也利用 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringApplicationRunListener 的值,然后再将获取到的值作为参数传递到 SpringApplicationRunListeners 的构造方法中去创建对象。
3、new DefaultApplicationArguments(args) :获取启动时传入参数 args(main 方法传进来的参数) 并初始化为 ApplicationArguments 对象。
1 2 3 4 5 public DefaultApplicationArguments (String[] args) { Assert.notNull(args, "Args must not be null" ); this .source = new Source(args); this .args = args; }
4、prepareEnvironment(listeners, applicationArguments) :根据 listeners 和 applicationArguments 配置SpringBoot 应用的环境。
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 private ConfigurableEnvironment prepareEnvironment ( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (this .webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } ConfigurationPropertySources.attach(environment); return environment; } private ConfigurableEnvironment getOrCreateEnvironment () { if (this .environment != null ) { return this .environment; } if (this .webApplicationType == WebApplicationType.SERVLET) { return new StandardServletEnvironment(); } return new StandardEnvironment(); } protected void configureEnvironment (ConfigurableEnvironment environment,String[] args) { configurePropertySources(environment, args); configureProfiles(environment, args); } protected void bindToSpringApplication (ConfigurableEnvironment environment) { try { Binder.get(environment).bind("spring.main" , Bindable.ofInstance(this )); } catch (Exception ex) { throw new IllegalStateException("Cannot bind to SpringApplication" , ex); } }
5、configureIgnoreBeanInfo(environment) :根据环境信息配置要忽略的 bean 信息
1 2 3 4 5 6 7 8 9 10 11 public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore" ;private void configureIgnoreBeanInfo (ConfigurableEnvironment environment) { if (System.getProperty( CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null ) { Boolean ignore = environment.getProperty("spring.beaninfo.ignore" , Boolean.class, Boolean.TRUE); System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString()); } }
6、printBanner(environment) :打印标志,上面我已经说过了。
1 2 3 4 5 6 7 8 9 10 11 12 13 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); }
7、createApplicationContext() :根据应用类型来确定该 Spring Boot 项目应该创建什么类型的 ApplicationContext ,默认情况下,如果没有明确设置的应用程序上下文或应用程序上下文类,该方法会在返回合适的默认值。
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 public static final String DEFAULT_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" ;public static final String 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_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); }
来看看在 1.5.12 中是怎么样的?
8、exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context)
1 2 3 4 5 6 7 8 9 10 11 private <T> Collection<T> getSpringFactoriesInstances (Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
这里也是通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringBootExceptionReporter 的全类名的 value 值。
9、prepareContext(context, environment, listeners, applicationArguments, printedBanner) :完成整个容器的创建与启动以及 bean 的注入功能。
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 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); } context.getBeanFactory().registerSingleton("springApplicationArguments" , applicationArguments); if (printedBanner != null ) { context.getBeanFactory().registerSingleton("springBootBanner" , printedBanner); } Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray(new Object[0 ])); listeners.contextLoaded(context); }
1)、postProcessApplicationContext(context)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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()); } } }
该方法对 context 进行了预设置,设置了 ResourceLoader 和 ClassLoader,并向 bean 工厂中添加了一个beanNameGenerator 。
2)、applyInitializers(context)
1 2 3 4 5 6 7 8 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); } }
在刷新之前将任何 ApplicationContextInitializer 应用于上下文
3)、load(context, sources.toArray(new Object[0]))
主要是加载各种 beans 到 ApplicationContext 对象中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected void load (ApplicationContext context, Object[] 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(); }
(1)、getBeanDefinitionRegistry(context)
获取 bean 定义注册表
1 2 3 4 5 6 7 8 9 10 private BeanDefinitionRegistry getBeanDefinitionRegistry (ApplicationContext context) { if (context instanceof BeanDefinitionRegistry) { return (BeanDefinitionRegistry) context; } if (context instanceof AbstractApplicationContext) { return (BeanDefinitionRegistry) ((AbstractApplicationContext) context) .getBeanFactory(); } throw new IllegalStateException("Could not locate BeanDefinitionRegistry" ); }
(2)、createBeanDefinitionLoader()
通过 BeanDefinitionLoader 的构造方法把参数(注册表、资源)传进去,然后创建 BeanDefinitionLoader。
(3)、load()
把资源全部加载。
10、refreshContext(context)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void refreshContext (ConfigurableApplicationContext context) { refresh(context); if (this .registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { } } } protected void refresh (ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
refreshContext(context) 方法又调用了 refresh(context)。在调用了 refresh(context) 方法之后,调用了 registerShutdownHook 方法。继续看它的 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 public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { 。。。 destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
到这里,我们就看见重点了,仔细看上的注释,正在做各种初始化工作,而今天我们关注的重点就是方法 finishBeanFactoryInitialization(beanFactory)。该方法进行了非懒加载 beans 的初始化工作。现在我们进入该方法内部,一探究竟。
看上图方法中的最后一步,调用了 beanFactory 的 preInstantiateSingletons() 方法。此处的 beanFactory 是哪个类的实例对象呢?
可以看到 ConfigurableListableBeanFactory 接口的实现类只有 DefaultListableBeanFactory,我们看下实现类中的 preInstantiateSingletons 方法是怎么做的。
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 void preInstantiateSingletons () throws BeansException { List<String> beanNames = new ArrayList<>(this .beanDefinitionNames); for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean){ isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { getBean(beanName); } } } for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null ) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null ; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
从上面的代码中可以看到很多调用了 getBean(beanName) 方法,跟踪此方法进去后,最终发现 getBean 调用了AbstractBeanFactory 类的 doGetBean(xxx) 方法,doGetBean(xxx) 方法中有这么一段代码:
但是 createBean() 方法并没有得到实现,实现类在 AbstractAutowireCapableBeanFactory 中。这才是创建 bean 的核心方法。
不知不觉,代码看的越来越深,感觉思维都差点回不去 run 方法了,切回大脑的上下文线程到 run 方法去。
11、afterRefresh(context, applicationArguments) :在上下文刷新后调用该方法,其内部没有做任何操作。
发现没做任何操作了之后,就觉得有点奇怪,所以把当前版本和 1.5.12 对比了下,发现:
在 1.5.12 中的 afterRefresh() 方法中调用了 callRunners() 方法,但是在 2.0.1 版本中的 run 方法中调用了 callRunners () 方法:
这里不得不说 SpringApplicationRunListeners 在 2.0.1 中的改变:
可以发现在 run 方法中,SpringApplicationRunListeners 监听器的状态花生了变化,这也是通过对比不同版本的代码才知道的区别,所以说我们看源码需要多对比着看。
so,我们来看下这个 SpringApplicationRunListener 这个接口:
started 状态:The context has been refreshed and the application has started but CommandLineRunner and ApplicationRunner have not been called
running 状态:Called immediately before the run method finishes, when the application context has been refreshed and all CommandLineRunner and ApplicationRunners have been called.
相关文章 1、Spring Boot 2.0系列文章(一):Spring Boot 2.0 迁移指南
2、Spring Boot 2.0系列文章(二):Spring Boot 2.0 新特性详解
3、Spring Boot 2.0系列文章(三):Spring Boot 2.0 配置改变
4、Spring Boot 2.0系列文章(四):Spring Boot 2.0 源码阅读环境搭建
5、Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览
6、Spring Boot 2.0系列文章(六):Spring boot 2.0 中 SpringBootApplication 注解详解
7、Spring Boot 2.0系列文章(七):SpringApplication 深入探索
总结 本文从源码级别分析了 Spring Boot 应用程序的启动过程,着重看了 SpringApplication 类中的构造函数的初始化和其 run 方法内部实现,并把涉及到的流程代码都过了一遍。
感悟:有时候跟代码跟着跟着,发现越陷越深,好难跳出来!后面还需多向别人请教阅读源码的技巧!
最后 虽然源码很难,但随着不断的探索,源码在你面前将会一览无遗,享受这种探索后的成就感!加油!骚年!
自己本人能力有限,源码看的不多,上面如有不对的还请留言交流。