Spring中的Environment接口
Environment的描述
Javadoc中的描述
Environment是表示当前应用程序正在其中运行的环境的接口,它为应用环境制定了两个关键的方面:profile和properties,与属性访问有关的方法通过PropertyResolver这个父接口公开(其中,PropertyResolver这个接口主要负责解析占位符对应的值);
profile机制保证了仅在给定profile处于激活状态( active )时才向容器注册的BeanDefinitiion的命名逻辑组;无论是用XML定义还是通过注解定义,都可以将Bean分配给指定的profile;与配置文件相关的Environment的作用是决定当前哪些配置文件处于激活状态,以及默认情况下哪些配置文件应处于激活状态(即Environment配合profile可以完成指定模式的环境的组件装配,以及不同的配置属性注入);
Properties在几乎所有应用程序中都起着重要作用,并且可能源自多种来源:属性文件,JVM 系统属性,系统环境变量,JNDI,ServletContext参数,临时属性对象,Map对象等;Environment与属性相关联的作用是为用户提供方便的接口,它可以用于配置属性源,并从Environment中解析属性;
Environment中存放了很多properties,properties的来源有很多种,而properties最终的作用都是提供属性配置,或为组件注入属性值;
- Spring 3.1前占位符处理
- 组件:org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
- Spring 3.1+占位符处理
- 组件:org.springframework.context.support.PropertySourcesPlaceholderConfigurer
Environment可以注入到组件中,用于获取当前环境激活的所有profile环境,但不推荐开发者直接使用它,而是通过占位符${...}注入属性的值;
Environment的体系结构
PropertyResolver
该接口用于配置属性的获取和解析的;
ConfigurableEnvironment
Configurable开头的类或接口,通常是扩展了xx属性的set方法;
可以从接口的方法定义中看到这样的方法名:setActiveProperiles,setDefaultProfiles;
其中getPropertySources方法获取所有的PropertySource对象;
Mutable开头的类名通常可能是一个类型的List封装,MutablePropertySources的内部是一个List;
StandardEnvironment
StandardEnvironment是Spring中默认使用的标准运行时环境的抽象实现;
其中StandardEnvironment类中没有getProperty方法的实现,而是在父类AbstractEnvironment中直接调用了自身组合的一个ConfigurablePropertyResolver来处理;
AbstractEnvironment#getProperty(java.lang.String)
Environment的使用
使用@Autowired获取Environment实例
查看代码
@Component
public class EnvironmentHolder {
@Autowired
Environment environment;
public void printEnvironment() {
System.out.println(environment);
}
}
查看代码
public class EnvironmentDemoApplication {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBean(EnvironmentHolder.class);
ctx.refresh();
EnvironmentHolder environmentHolder = ctx.getBean(EnvironmentHolder.class);
environmentHolder.printEnvironment();
}
}
运行main方法,控制台打印出Environment的对象信息:
使用Environment获取配置属性的值
在resources目录下新增一个propertysource目录,创建一个demo.properties文件;
查看代码
demo.name=a
查看代码
@Component
@PropertySource("propertysource/demo.properties")
public class EnvironmentHolder {
@Autowired
Environment environment;
public void printEnvironment() {
System.out.println(Arrays.toString(environment.getDefaultProfiles()));
System.out.println(environment.getProperty("demo.name"));
}
}
查看代码
public class EnvironmentDemoApplication {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBean(EnvironmentHolder.class);
ctx.refresh();
EnvironmentHolder environmentHolder = ctx.getBean(EnvironmentHolder.class);
environmentHolder.printEnvironment();
}
}
运行main方法,控制台打印如下信息:
从打印的结果可以看出默认的profiles有一个默认值default,它的由来可以查看AbstractEnvironment#getDefaultProfiles;
AbstractEnvironment#getDefaultProfiles
getDefaultProfiles方法调用了doGetDefaultProfiles;
注:在Spring框架中,如果有出现一个方法是do开头,并且去掉do后能找到一个与剩余名称一样的方法,则表示的含义:不带do开头的方法一般负责前置校验处理、返回结果封装,带do开头的方法是真正执行逻辑的方法;如AbstractBeanFactory#getBean方法的底层会调用doGetBean方法来真正地执行从IOC容器中寻找bean,AbstractBeanFactory#createBean方法会调用doCreateBean方法真正地执行创建bean的逻辑;
AbstractEnvironment#doGetDefaultProfiles
该方法会获取框架默认的profiles,并与当前的对比,如果一致,则尝试从Environment中获取显示声明的profiles,否则取默认的deafultProfiles;
如果配置项spring.profiles.default没有配置,则从取默认defaultProfiles;
当通过JVM启动参数指定spring.profiles.default的配置,这时候就可以覆盖默认的profiles;
AbstractEnvironment#getReservedDefaultProfiles
getReservedDefaultProfiles方法取AbstractEnvironment中内置常量RESERVED_DEFAULT_PROFILE_NAME的值;