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;
          }
       }
    }
    
  • 相关阅读:
    easyUI的汇总列,在前端生成
    return返回两个三元表达式的和,返回不正确,同样要注意在JavaScript中,也是如此
    清除浮动有哪些方式?比较好的方式是哪一种?
    浏览器重置样式
    MUI框架的缩写输入
    会自动消失的提示信息
    JSON.stringify转化报错
    Jquery on方法绑定事件后执行多次
    属性索引选择元素
    字符串赋值数字时的问题
  • 原文地址:https://www.cnblogs.com/chinda/p/14308610.html
Copyright © 2011-2022 走看看