package com.lkl.springboot.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* 注入enviroment
*
* @author liaokailin
* @version $Id: DIEnviroment.java, v 0.1 2015年10月2日 下午9:17:19 liaokailin Exp $
*/
@Component
public class DIEnviroment {
@Autowired
Environment environment;
public String getProValueFromEnviroment(String key) {
return environment.getProperty(key);
}
}
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
初始
environment 为空,
this
.
webEnvironment 判断构建的是否为web环境,通过deduceWebEnvironment方法推演出为true
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
由于可以得到得出构建的enviroment为
StandardServletEnvironment
创建对象调用其父类已经自身构造方法,StandardServletEnvironment、StandardEnvironment无构造方法,调用AbstractEnvironment构造方法
public AbstractEnvironment() {
customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug(format(
"Initialized %s with PropertySources %s", getClass().getSimpleName(), this.propertySources));
}
}
首先看
this
.propertySources定义
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
从字面的意义可以看出MutablePropertySources为多PropertySource的集合,其定义如下:
public class MutablePropertySources implements PropertySources {
private final Log logger;
private final List> propertySourceList = new CopyOnWriteArrayList>(); ...}
其中PropertySource保存配置资源信息
public abstract class PropertySource {
protected final Log logger = LogFactory.getLog(getClass());
protected final String name;
protected final T source; ...}
MutablePropertySources中属性List<PropertySource>>集合中,MutablePropertySources又作为AbstractEnvironment中的属性,因此将AbstractEnvironment保存在spring bean容器中即可访问到所有的PropertySource。
来看下对应的类图关系:
带着如上的猜想来继续查看源码。
继续来看AbstractEnvironment对应构造方法中的customizePropertySources
protected void customizePropertySources(MutablePropertySources propertySources) {
}
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);
}
public void addLast(PropertySource> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Adding [%s] PropertySource with lowest search precedence",
propertySource.getName()));
}
removeIfPresent(propertySource);
this.propertySourceList.add(propertySource);
}
protected void removeIfPresent(PropertySource> propertySource) {
this.propertySourceList.remove(propertySource);
}
@Override
public boolean equals(Object obj) {
return (this == obj || (obj instanceof PropertySource &&
ObjectUtils.nullSafeEquals(this.name, ((PropertySource>) obj).name)));
}
/**
* Return a hash code derived from the {@code name} property
* of this {@code PropertySource} object.
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.name);
}
至此StandardEnvironment的初始化完成.
在bean中注入Enviroment实际为Enviroment接口的实现类,从类图中可以看出其子类颇多,具体在容器中是哪个子类就需要从代码获取答案。
在SpringApplication.run(String... args)中存在refresh(context)调用
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
...
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
其中调用
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment())注册名称为environment的bean;
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
其中enviroment变量为前面创建
StandardServletEnvironment;前后得到验证。
首先构造PropertySource,然后将其添加到Enviroment中
package com.lkl.springboot.config;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.MapPropertySource;
public class DynamicPropertySource extends MapPropertySource {
private static Logger log = LoggerFactory.getLogger(DynamicPropertySource.class);
private static ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);
static {
scheduled.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
map = dynamicLoadMapInfo();
}
}, 1, 10, TimeUnit.SECONDS);
}
public DynamicPropertySource(String name) {
super(name, map);
}
private static Map map = new ConcurrentHashMap(64);
@Override
public Object getProperty(String name) {
return map.get(name);
}
//动态获取资源信息
private static Map dynamicLoadMapInfo() {
//通过http或tcp等通信协议获取配置信息
return mockMapInfo();
}
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
private static Map mockMapInfo() {
Map map = new HashMap();
int randomData = new Random().nextInt();
log.info("random data{};currentTime:{}", randomData, sdf.format(new Date()));
map.put("dynamic-info", randomData);
return map;
}
}
package com.lkl.springboot.config;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.AbstractEnvironment;
/**
* 加载动态配置信息
*
* @author liaokailin
* @version $Id: DynamicConfig.java, v 0.1 2015年10月2日 下午11:12:44 liaokailin Exp $
*/
@Configuration
public class DynamicConfig {
public static final String DYNAMIC_CONFIG_NAME = "dynamic_config";
@Autowired
AbstractEnvironment environment;
@PostConstruct
public void init() {
environment.getPropertySources().addFirst(new DynamicPropertySource(DYNAMIC_CONFIG_NAME));
}
}
archaius为开源的配置管理api,有兴趣的同学可研究一下: https://github.com/Netflix/archaius。
下一篇将讲解spring boot如何加载application.xml。
转载请注明
http://blog.csdn.net/liaokailin/article/details/48186331