详解Spring中 Environment

Environment为Spring体系中的环境上下文,给我们提供了profiles and properties功能。

1 profiles

profiles用来区分不同环境的配置,每一个profiles相当于一个bean的集合

1.1 示例

例:

@Component
@Profile("dev")
public class EnvBeanDev {
}

@Component
@Profile("prd")
public class EnvBeanPrd {
}

启动类:

public class AnnotationDemo1 {
	public static void main(String[] args) {
		// 设置激活的profile
		System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME,"dev");

		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		System.out.println(context.getBean("bean1"));
		System.out.println(context.getBean("envBeanDev"));
		System.out.println(context.getBean("envBeanPrd"));
	}
}

输出结果:
在这里插入图片描述可以看到设置了激活的Profile后,指定Profile和未设置Profile的Bean会被加载。

1.2 profiles设置激活

Spring的profiles有两个变量可以配置

  • spring.profiles.default 默认值,优先级低。当active没有配置时,使用此变量。
  • spring.profiles.active 优先级高,指定当前容器使用哪个profile。

上面例子是通过在System中设置spring.profiles.active ,Profiles激活有多种设置方式。

  1. JAVA标准API:System.setProperty(“spring.profiles.active”, “dev”);//在启动容器之前,先指定环境中的profiles参数
  2. 设置JVM的启动参数: -Dspring.profiles.active=dev
  3. spring环境上下文:Environment.setActiveProfiles(“wow”,“pes”,“ff”);
  4. 等还有maven、web.xml、dipatecherServlet

1.3 原理

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

	/**
	 * The set of profiles for which the annotated component should be registered.
	 */
	String[] value();

}

可以看到Profile的原理就是通过Conditional实现的,在扫描到Componment后会调用ProfileCondition的matches方法,比对当前Bean的profile和激活的profile是否相同。

2 properties

首先理解几个接口:
PropertySource:属性源,属性的来源,其中存放的是键-值对,比如System中的属性、properties文件中的属性,不同的properties文件对应不同的属性源。
PropertySources:管理属性源的接口,相当于是属性源的集合。
PropertyResolver:属性解析器定义了对属性的操作,存取属性,解析占位符。

Spring中默认的环境上线文是StandardEnvironment,StandardEnvironment继承了AbstractEnvironment,StandardEnvironment实例化的时候会调用父类构造方法,会调用父类无参构造,AbstractEnvironment类的构造函数如下:

public AbstractEnvironment() {
		this(new MutablePropertySources());
}

protected AbstractEnvironment(MutablePropertySources propertySources) {
		this.propertySources = propertySources;
		this.propertyResolver = createPropertyResolver(propertySources);
		customizePropertySources(propertySources);
	}
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

无参构造中首先会创建一个PropertySources的实现MutablePropertySources管理PropertySource,相当于一个PropertySource集合,在第二个构造函数中还创建了PropertyResolver默认解析器PropertySourcesPropertyResolver,传入了属性源集合,最后调用customizePropertySources加入了两个属性源。

2.1 Environment#getProperty(String key)原理

该方法首先会进入AbstractEnvironment#getProperty(String key)

public String getProperty(String key) {
		return this.propertyResolver.getProperty(key);
	}

调用了解析器的getProperty,而上面我们知道默认的解析器为:PropertySourcesPropertyResolver,多以进入PropertySourcesPropertyResolver#getProperty(String key):

public String getProperty(String key) {
		return getProperty(key, String.class, true);
	}


protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
		if (this.propertySources != null) {
			// 循环所有的PropertySource获取对应属性的值
			for (PropertySource<?> propertySource : this.propertySources) {
				if (logger.isTraceEnabled()) {
					logger.trace("Searching for key '" + key + "' in PropertySource '" +
							propertySource.getName() + "'");
				}
				Object value = propertySource.getProperty(key);
				if (value != null) {
					if (resolveNestedPlaceholders && value instanceof String) {
						// 解析占位符${}
						value = resolveNestedPlaceholders((String) value);
					}
					logKeyFound(key, propertySource, value);
					// 转换为指定类型
					return convertValueIfNecessary(value, targetValueType);
				}
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Could not find key '" + key + "' in any property source");
		}
		return null;
	}

最终还是循环了所有PropertySources,从PropertySource中获取属性值。

2.2 向Environment中加入PropertySource

通过@PropertySource注解,该注解通过PropertySourceFactory的实现读取配置文件,所以如果是读取其它类的实现可自行实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值