天天看点

spring boot 源码_springboot源码架构解析listener

说在前面

前期回顾

sharding-jdbc源码解析 更新完毕

spring源码解析 更新完毕

spring-mvc源码解析 更新完毕

spring-tx源码解析 更新完毕

spring-boot源码解析 更新完毕

rocketmq源码解析 更新完毕

dubbbo源码解析 更新完毕

netty源码解析 更新完毕

spring源码架构更新完毕

spring-mvc源码架构更新完毕

springboot源码架构更新中

github https://github.com/tianheframe

sharding-jdbc源码解析 更新完毕

rocketmq源码解析 更新完毕

seata 源码解析 更新完毕

dubbo 源码解析 更新完毕

netty 源码解析 更新完毕

源码解析

spring boot 源码_springboot源码架构解析listener

org.springframework.boot.SpringApplicationRunListener 用于SpringApplication run方法的侦听器。springapplicationrunlistener是通过SpringFactoriesLoader加载的,它应该声明一个公共构造函数来接受一个SpringApplication实例和一个参数字符串[]。每次运行都将创建一个新的SpringApplicationRunListener实例。

void starting();
           

在run方法首次启动时立即调用。可以用于非常早期的初始化。

void environmentPrepared(ConfigurableEnvironment environment);
           

在准备好环境之后,但在创建ApplicationContext之前调用。

void contextPrepared(ConfigurableApplicationContext context);
           

在创建和准备ApplicationContext之后调用,但在加载源之前调用。

void contextLoaded(ConfigurableApplicationContext context);
           

在加载应用程序上下文之后调用,但在刷新应用程序上下文之前调用。

void finished(ConfigurableApplicationContext context, Throwable exception);
           

在运行方法结束之前立即调用。

org.springframework.boot.context.event.EventPublishingRunListener SpringApplicationRunListener来发布SpringApplicationEvents。

 为在实际刷新上下文之前触发的事件使用内部ApplicationEventMulticaster。

private final SpringApplication application;
           

application

private final SimpleApplicationEventMulticaster initialMulticaster;
           

initialMulticaster

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);    }  }
           

添加ApplicationListener

public void starting() {    this.initialMulticaster        .multicastEvent(new ApplicationStartedEvent(this.application, this.args));  }
           

发布ApplicationStartedEvent

@Override  public void environmentPrepared(ConfigurableEnvironment environment) {    this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(        this.application, this.args, environment));  }
           

发布ApplicationEnvironmentPreparedEvent

@Override  public void contextLoaded(ConfigurableApplicationContext context) {    for (ApplicationListener> listener : this.application.getListeners()) {      if (listener instanceof ApplicationContextAware) {        ((ApplicationContextAware) listener).setApplicationContext(context);      }      context.addApplicationListener(listener);    }    this.initialMulticaster.multicastEvent(        new ApplicationPreparedEvent(this.application, this.args, context));  }
           

添加listener,发布ApplicationPreparedEvent

@Override  public void finished(ConfigurableApplicationContext context, Throwable exception) {    SpringApplicationEvent event = getFinishedEvent(context, exception);    if (context != null && context.isActive()) {      // Listeners have been registered to the application context so we should 侦听器已经注册到应用程序上下文,因此我们应该这样做      // use it at this point if we can 如果可以的话,现在就用它      context.publishEvent(event);    }    else {      // An inactive context may not have a multicaster so we use our multicaster to 非活动上下文可能没有多播程序,因此我们使用多播程序      // call all of the context's listeners instead 而是调用上下文的所有侦听器      if (context instanceof AbstractApplicationContext) {        for (ApplicationListener> listener : ((AbstractApplicationContext) context)            .getApplicationListeners()) {          this.initialMulticaster.addApplicationListener(listener);        }      }      if (event instanceof ApplicationFailedEvent) {        this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());      }      this.initialMulticaster.multicastEvent(event);    }  }
           

发布ApplicationFailedEvent、ApplicationReadyEvent事件

private SpringApplicationEvent getFinishedEvent(      ConfigurableApplicationContext context, Throwable exception) {    if (exception != null) {      return new ApplicationFailedEvent(this.application, this.args, context,          exception);    }    return new ApplicationReadyEvent(this.application, this.args, context);  }
           

获得完成事件

org.springframework.boot.builder.ParentContextCloserApplicationListener 侦听器,如果其父应用程序上下文已关闭,则该侦听器将关闭该应用程序上下文。它侦听refresh事件并从中获取当前上下文,然后侦听关闭事件并将其传播到层次结构中。

实现org.springframework.context.ApplicationContextAware接口。

private ApplicationContext context;
           

ApplicationContext

@Override  public void setApplicationContext(ApplicationContext context) throws BeansException {    this.context = context;  }
           

重写org.springframework.context.ApplicationContextAware#setApplicationContext方法,设置ApplicationContext

@Override  public void onApplicationEvent(ParentContextAvailableEvent event) {    maybeInstallListenerInParent(event.getApplicationContext());  }
           

org.springframework.boot.builder.ParentContextCloserApplicationListener#maybeInstallListenerInParent

private void maybeInstallListenerInParent(ConfigurableApplicationContext child) {    if (child == this.context) {      if (child.getParent() instanceof ConfigurableApplicationContext) {        ConfigurableApplicationContext parent = (ConfigurableApplicationContext) child            .getParent();        parent.addApplicationListener(createContextCloserListener(child));      }    }  }
           

org.springframework.boot.builder.ParentContextCloserApplicationListener#createContextCloserListener 子类可以覆盖它来创建自己的ContextCloserListener子类。这仍然强制使用弱引用。

protected ContextCloserListener createContextCloserListener(      ConfigurableApplicationContext child) {    return new ContextCloserListener(child);  }
           

org.springframework.boot.context.FileEncodingApplicationListener 如果系统文件编码与环境中设置的期望值不匹配,应用程序侦听器将暂停应用程序启动。默认情况下没有效果,但是如果您设置spring。mandatory_file_encoding(或它的某些驼峰大小写或大写变体)到字符编码的名称(例如。然后这个初始化器在文件中抛出一个异常。编码系统属性不等于它。系统属性文件。编码通常由JVM设置,以响应LANG或LC_ALL环境变量。它(与其他依赖于平台的变量一起键入这些环境变量)用于编码JVM参数以及文件名和路径。在大多数情况下,您可以在命令行上覆盖文件编码系统属性(使用标准JVM特性),但也可以考虑将LANG环境变量设置为显式的字符编码值(例如。“en_GB.UTF-8”)。

org.springframework.boot.ClearCachesApplicationListener 清空缓存的ApplicationListener

org.springframework.boot.SpringApplicationRunListeners SpringApplicationRunListener的集合

private final List listeners;
           

listeners

public void starting() {    for (SpringApplicationRunListener listener : this.listeners) {      listener.starting();    }  }
           

执行监听器的启动方法

public void environmentPrepared(ConfigurableEnvironment environment) {    for (SpringApplicationRunListener listener : this.listeners) {      listener.environmentPrepared(environment);    }  }
           

执行监听器的环境准备方法

public void contextPrepared(ConfigurableApplicationContext context) {    for (SpringApplicationRunListener listener : this.listeners) {      listener.contextPrepared(context);    }  }
           

执行监听器的上下文准备方法

public void contextLoaded(ConfigurableApplicationContext context) {    for (SpringApplicationRunListener listener : this.listeners) {      listener.contextLoaded(context);    }  }
           

执行上下文的加载方法

public void finished(ConfigurableApplicationContext context, Throwable exception) {    for (SpringApplicationRunListener listener : this.listeners) {      callFinishedListener(listener, context, exception);    }  }
           

org.springframework.boot.SpringApplicationRunListeners#callFinishedListener

private void callFinishedListener(SpringApplicationRunListener listener,      ConfigurableApplicationContext context, Throwable exception) {    try {      listener.finished(context, exception);    }    catch (Throwable ex) {      if (exception == null) {        ReflectionUtils.rethrowRuntimeException(ex);      }      if (this.log.isDebugEnabled()) {        this.log.error("Error handling failed", ex);      }      else {        String message = ex.getMessage();        message = (message != null) ? message : "no error message";        this.log.warn("Error handling failed (" + message + ")");      }    }  }
           

执行监听器的完成方法

org.springframework.boot.context.config.DelegatingApplicationListener 将委托给在context.listener下指定的其他侦听器的ApplicationListener。类环境属性。

private SimpleApplicationEventMulticaster multicaster;
           

multicaster

@Override  public void onApplicationEvent(ApplicationEvent event) {    if (event instanceof ApplicationEnvironmentPreparedEvent) {      List> delegates = getListeners(          ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());      if (delegates.isEmpty()) {        return;      }      this.multicaster = new SimpleApplicationEventMulticaster();      for (ApplicationListener listener : delegates) {        this.multicaster.addApplicationListener(listener);      }    }    if (this.multicaster != null) {      this.multicaster.multicastEvent(event);    }  }
           

添加监听器,发布事件

private List> getListeners(      ConfigurableEnvironment environment) {    if (environment == null) {      return Collections.emptyList();    }//    查找监听器的类context.listener.classes    String classNames = environment.getProperty(PROPERTY_NAME);    List> listeners = new ArrayList>();    if (StringUtils.hasLength(classNames)) {      for (String className : StringUtils.commaDelimitedListToSet(classNames)) {        try {          Class> clazz = ClassUtils.forName(className,              ClassUtils.getDefaultClassLoader());          Assert.isAssignable(ApplicationListener.class, clazz, "class ["              + className + "] must implement ApplicationListener");          listeners.add((ApplicationListener) BeanUtils              .instantiateClass(clazz));        }        catch (Exception ex) {          throw new ApplicationContextException(              "Failed to load context listener class [" + className + "]",              ex);        }      }    }    AnnotationAwareOrderComparator.sort(listeners);    return listeners;  }
           

加载属性文件context.listener.classes属性指定的监听器类并初始化。

org.springframework.boot.context.config.ConfigFileApplicationListener EnvironmentPostProcessor 它通过从众所周知的文件位置加载属性来配置上下文环境。默认情况下,属性将从application.properties、application.yml文件在以下位置

classpath:

file:./

classpath:config/

file:./config/:

可以使用setSearchLocations(字符串)和setSearchNames(字符串)指定其他搜索位置和名称。

其他文件也将基于活动配置文件加载。例如,如果'web'配置文件是活跃的application-web.properties、application-web.yml将被考虑。

spring.config.name属性可用于指定要加载的替代名称和,spring.config.location属性可用于指定其他搜索位置或特定文件。

配置属性也绑定到SpringApplication。这使得动态设置SpringApplication属性成为可能,就像源一样 ("spring.main.sources" - a CSV list) 指示web环境的标志 ("spring.main.web_environment=true") 或者把旗帜关掉("spring.main.show_banner=false").

private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
           

配置文件名前缀

private static final String DEFAULT_NAMES = "application";
           

默认配置文件名

public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
           

激活的文件名

public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
           

引用的配置文件名

public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
           

配置文件名

public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
           

配置文件路径

private final ConversionService conversionService = new DefaultConversionService();
           

conversionService

@Override  public boolean supportsEventType(Class extends ApplicationEvent> eventType) {    return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)        || ApplicationPreparedEvent.class.isAssignableFrom(eventType);  }
           

支持ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent事件

@Override  public void onApplicationEvent(ApplicationEvent event) {    if (event instanceof ApplicationEnvironmentPreparedEvent) {      onApplicationEnvironmentPreparedEvent(          (ApplicationEnvironmentPreparedEvent) event);    }    if (event instanceof ApplicationPreparedEvent) {      onApplicationPreparedEvent(event);    }  }
           

org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent

private void onApplicationEnvironmentPreparedEvent(      ApplicationEnvironmentPreparedEvent event) {//    加载EnvironmentPostProcessor    List postProcessors = loadPostProcessors();    postProcessors.add(this);    AnnotationAwareOrderComparator.sort(postProcessors);    for (EnvironmentPostProcessor postProcessor : postProcessors) {//      加载org.springframework.boot.env.EnvironmentPostProcessor.postProcessEnvironment()方法      postProcessor.postProcessEnvironment(event.getEnvironment(),          event.getSpringApplication());    }  }
           

加载EnvironmentPostProcessor,执行org.springframework.boot.env.EnvironmentPostProcessor.postProcessEnvironment()方法,org.springframework.boot.context.config.ConfigFileApplicationListener#loadPostProcessors

List loadPostProcessors() {    return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,        getClass().getClassLoader());  }
           

从BeanFactory中加载EnvironmentPostProcessor

org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationPreparedEvent

private void onApplicationPreparedEvent(ApplicationEvent event) {    this.logger.replayTo(ConfigFileApplicationListener.class);//    添加PropertySourceOrderingPostProcessor    addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());  }
           
protected void bindToSpringApplication(ConfigurableEnvironment environment,      SpringApplication application) {    PropertiesConfigurationFactory binder = new PropertiesConfigurationFactory(        application);    binder.setTargetName("spring.main");//    设置conversionService    binder.setConversionService(this.conversionService);    binder.setPropertySources(environment.getPropertySources());    try {//      绑定属性      binder.bindPropertiesToTarget();    }    catch (BindException ex) {      throw new IllegalStateException("Cannot bind to SpringApplication", ex);    }  }
           

org.springframework.boot.bind.PropertiesConfigurationFactory#bindPropertiesToTarget

public void bindPropertiesToTarget() throws BindException {    Assert.state(this.propertySources != null, "PropertySources should not be null");    try {      if (logger.isTraceEnabled()) {        logger.trace("Property Sources: " + this.propertySources);      }      this.hasBeenBound = true;      doBindPropertiesToTarget();    }    catch (BindException ex) {      if (this.exceptionIfInvalid) {        throw ex;      }      PropertiesConfigurationFactory.logger          .error("Failed to load Properties validation bean. "              + "Your Properties may be invalid.", ex);    }  }
           

org.springframework.boot.bind.PropertiesConfigurationFactory#doBindPropertiesToTarget

private void doBindPropertiesToTarget() throws BindException {    RelaxedDataBinder dataBinder = (this.targetName != null)        ? new RelaxedDataBinder(this.target, this.targetName)        : new RelaxedDataBinder(this.target);    if (this.validator != null        && this.validator.supports(dataBinder.getTarget().getClass())) {      dataBinder.setValidator(this.validator);    }    if (this.conversionService != null) {//      设置conversionService      dataBinder.setConversionService(this.conversionService);    }    dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);    dataBinder.setIgnoreNestedProperties(this.ignoreNestedProperties);    dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);    dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);    customizeBinder(dataBinder);    if (this.applicationContext != null) {      ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar(          this.applicationContext, this.applicationContext.getEnvironment());//      注册定制的属性修改器      resourceEditorRegistrar.registerCustomEditors(dataBinder);    }    Iterable relaxedTargetNames = getRelaxedTargetNames();    Set names = getNames(relaxedTargetNames);    PropertyValues propertyValues = getPropertySourcesPropertyValues(names,        relaxedTargetNames);    dataBinder.bind(propertyValues);    if (this.validator != null) {//      验证属性      dataBinder.validate();    }//    检查绑定的参数错误    checkForBindingErrors(dataBinder);  }
           

org.springframework.boot.context.config.ConfigFileApplicationListener.PropertySourceOrderingPostProcessor 实现org.springframework.beans.factory.config.BeanFactoryPostProcessor接口,覆盖BeanFactory中属性

private ConfigurableApplicationContext context;
           

context

@Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)        throws BeansException {      reorderSources(this.context.getEnvironment());    }
           

重写org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory接口,覆盖属性

@Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)        throws BeansException {      reorderSources(this.context.getEnvironment());    }
           

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader 加载激活的配置文件

private Queue profiles;
           

激活的待处理的配置文件

private List processedProfiles;
           

处理过的配置文件

public void load() {      this.propertiesLoader = new PropertySourcesLoader();      this.activatedProfiles = false;      this.profiles = Collections.asLifoQueue(new LinkedList());      this.processedProfiles = new LinkedList();      // Pre-existing active profiles set via Environment.setActiveProfiles() 通过Environment.setActiveProfiles()设置预先存在的活动概要文件      // are additional profiles and config files are allowed to add more if 是否允许添加更多的配置文件和配置文件      // they want to, so don't call addActiveProfiles() here. 它们想这样做,所以这里不要调用addActiveProfiles()。      Set initialActiveProfiles = initializeActiveProfiles();      this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));      if (this.profiles.isEmpty()) {        for (String defaultProfileName : this.environment.getDefaultProfiles()) {          Profile defaultProfile = new Profile(defaultProfileName, true);          if (!this.profiles.contains(defaultProfile)) {            this.profiles.add(defaultProfile);          }        }      }      // The default profile for these purposes is represented as null. We add it      // last so that it is first out of the queue (active profiles will then      // override any settings in the defaults when the list is reversed later).//这些用途的默认配置文件表示为null。我们添加它// last,以便它首先离开队列(然后活动配置文件将离开队列)//稍后列表反转时,覆盖默认设置中的任何设置)。      this.profiles.add(null);      while (!this.profiles.isEmpty()) {        Profile profile = this.profiles.poll();//        加载location类型的配置文件        for (String location : getSearchLocations()) {          if (!location.endsWith("/")) {            // location is a filename already, so don't search for more            // filenames            load(location, null, profile);          }          else {            for (String name : getSearchNames()) {              load(location, name, profile);            }          }        }        this.processedProfiles.add(profile);      }      addConfigurationProperties(this.propertiesLoader.getPropertySources());    }
           

加载配置文件,org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#initializeActiveProfiles 初始化激活的配置文件

private Set initializeActiveProfiles() {//      spring.profiles.active 加载指定的环境配置文件      if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)//          spring.profiles.include 包含的文件名          && !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {        return Collections.emptySet();      }      // Any pre-existing active profiles set via property sources (e.g. System 通过属性源(例如System)设置的任何预先存在的活动概要文件      // properties) take precedence over those added in config files. 属性)优先于配置文件中添加的属性。      SpringProfiles springProfiles = bindSpringProfiles(          this.environment.getPropertySources());//      加载激活的配置文件      Set activeProfiles = new LinkedHashSet(          springProfiles.getActiveProfiles());//      添加include的配置文件      activeProfiles.addAll(springProfiles.getIncludeProfiles());      maybeActivateProfiles(activeProfiles);      return activeProfiles;    }
           

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#bindSpringProfiles(org.springframework.core.env.PropertySources) 构建spring配置文件

private SpringProfiles bindSpringProfiles(PropertySources propertySources) {      SpringProfiles springProfiles = new SpringProfiles();      RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,          "spring.profiles");      dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));      springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));      springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));      return springProfiles;    }
           

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#getSearchLocations 获取location类型的配置文件

private Set<String> getSearchLocations() {      Set<String> locations = new LinkedHashSet<String>();      // User-configured settings take precedence, so we do them first 用户配置的设置优先,因此我们首先执行这些设置,spring.config.location 可以指定多个配置文件,多个配置文件用,分开,支持占位符      if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {        for (String path : asResolvedSet(            this.environment.getProperty(CONFIG_LOCATION_PROPERTY), null)) {          if (!path.contains("$")) {            path = StringUtils.cleanPath(path);//            不是直接文件路径就采用file:本地文件协议            if (!ResourceUtils.isUrl(path)) {              path = ResourceUtils.FILE_URL_PREFIX + path;            }          }          locations.add(path);        }      }      locations.addAll(          asResolvedSet(ConfigFileApplicationListener.this.searchLocations,              DEFAULT_SEARCH_LOCATIONS));      return locations;    }
           
private Set getSearchNames() {      if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {        return asResolvedSet(this.environment.getProperty(CONFIG_NAME_PROPERTY),            null);      }//      默认配置文件名 application      return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);    }
           

获取默认的配置文件名 application

说在最后

本次解析仅代表个人观点,仅供参考。

spring boot 源码_springboot源码架构解析listener

扫码进入技术微信群

spring boot 源码_springboot源码架构解析listener
spring boot 源码_springboot源码架构解析listener
spring boot 源码_springboot源码架构解析listener

钉钉技术群

spring boot 源码_springboot源码架构解析listener

qq技术群

spring boot 源码_springboot源码架构解析listener

继续阅读