参考:https://blog.csdn.net/sdlyjzh/article/details/79307239
一、体系结构
Environment
是一个集成到容器之中的特殊抽象,它针对应用的环境建立了两个关键的概念:profile
和properties
.
profile是命名好的,其中包含了多个Bean的定义的一个逻辑集合,只有当指定的profile被激活的时候,其中的Bean才会激活。无论是通过XML定义的还是通过注解解析的Bean都可以配置到profile之中。而Environment
对象的角色就是跟profile相关联,然后决定来激活哪一个profile,还有哪一个profile为默认的profile。
properties在几乎所有的应用当中都有着重要的作用,当然也可能导致多个数据源:property文件,JVM系统property,系统环境变量,JNDI,servlet上下文参数,ad-hoc属性对象,Map等。Environment
对象和property相关联,然后来给开发者一个方便的服务接口来配置这些数据源,并正确解析
下面着重介绍StandardEnviroment和StandardServletEnviroment
二、Environment对properties的处理
1.StandardEnviroment
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
将 系统属性 和系统环境变量 保存到 环境中
2.StandardServletEnviroment
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
1.将 servletConfigInitParams 、servletContextInitParams、jndiProperties保存到环境变量中(这里只是创建了相应对象,无实际内容,真正初始化在StandardServletEnviroment.initPropertySources完成【该方法被ContextLoaderListener调用】,)
2.调用父类StandardEnviroment(将 系统属性 和系统环境变量 保存到 环境中)
三、Environment对profile的处理
StandardEnviroment和StandardServletEnviroment并没有对profile处理,但他们的父类AbstractEnvironment实现了对profile的简单操作
情景描述:
想象这样一种情况,在软件开发的过程中有开发环境和正式环境,他们使用的数据源不同,怎么才能做到无缝切换呢。也就是说怎么让Spring容器在不同的条件下注册不同的Bean。比如说生产环境和测试的环境的数据源
传统做法:
在spring3.0以前我们可以这么做,把这些不同环境的bean定义在不同的xml文件中,然后采用import标签配合PropertySourcesPlaceholderConfigurer导入不同的配置。
如下一个示例:
<import resource="com/test/dao/dao-${test}.xml" />
上面这个示例要使之工作,需要在spring容器启动之前在System property和环境变量中添加test() 【原因如此.】
1. 带参数启动。启动程序中传入property。如下:
-Dtest=test
2. 在程序中编码添加(需在IOC加载前,或refresh容器)。
Properties pp = System.getProperties();
pp.put(key, value)
使用profile:
以上的机制的好坏暂且不谈,但是有一点是不同的团队拥有不同的方案,而且配置文件分散,spring的profile提供统一的解决方案。
Profile是<beans>标签的一个属性,定义了一组bean属于同一个profile,如下图:
<beans profile="qa">
<bean id="userDao" class="com.test.dao.UserDaoImp">
</bean>
<bean id="userDao1" class="com.test.dao.UserDaoImp">
<qualifier type="com.test.service.MyQualify" value="userMy" />
</bean>
</beans>
profile在spring内部由activeProfiles 和defaultProfiles区分,作为成员变量(Map)存在于Environment中
启用profile:
1. 使用代码
context.getEnvironment().setActiveProfiles("test");
context.refresh();
2. 启动时传入参数。
-Dspring.profiles.active="profile1,profile2"(相当于在system.getProperty添加了k-v)
两种方式对比:
profile相比传统方式 更加细粒度。profile针对于bean,传统方式针对于bean定义文件