SpringBoot源码分析-启动过程
启动流程图
启动原理
我们开发任何一个Spring Boot项目,都会用到如下的启动类
1 2 3 4 5 6 @SpringBootApplication public class ApplicationTest { public static void main (String[] args) { SpringApplication.run(ApplicationTest.class); } }
从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。
SpringBootApplication注解
@SpringBootApplication注解是Spring Boot的核心注解,它其实是一个组合注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @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
虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:
@Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
@EnableAutoConfiguration
@ComponentScan
即 @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan。
所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:
1 2 3 4 5 6 7 8 @Configuration @EnableAutoConfiguration @ComponentScan public class ApplicationTest { public static void main (String[] args) { SpringApplication.run(ApplicationTest.class, args); } }
每次写这3个比较累,所以写一个@SpringBootApplication方便点。接下来分别介绍这3个Annotation。
@Configuration
这里的@Configuration对我们来说不陌生,它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。
@ComponentScan
@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。
@EnableAutoConfiguration
@EnableAutoConfiguration注解是springboot 完成自动装配的核心注解,借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
@EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。
@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:
1 2 3 4 5 6 7 8 9 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { ... }
其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class)
,借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样,借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!
SpringApplication执行流程 启动类 1 2 3 4 5 6 @SpringBootApplication public class ApplicationTest { public static void main (String[] args) { SpringApplication.run(ApplicationTest.class); } }
接着会走几个run方法的重载
1 2 3 4 5 6 7 8 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方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:
根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
推断并设置main方法的定义类。
当程序开始执行之后,会先创建SpringApplication对象,会调用SpringApplication的构造方法,进行某些初始参数的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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(); }
主要流程如下
推断当前WEB应用类型
读取META-INF/spring.factories 初始化ApplicationContextInitializer和ApplicationListener
推断主入口类
deduceFromClasspath
在上述构造方法中,有一个判断应用类型的方法,用来判断当前应用程序的类型:
检查是存在比如是否存在特定类来判断类型,比如判断是否存在javax.servlet.Servlet,如果存在则判断为SERVLET类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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; }
WebApplicationType的类型
总共有三种环境:非web环境、web环境、reactive环境三种
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public enum WebApplicationType { NONE, SERVLET, REACTIVE;
读取spring.factories完成初始化
读取META-INF/spring.factories文件获取对应的类完成初始化
初始化ApplicationContextInitializer
ApplicationContextInitializer
是spring组件spring-context
组件中的一个接口,主要是spring ioc容器刷新之前的一个回调接口,用于处于自定义逻辑。
1 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
初始化ApplicationListener
ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。
其中spring有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener接口可以收到监听动作,然后可以写自己的逻辑。
同样事件可以自定义、监听也可以自定义,完全根据自己的业务逻辑来处理。
1 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
deduceMainApplicationClass
推断主入口应用类
1 2 3 4 5 6 7 8 9 10 11 12 13 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 ; }
基本流程就是创建一个运行时异常,然后获得堆栈数组,遍历StackTraceElement数组,判断方法名称是否为“mian”,如果过是则通过Class.forName()方法创建Class对象。
启动服务
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 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 65 66 67 68 69 70 71 72 73 74 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; }
下面详细介绍各个启动的环节:
创建监控类
创建并启动计时监控类,可以看到记录当前任务的名称,默认是空字符串,然后记录当前springboot应用启动的开始时间。
1 2 StopWatch stopWatch = new StopWatch ();stopWatch.start();
详细源码如下
1 2 3 4 5 6 7 8 9 10 11 12 public void start () throws IllegalStateException { this .start("" ); } public void start (String taskName) throws IllegalStateException { if (this .currentTaskName != null ) { throw new IllegalStateException ("Can't start StopWatch: it's already running" ); } else { this .currentTaskName = taskName; this .startTimeNanos = System.nanoTime(); } }
初始化应用上下文和异常报告集合 1 2 ConfigurableApplicationContext context = null ;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList <>();
设置系统属性
设置系统属性java.awt.headless的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 private void configureHeadlessProperty () { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this .headless))); }
创建spring运行监听器
创建所有spring运行监听器并发布应用启动事件
SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。
1 2 3 4 5 6 7 SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();
创建spring监听器 1 2 3 4 5 private SpringApplicationRunListeners getRunListeners (String[] args) { Class<?>[] types = new Class <?>[]{SpringApplication.class, String[].class}; return new SpringApplicationRunListeners (logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this , args)); }
getSpringFactoriesInstances方法是从META-INF/spring.factories
文件下的类获取 SpringApplicationRunListener
接口的所有实现类,但是只有一个实现类EventPublishingRunListener
创建监听器集合并返回
1 2 3 4 SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener > listeners) { this .log = log; this .listeners = new ArrayList <>(listeners); }
启动监听 1 2 3 4 5 6 7 void starting () { for (SpringApplicationRunListener listener : this .listeners) { listener.starting(); } }
EventPublishingRunListener实现类的starting方法
1 2 3 4 5 6 @Override public void starting () { this .initialMulticaster.multicastEvent(new ApplicationStartingEvent (this .application, this .args)); }
发布事件的具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public void multicastEvent (final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null ) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
初始化默认应用参数类
创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。
1 ApplicationArguments applicationArguments = new DefaultApplicationArguments (args);
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; }
准备运行环境
根据运行监听器和应用参数来准备spring环境
遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。
1 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
详细环境的准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private ConfigurableEnvironment prepareEnvironment (SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); 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; }
创建环境
获取或者创建应用环境,根据应用程序的类型可以分为servlet环境、标准环境(特殊的非web环境)和响应式环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 (); } }
配置应用环境 1 2 3 4 5 6 7 8 9 10 protected void configureEnvironment (ConfigurableEnvironment environment, String[] args) { if (this .addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); } configurePropertySources(environment, args); configureProfiles(environment, args); }
创建banner打印类
如果SpringApplication的showBanner属性被设置为true,则打印banner。
1 Banner printedBanner = 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); }
创建应用的上下文
创建应用的上下文:根据不同哦那个的应用类型初始化不同的上下文应用类
根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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); }
准备异常报告器
准备异常报告器,用来支持报告关于启动的错误 获取SpringBootExceptionReporter接口的类,异常报告
1 2 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class []{ConfigurableApplicationContext.class}, context);
从META-INF/spring.factories中加载SpringBootExceptionReporter接口类型的实现类,并通过反射实例化
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 = getClassLoader(); Set<String> names = new LinkedHashSet <>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
准备应用上下文
准备应用上下文,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化提供基础
1 prepareContext(context, environment, listeners, applicationArguments, printedBanner);
详细准备过程
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 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); } if (this .lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor ()); } Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray(new Object [0 ])); listeners.contextLoaded(context); }
postProcessApplicationContext
这里没有做任何的处理过程,因为beanNameGenerator和resourceLoader默认为空,可以方便后续做扩展处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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()); } }
进行初始化
ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。
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); } }
添加所有的事件监听器
遍历调用所有SpringApplicationRunListener的contextPrepared()方法。
1 2 3 4 5 void contextPrepared (ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this .listeners) { listener.contextPrepared(context); } }
加载启动类
最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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(); }
加载Class文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private int load (Object source) { Assert.notNull(source, "Source must not be null" ); if (source instanceof Class<?>) { return load((Class<?>) source); } if (source instanceof Resource) { return load((Resource) source); } if (source instanceof Package) { return load((Package) source); } if (source instanceof CharSequence) { return load((CharSequence) source); } throw new IllegalArgumentException ("Invalid source type " + source.getClass()); }
这里会加载我们的启动类ApplicationTest,因为是一个class所以会走load((Class<?>) source)
springboot会优先选择groovy加载方式,找不到在选择java方式
1 2 3 4 5 6 7 8 9 10 11 12 13 private int load (Class<?> source) { if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } if (isComponent(source)) { this .annotatedReader.register(source); return 1 ; } return 0 ; }
在这里面会判断是否包含@Component注解,如果包含则会注册到注解扫描器中,交给以后的PostProcessor处理
1 2 3 4 5 6 7 8 9 10 11 private boolean isComponent (Class<?> type) { if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) { return true ; } return !type.getName().matches(".*\\$_.*closure.*" ) && !type.isAnonymousClass() && type.getConstructors() != null && type.getConstructors().length != 0 ; }
触发contextLoaded事件
遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
1 2 3 4 5 void contextLoaded (ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this .listeners) { listener.contextLoaded(context); } }
刷新应用上下文
核心方法,启动spring容器
调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。
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(); }
接着就回到了Spring中的源码了
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 65 66 67 68 69 70 71 72 73 74 75 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) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
应用上下文刷新后置处理
应用上下文刷新后置处理,做一些扩展功能
当前方法的代码是空的,可以做一些自定义的后置处理操作
1 2 protected void afterRefresh (ConfigurableApplicationContext context, ApplicationArguments args) {}
停止计时监控类
计时监听器停止,并统计一些任务执行信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void stop () throws IllegalStateException { if (this .currentTaskName == null ) { throw new IllegalStateException ("Can't stop StopWatch: it's not running" ); } else { long lastTime = System.nanoTime() - this .startTimeNanos; this .totalTimeNanos += lastTime; this .lastTaskInfo = new StopWatch .TaskInfo(this .currentTaskName, lastTime); if (this .keepTaskList) { this .taskList.add(this .lastTaskInfo); } ++this .taskCount; this .currentTaskName = null ; } }
发布应用上下文启动完成事件
触发所有SpringapplicationRunListener监听器的started事件方法
1 2 3 4 5 void started (ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this .listeners) { listener.started(context); } }
执行所有Runner执行器
执行所有applicationRunner和CommandLineRunner两种运行器
查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } } }
发布应用上下文就绪事件
触发所有springapplicationRunnListener将挺起的running事件方法
1 2 3 4 5 void running (ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this .listeners) { listener.running(context); } }