说在前面
前期回顾
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 源码解析 更新完毕
源码解析
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
说在最后
本次解析仅代表个人观点,仅供参考。
扫码进入技术微信群
钉钉技术群
qq技术群