SpringBoot——原理解析
Spring原理、SpringMVC原理、自动配置原理、SpringBoot原理。
1. SpringBoot启动过程
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
} // ↑ 创建SpringApplication ↑ 运行SpringApplication
组件用黄色的高光标识
组件介入的各个时机的调用用青蓝色背景标识(只在 运行 SpringApplication中有)
1️⃣ 创建 SpringApplication
保存一些信息。
判定当前应用的类型 => ClassUtils:Servlet。
WebApplicationType类
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; // 返回SERVLET编程类型 }
bootstrappers:
初始启动引导器(List<Bootstrapper>)
:去spring.factories
文件中找org.springframework.boot.Bootstrapper找 ApplicationContextInitializer(初始化器);去
spring.factories
找 ApplicationContextInitializerList<ApplicationContextInitializer<?>> initializers
找 ApplicationListener (应用监听器);去
spring.factories
找 ApplicationListenerList<ApplicationListener<?>> listeners
创建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)); // WebApplicationType是枚举类 有NONE,SERVLET,REACTIVE 下行webApplicationType是SERVLET this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 初始启动引导器 去spring.factories文件中找org.springframework.boot.Bootstrapper 但我找不到实现Bootstrapper接口的类 this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class)); // 去spring.factories找 ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 去spring.factories找 ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); // 决定哪个类是我们的主程序 } // ↓ private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { // 哪个类有main方法 被找到的第1个类就是主程序类 if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
简单来说,应用创建的过程就是把一些关键的组件信息读取并保存到SpringApplication中,作为运行SpringApplication的前置工作。
2️⃣ 运行 SpringApplication
StopWatch
记录应用的启动时间
创建引导上下文(Context环境)
createBootstrapContext()
➢ 获取到所有之前的 bootstrappers 挨个执行 intitialize()方法 来完成对引导启动器上下文环境设置 public interface Bootstrapper { /** * Initialize the given {@link BootstrapRegistry} with any required registrations. * @param registry the registry to initialize */ void intitialize(BootstrapRegistry registry); }
让当前应用进入headless模式(自力更生模式)
java.awt.headless
获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】
➢
getSpringFactoriesInstances()
去spring.factories
找 SpringApplicationRunListener-
遍历 SpringApplicationRunListener 调用 starting() 方法; ➢ 相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
保存命令行参数:
ApplicationArguments
准备环境
prepareEnvironment()
➢ 返回或者创建基础环境信息对象:
StandardServletEnvironment
➢ 配置环境信息对象。
◽️ 读取所有的配置源的配置属性值。
➢ 绑定环境信息
➢ 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成 创建IOC容器
(createApplicationContext())
➢ 根据项目类型(Servlet)创建容器
➢ 当前会创建
AnnotationConfigServletWebServerApplicationContext
准备ApplicationContext IOC容器的基本信息
prepareContext()
➢ 保存环境信息IOC容器的后置处理流程
➢ 应用初始化器:
applyInitializers
;◽️ 遍历所有的 ApplicationContextInitializer,调用 initialize()。来对IOC容器进行初始化扩展功能 ➢ 所有的监听器 调用 contextLoaded();通知所有的监听器 contextLoaded:IOC容器已经加载完成 刷新IOC容器:
refreshContext()
➢ 创建容器中的所有组件
// Instantiate all remaining (non-lazy-init) singletons. 使用单例模式 实例化所有剩余的(非延迟初始化)组件。 finishBeanFactoryInitialization(beanFactory);
容器刷新完成后工作
afterRefresh()
-
所有监听器 调用 listeners.started(context); 通知所有的监听器started 调用所有runners;
callRunners()
➢ 获取容器中的 ApplicationRunner
@FunctionalInterface public interface ApplicationRunner { /** * Callback used to run the bean. * @param args incoming application arguments * @throws Exception on error */ void run(ApplicationArguments args) throws Exception; }
➢ 获取容器中的 CommandLineRunner
@FunctionalInterface public interface CommandLineRunner { /** * Callback used to run the bean. * @param args incoming main method arguments * @throws Exception on error */ void run(String... args) throws Exception; }
➢ 合并所有runner并且按照
@Order
进行排序➢ 遍历所有的runner,调用 run() 方法 如果以上有异常,
➢ 调用Listener 的 failed() 方法 -
调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running -
running如果有问题,继续通知 failed,调用所有 Listener 的 failed;通知所有的监听器 failed 最终返回IOC容器
return context
运行SpringApplication 完整代码
// run()方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch();//开始计时器 stopWatch.start();//开始计时 // 1. // 创建引导上下文(Context环境)createBootstrapContext() // 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); // 2.到最后该方法会返回这context ConfigurableApplicationContext context = null; // 3.让当前应用进入headless模式 configureHeadlessProperty(); // 4.获取所有 RunListener(运行监听器)为了方便所有Listener进行事件感知 SpringApplicationRunListeners listeners = getRunListeners(args); // 5. 遍历 SpringApplicationRunListener 调用starting方法 // 相当于通知所有感兴趣系统正在启动过程的人 项目正在starting listeners.starting(bootstrapContext, this.mainApplicationClass); try { // 6.保存命令行参数 ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 7.准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); /* 打印标志 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.2) */ Banner printedBanner = printBanner(environment); // 创建IOC容器(createApplicationContext()) // 根据项目类型webApplicationType(NONE,SERVLET,REACTIVE)创建容器, // 当前会创建 AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 8.准备ApplicationContext IOC容器的基本信息 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 9.刷新IOC容器 创建容器中的所有组件 Spring框架的内容 refreshContext(context); // 该方法没内容,大概为将来填入 afterRefresh(context, applicationArguments); stopWatch.stop(); // 停止计时 if (this.logStartupInfo) { // this.logStartupInfo默认是true new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 10. listeners.started(context); // 11.调用所有runners callRunners(context, applicationArguments); } catch (Throwable ex) { // 13. handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { // 12. listeners.running(context); } catch (Throwable ex) { // 13. handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
// 1. private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext)); return bootstrapContext; } // 3. private void configureHeadlessProperty() { // this.headless默认为true System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); } private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless"; // 4. private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; //getSpringFactoriesInstances 去 spring.factories 找 SpringApplicationRunListener return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); } // 7.准备环境 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment // 返回或者创建基础环境信息对象 如:StandardServletEnvironment, StandardReactiveWebEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置环境信息对象,读取所有的配置源的配置属性值。 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 绑定环境信息 ConfigurationPropertySources.attach(environment); // 7.1 通知所有的监听器当前环境准备完成 listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); configureAdditionalProfiles(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; } // 8. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 保存环境信息 context.setEnvironment(environment); // IOC容器的后置处理流程 postProcessApplicationContext(context); // 应用初始化器 applyInitializers(context); // 8.1 遍历所有的 listener 调用 contextPrepared // EventPublishRunListenr通知所有的监听器contextPrepared listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans 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()); } // Load the sources Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); // 8.2 listeners.contextLoaded(context); } // 11.调用所有runners private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); // 获取容器中的 ApplicationRunner runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); // 获取容器中的 CommandLineRunner runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); // 合并所有runner并且按照@Order进行排序 AnnotationAwareOrderComparator.sort(runners); // 遍历所有的runner 调用 run() 方法 for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } } // 13. private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, SpringApplicationRunListeners listeners) { try { try { handleExitCode(context, exception); if (listeners != null) { //14. listeners.failed(context, exception); } } finally { reportFailure(getExceptionReporters(context), exception); if (context != null) { context.close(); } } } catch (Exception ex) { logger.warn("Unable to close ApplicationContext", ex); } ReflectionUtils.rethrowRuntimeException(exception); }
2. 自定义事件监听组件
自定义上方高光的五个组件
MyApplicationContextInitializer
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; public class MyApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("MyApplicationContextInitializer ....initialize.... "); } }
MyApplicationListener
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; public class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("MyApplicationListener.....onApplicationEvent..."); } }
MySpringApplicationRunListener
import org.springframework.boot.ConfigurableBootstrapContext; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationRunListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; public class MySpringApplicationRunListener implements SpringApplicationRunListener { private SpringApplication application; public MySpringApplicationRunListener(SpringApplication application, String[] args){ this.application = application; } @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { System.out.println("MySpringApplicationRunListener....starting...."); } @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { System.out.println("MySpringApplicationRunListener....environmentPrepared...."); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("MySpringApplicationRunListener....contextPrepared...."); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("MySpringApplicationRunListener....contextLoaded...."); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("MySpringApplicationRunListener....started...."); } @Override public void running(ConfigurableApplicationContext context) { System.out.println("MySpringApplicationRunListener....running...."); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("MySpringApplicationRunListener....failed...."); } }
MyApplicationRunner
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Order(1) // 按照Order排序 数字越大优先级越高 @Component // 放入容器 public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("MyApplicationRunner...run..."); } }
MyCommandLineRunner
import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 应用启动做一个一次性事情 */ @Order(2) // 按照Order排序 @Component // 放入容器 public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("MyCommandLineRunner....run...."); } }
注册
MyApplicationContextInitializer
,MyApplicationListener
,MySpringApplicationRunListener
resources/META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\ com.atguigu.boot.listener.MyApplicationContextInitializer org.springframework.context.ApplicationListener=\ com.atguigu.boot.listener.MyApplicationListener org.springframework.boot.SpringApplicationRunListener=\ com.atguigu.boot.listener.MySpringApplicationRunListener
完结撒花✿✿ヽ(°▽°)ノ✿ 感谢雷神,后会有期!