springboot源码之启动流程1 发表于 2023-10-10 | 更新于 2024-11-07
| 阅读量:
主程序入口
这里补充 入口 携带的注解说明
1 2 3 4 5 public class NotificationApp { public static void main (String[] args) { SpringApplication.run(NotificationApp.class, args); } }
构造方法 1 2 3 4 5 6 7 8 9 10 org.springframework.boot.SpringApplication 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(); }
WebApplicationType#deduceFromClasspath 这段代码是用于从类路径中推断出静态的Web应用程序类型的。它通过检查类路径中是否存在特定的类来确定应用程序类型。
首先,它检查是否存在WEBFLUX_INDICATOR_CLASS
类,并且不存在WEBMVC_INDICATOR_CLASS
和JERSEY_INDICATOR_CLASS
类。如果满足这个条件,那么应用程序类型被判断为WebApplicationType.REACTIVE
,表示是一个基于响应式编程模型的Web应用程序。
接下来,它遍历SERVLET_INDICATOR_CLASSES
列表中的类名。如果在类路径中找不到其中任何一个类,那么应用程序类型被判断为WebApplicationType.NONE
,表示不是一个基于Servlet的Web应用程序。
如果以上两个条件都不满足,那么应用程序类型被判断为WebApplicationType.SERVLET
,表示是一个基于Servlet的Web应用程序。
WebApplicationType
是一个枚举类型,用于表示Web应用程序的类型,包括NONE
、SERVLET
和REACTIVE
。
1 2 3 4 5 6 7 8 9 10 11 12 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; }
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 org.springframework.boot.SpringApplication public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch (); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList (); this .configureHeadlessProperty(); SpringApplicationRunListeners listeners = this .getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments (args); ConfigurableEnvironment environment = this .prepareEnvironment(listeners, applicationArguments); this .configureIgnoreBeanInfo(environment); Banner printedBanner = this .printBanner(environment); context = this .createApplicationContext(); exceptionReporters = this .getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class []{ConfigurableApplicationContext.class}, context); this .prepareContext(context, environment, listeners, applicationArguments, printedBanner); this .refreshContext(context); this .afterRefresh(context, applicationArguments); stopWatch.stop(); if (this .logStartupInfo) { (new StartupInfoLogger (this .mainApplicationClass)).logStarted(this .getApplicationLog(), stopWatch); } listeners.started(context); this .callRunners(context, applicationArguments); } catch (Throwable var10) { this .handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException (var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this .handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null ); throw new IllegalStateException (var9); } }
SpringApplication#getRunListeners springAllicationRunListener
是SpringApplication
的run
方法的监听器。springAllicationRunListener
通过springFactoriesLoader
加载,且必须声明一个公共的构造函数,接收SpringApplication
实例和string[]
参数,每次运行时都会创建一个实例。
SpringApplicationRunListener
提供了一系列方法,用户可以通过回调这些方法,在各个启动流程时,加入指定的处理逻辑:
1 2 3 4 5 6 7 private SpringApplicationRunListeners getRunListeners (String[] args) { Class<?>[] types = new Class <?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners (logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this , args)); }
1 2 3 4 SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener > listeners) { this .log = log; this .listeners = new ArrayList <>(listeners); }
SpringApplicationRunListeners
构造方法的第二个参数是集合类型的listeners
,通过调用getSpringFactoriesInstances
获取。
SpringApplicationRunListeners#getSpringFactoriesInstances getSpringFactoriesInstances
是用来获取factories
配置文件中的注册类,并进行实例化操作。
SpringApplicationRunListeners
通过SpringFactoriesLoader
进行加载
1 2 3 4 5 6 7 8 9 10 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; }
SpringApplicationRunListeners#createSpringFactoriesInstances 创建springFactories实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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; }
EventPublishingRunListener EventPublishingRunListener
是springboot
针对springAllicationRunListener
接口内置的唯一实现。
它使用内置的SimpleApplicationEventMulticaster
来广播在上下文刷新之前触发的事件。
默认情况下,Spring Boot
在初始化过程中触发的事件也是交由EventPublishingRunListener
来代理实现的。 其构造方法如下:
1 2 3 4 5 6 7 8 public EventPublishingRunListener (SpringApplication application, String[] args) { this .application = application; this .args = args; this .initialMulticaster = new SimpleApplicationEventMulticaster (); for (ApplicationListener<?> listener : application.getListeners()) { this .initialMulticaster.addApplicationListener(listener); } }
springboot
完成基本初始化之后,会遍历springapplication
的所有applicationListener
实例,并将它们与SimpleApplicationEventMulticaster
进行关联,方便启动过程中将时间传递给所有监听器。
spring事件推送原理
SpringApplication#prepareEnvironment
加载并解析配置文件:在启动过程中,Spring会加载应用程序的配置文件,如application.properties或application.yml。prepareEnvironment方法负责加载这些配置文件,并将其解析为Spring框架内部可以理解的数据结构。
配置环境属性:prepareEnvironment方法还负责配置应用程序的环境属性。这些属性可以通过Environment对象访问,用于在应用程序的不同部分共享配置信息。例如,可以通过环境属性指定数据库连接的URL、用户名和密码等。
配置配置源:prepareEnvironment方法还负责配置Spring框架的配置源。配置源是指Spring框架用于获取配置信息的来源,可以是XML配置文件、注解或Java配置类等。通过配置源,Spring可以了解应用程序的组件定义、依赖关系和其他配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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; }
ConfigFileApplicationListener.onApplicationEvent -> postProcessEnvironment
中加载application.yml
配置 addPropertySources
1 ConfigFileApplicationListener.onApplicationEvent -> postProcessEnvironment
SpringApplication#deduceEnvironmentClass 1 2 3 4 5 6 7 8 9 10 private Class<? extends StandardEnvironment > deduceEnvironmentClass() { switch (this .webApplicationType) { case SERVLET: return StandardServletEnvironment.class; case REACTIVE: return StandardReactiveWebEnvironment.class; default : return StandardEnvironment.class; } }
SpringApplication#getSpringFactoriesInstances 用于从META-INF/spring.factories文件中获取指定类型的所有实现类。在这里,它会获取所有实现了SpringBootExceptionReporter接口的类的实例。
1 2 3 4 5 6 7 8 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; }
SpringApplication#prepareContext
加载应用程序配置文件,包括 application.properties
和 application.yml
。
注册应用程序事件监听器。
解析命令行参数并将其存储在应用程序参数对象中。
打印应用程序启动横幅信息。
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 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); }
SpringApplication#load 加载beans
到应用上下文
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 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(); }
BeanDefinitionLoader#loader.load# 根据不同的源类型加载配置文件
如果源对象是 Class 类型,则调用 load(Class<?> clazz) 方法加载配置文件。
如果源对象是 Resource 类型,则调用 load(Resource resource) 方法加载配置文件。
如果源对象是 Package 类型,则调用 load(Package pkg) 方法加载配置文件。
如果源对象是 CharSequence 类型,则调用 load(CharSequence content) 方法加载配置文件。
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()); }
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 private int load (Class<?> source) { if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); load(loader); } if (isEligible(source)) { this .annotatedReader.register(source); return 1 ; } return 0 ; } public void register (Class<?>... componentClasses) { for (Class<?> componentClass : componentClasses) { registerBean(componentClass); } }
AnnotatedBeanDefinitionReader#doRegisterBean 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 <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
SpringApplication#refreshContext
创建并初始化 BeanFactory:首先,它会创建一个 BeanFactory 对象,用于管理和创建应用程序中的 Bean。
加载 Bean 定义:接下来,它会加载应用程序中定义的 Bean,包括通过注解、XML 配置文件等方式定义的 Bean。
实例化和初始化 Bean:然后,它会实例化和初始化所有的 Bean,包括依赖注入、AOP 代理等操作。
处理 Bean 生命周期回调:在 Bean 实例化和初始化完成后,refresh
方法会调用各个 Bean 的生命周期回调方法,例如 @PostConstruct
注解标注的方法。
注册 Bean 后置处理器:refresh
方法还会注册 Bean 后置处理器,用于在 Bean 初始化前后进行一些额外的处理操作。
通过调用 SpringApplication#refresh
方法,应用程序上下文将完成初始化和刷新,所有的 Bean 将被正确创建和配置,应用程序将进入可用状态,可以响应外部请求。
具体内容我放到另外一篇博文中了springboot源码之启动流程2
1 2 3 4 5 6 7 8 9 10 11 12 private void refreshContext (ConfigurableApplicationContext context) { refresh((ApplicationContext) context); if (this .registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { } } }
SpringApplication#callRunners spring callRunners(context, applicationArguments)
是 Spring Boot 中的一个方法,用于执行在应用程序启动时需要运行的 ApplicationRunner
和 CommandLineRunner
接口的实现类。
在 Spring Boot 应用程序启动时,可以通过实现 ApplicationRunner
或 CommandLineRunner
接口来定义一些需要在应用程序启动后立即执行的逻辑。这些逻辑可以包括初始化数据、加载配置、启动定时任务等。
callRunners(context, applicationArguments)
方法会在 Spring Boot 应用程序启动时被调用,它会获取所有实现了 ApplicationRunner
和 CommandLineRunner
接口的 Bean,并按照优先级顺序依次执行它们的 run
方法。通过调用这些方法,可以在应用程序启动时执行一些自定义的逻辑。
context
参数是 Spring 应用程序的上下文,它包含了应用程序中所有的 Bean。applicationArguments
参数是应用程序的命令行参数,可以通过它获取命令行传递的参数值
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); } } }
environment的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 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 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry @Nullable protected Object getSingleton (String beanName, boolean allowEarlyReference) { Object singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this .singletonObjects) { singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null ) { ObjectFactory<?> singletonFactory = this .singletonFactories.get(beanName); if (singletonFactory != null ) { singletonObject = singletonFactory.getObject(); this .earlySingletonObjects.put(beanName, singletonObject); this .singletonFactories.remove(beanName); } } } } } } return singletonObject; }
引用 1. spring三级缓存 2. springbean装配过程 3. Spring 的 InstantiationAware 后处理器 4. 为什么JDK动态代理只能代理接口,不能直接代理类?CGlib为什么可以代理类? 5. SpringBoot的启动流程