zoukankan      html  css  js  c++  java
  • SpringBoot源码学习(二) 发布启动事件

    运行Spring应用程序

    public ConfigurableApplicationContext run(String... args) {
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
       // 配置无头属性, 设置该应用程序即使没有检测到显示器也允许启动
       configureHeadlessProperty();
       // 从`META-INF/spring.factories`文件集中获取SpringApplicationRunListener的子类listener
       SpringApplicationRunListeners listeners = getRunListeners(args);
       // 开启事件监听,通知监听者们(listener)执行相应操作
       listeners.starting();
       try {
          // 封装命令行参数
          ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
          // 准备环境
          ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
          // 配置忽略信息
          configureIgnoreBeanInfo(environment);
          // 打印banner
          Banner printedBanner = printBanner(environment);
          // 创建应用上下文
          context = createApplicationContext();
          // 从`META-INF/spring.factories`文件集中获取SpringBootExceptionReporter的子类
          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;
    }
    

    获取监听器

    调用getRunListeners(args)方法,实例化一个SpringApplicationRunListeners对象。 通过getSpringFactoriesInstances方法读取META-INF/spring.factories进而实例化EventPublishingRunListener

    /**
     * 从`META-INF/spring.factories`文件集中获取SpringApplicationRunListener的子类listener
     * @param args 命令行参数
     * @return
     */
    private SpringApplicationRunListeners getRunListeners(String[] args) {
       Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
       // 实例化观察模式的目标类, 在实例化时绑定监听器(SpringApplicationRunListener子类)
       return new SpringApplicationRunListeners(logger,
             getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
    
    org.springframework.boot.SpringApplicationRunListener=
    org.springframework.boot.context.event.EventPublishingRunListener
    

    注意: getSpringFactoriesInstances参数中的this,此方法将SpringApplication本身也传递过去了。

    EventPublishingRunListener初始化

    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
          ClassLoader classLoader, Object[] args, Set<String> names) {
       List<T> instances = new ArrayList<>(names.size());
       // 此时`names`只有`org.springframework.boot.context.event.EventPublishingRunListener`一个元素
       for (String name : names) {
          try {
             Class<?> instanceClass = ClassUtils.forName(name, classLoader);
             Assert.isAssignable(type, instanceClass);
             // 行参parameterTypes此时为`new Class<?>[] { SpringApplication.class, String[].class }`
             Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
             // 实参此时为 `this, args`,this为SpringApplication实例, args为命令行参数
             T instance = (T) BeanUtils.instantiateClass(constructor, args);
             instances.add(instance);
          }
          catch (Throwable ex) {
             throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
          }
       }
       return instances;
    }
    

    调用getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)通过反射实例化EventPublishingRunListener

    EventPublishingRunListener实例化

    public EventPublishingRunListener(SpringApplication application, String[] args) {
       this.application = application;
       // 命令行参数
       this.args = args;
       // 事件多播器
       this.initialMulticaster = new SimpleApplicationEventMulticaster();
       /**
        * org.springframework.boot.devtools.restart.RestartApplicationListener,
        * org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,
        * org.springframework.boot.context.config.ConfigFileApplicationListener,
        * org.springframework.boot.context.config.AnsiOutputApplicationListener,
        * org.springframework.boot.context.logging.LoggingApplicationListener,
        * org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,
        * org.springframework.boot.autoconfigure.BackgroundPreinitializer,
        * org.springframework.boot.context.config.DelegatingApplicationListener,
        * org.springframework.boot.builder.ParentContextCloserApplicationListener,
        * org.springframework.boot.devtools.logger.DevToolsLogFactory$Listener,
        * org.springframework.boot.ClearCachesApplicationListener,
        * org.springframework.boot.context.FileEncodingApplicationListener,
        * org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
        */
       for (ApplicationListener<?> listener : application.getListeners()) {
          this.initialMulticaster.addApplicationListener(listener);
       }
    }
    

    依赖关系图谱

    SimpleApplicationEventMulticaster

    SimpleApplicationEventMulticaster实例化

    此源码为AbstractApplicationEventMulticaster中方法。

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
       synchronized (this.defaultRetriever) {
          // Explicitly remove target for a proxy, if registered already,
          // in order to avoid double invocations of the same listener.
          // 删除代理的目标(如果已注册),以避免重复调用同一侦听器,暂时没有发现有哪个监听器符合条件
          Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
          if (singletonTarget instanceof ApplicationListener) {
             this.defaultRetriever.applicationListeners.remove(singletonTarget);
          }
           
          // 添加目标 
          this.defaultRetriever.applicationListeners.add(listener);
          // 清理检索缓存 
          this.retrieverCache.clear();
       }
    }
    

    启动监听器

    listeners.starting();

    void starting() {
       // org.springframework.boot.context.event.EventPublishingRunListener
       for (SpringApplicationRunListener listener : this.listeners) {
          listener.starting();
       }
    }
    

    调用EventPublishingRunListener中的starting()方法。

    @Override
    public void starting() {
       // 构造EventObject事件, source为application并广播事件,通知各个监听器
       this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    

    广播Event

    @Override
    public void multicastEvent(ApplicationEvent event) {
       // 过滤监听器,为其广播事件。resolveDefaultEventType(event)除了`org.springframework.http.client.PublisherEntity`和`org.springframework.context.PayloadApplicationEvent`其余返回new ResolvableType(clazz)
       multicastEvent(event, resolveDefaultEventType(event));
    }
    
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
       ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
       Executor executor = getTaskExecutor();
       /**
        * 返回与给定事件类型匹配的ApplicationListeners的集合。不匹配的监听器会被排除在外。
        * org.springframework.boot.devtools.restart.RestartApplicationListener,
        * org.springframework.boot.context.logging.LoggingApplicationListener,
        * org.springframework.boot.autoconfigure.BackgroundPreinitializer,
        * org.springframework.boot.context.config.DelegatingApplicationListener,
        * org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
        */
       for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
          if (executor != null) {
             executor.execute(() -> invokeListener(listener, event));
          }
          else {
             // 用给定的事件调用给定的监听器。
             invokeListener(listener, event);
          }
       }
    }
    
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
       ErrorHandler errorHandler = getErrorHandler();
       if (errorHandler != null) {
          try {
             doInvokeListener(listener, event);
          }
          catch (Throwable err) {
             errorHandler.handleError(err);
          }
       }
       else {
          doInvokeListener(listener, event);
       }
    }
    
    @SuppressWarnings({"rawtypes", "unchecked"})
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
       try {
          listener.onApplicationEvent(event);
       }
       catch (ClassCastException ex) {
          String msg = ex.getMessage();
          if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
             // Possibly a lambda-defined listener which we could not resolve the generic event type for
             // -> let's suppress the exception and just log a debug message.
             Log logger = LogFactory.getLog(getClass());
             if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, ex);
             }
          }
          else {
             throw ex;
          }
       }
    }
    
  • 相关阅读:
    jackson 枚举 enum json 解析类型 返回数字 或者自定义文字 How To Serialize Enums as JSON Objects with Jackson
    Antd Pro V5 中ProTable 自定义查询参数和返回值
    ES6/Antd 代码阅读记录
    es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?
    Antd Hooks
    使用.Net Core开发WPF App系列教程(其它 、保存控件内容为图片)
    使用.Net Core开发WPF App系列教程( 三、与.Net Framework的区别)
    使用.Net Core开发WPF App系列教程( 四、WPF中的XAML)
    使用.Net Core开发WPF App系列教程( 二、在Visual Studio 2019中创建.Net Core WPF工程)
    使用.Net Core开发WPF App系列教程( 一、.Net Core和WPF介绍)
  • 原文地址:https://www.cnblogs.com/chinda/p/14308610.html
Copyright © 2011-2022 走看看