预备知识
发布/订阅模式
java.util.Observable是一个发布者
java.util.Observer是订阅者
发布者和订阅者:1:N
发布者和订阅者:N:M
事件/监听模式
java.util.EventObject:事件对象
*事件对象总是关联着事件源(Source)
java.util.EventListener:事件监听接口
Spring 事件/监听
ApplicationEvent:应用事件
ApplicationListener:应用监听器
Spring Boot 事件/监听器
ConfigFileApplicationListener
管理配置文件,比如:application.properties以及application.yml
application-{proflie}.properties:
profile = dev、test
1. application-{profile}.properties
2. application.properties
Spring Boot 在相对于ClassPath: /META-INF/spring.factories
Java SPI:java.util.ServiceLoader
Spring SPI:
Spring Boot "/META-INF/spring.factories"
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
如何控制顺序
实现Ordered以及标记@Order
在Spring里面,数值越小,优先级越高。
Spring Cloud 事件/监听器
BootstrapApplicationListener
Spring Cloud "/META-INF/spring.factories" --spring-cloud-context
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener
加载的优先级高于ConfigFileApplicationListener,所以application.properties文件即使定义也配置不到!
原因在于:
BootstrapApplicationListener 第6优先 (最高优先级+5)
ConfigFileApplicationListener 第11优先 (最高优先级+10)
1. 负责加载bootstrap.properties或者bootstrap.yaml
2. 负责初始化Bootstrap ApplicationContextID="bootstrap"
ConfigurableApplicationContext context = builder.run();
Bootstrap是一个根Spring上下文,parent = null
联想 ClassLoader:
ExtClassLoader <- AppClassLoader <- SystemClassLoader ->BootstrapClassLoader(null)
ConfigurableApplicationContext
标准实现类:AnnotationConfigApplicationContext
Env端点:EnvironmentEndpoint
Environment关联多个带名称的PropertySource
可以参考一下Spring Framework源码:
AbstractRefreshableWebApplicationContext
@Override
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
}
}
Environment有两种实现方式:
普通类型:StandardEnvironment
Web类型:StandardServletEnvironment
Environment
AbstractEnvironment
-StandardEnvironment
Environment关联着一个PropertySources实例
PropertySources关联着多个PropertySource,并且有优先级
Java System#getProperties实现:名称"systemProperties",对应的内容 System.getProperties()
Java System#getenv实现(环境变量):名称"systemEnvironment",对应的内容 System.getEnv()
关于StringBoot优先级顺序,可以参考:https://docs.spring.io/spring-boot/docs/2.0.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-external-config
实现自定义配置
1. 实现PropertySourceLocator
2. 暴露该实现作为了一个Spring Bean
3. 实现PropertySource
public static class MyPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
Map<String,Object> source = new HashMap<>();
source.put("server.port", "9090");
MapPropertySource propertySource = new MapPropertySource("my-property-source", source);
return propertySource;
}
}
4. 定义并配置 /META-INF/spring.factories:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.cloud.SpringCloudConfigClientApplication.MyPropertySourceLocator
注意事项:
Environment允许出现同名的配置,不过优先级高的胜出。
内部实现:MutablePropertySources关联代码:
List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
porpertySourceList FIFO,它有顺序
可以通过MutablePropertySources#addFirst提高到最优先,相当于调用:
List#add(0,PropertySource);