「SpringBoot」09 原理解析

SpringBoot——原理解析

笔记整理自【尚硅谷】雷神SpringBoot2视频教程

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.factoriesApplicationContextInitializer

    List<ApplicationContextInitializer<?>> initializers
    

    image-20220727211833347

  • ApplicationListener (应用监听器);去spring.factoriesApplicationListener

    List<ApplicationListener<?>> listeners
    

    image-20220727212256954

  • 创建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.factoriesSpringApplicationRunListener

    image-20220728105312800

    image-20220728105552786

  • 遍历 SpringApplicationRunListener 调用 starting() 方法;

    相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。

  • 保存命令行参数:ApplicationArguments

  • 准备环境 prepareEnvironment()

    ➢ 返回或者创建基础环境信息对象:StandardServletEnvironment

    ➢ 配置环境信息对象。

    ​ ◽️ 读取所有的配置源的配置属性值。

    ➢ 绑定环境信息

    ➢ 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
  • 创建IOC容器(createApplicationContext())

    ➢ 根据项目类型(Servlet)创建容器

    ➢ 当前会创建 AnnotationConfigServletWebServerApplicationContext

  • 准备ApplicationContext IOC容器的基本信息 prepareContext()

    ➢ 保存环境信息IOC容器的后置处理流程

    ➢ 应用初始化器:applyInitializers

    ◽️ 遍历所有的 ApplicationContextInitializer,调用 initialize()。来对IOC容器进行初始化扩展功能

    image-20220728112147776

    image-20220728112657577

    ➢ 所有的监听器 调用 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);
    }
    

Application Events and Listeners

ApplicationRunner 与CommandLineRunner

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....");
        }
    }
    
  • 注册MyApplicationContextInitializerMyApplicationListenerMySpringApplicationRunListener

    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
    

    image-20220728191459394

完结撒花✿✿ヽ(°▽°)ノ✿ 感谢雷神,后会有期!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小成同学_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值