我个人在阅读spring的过程中将spring 分成了几个体系,因为我觉得Spring是要给非常优秀的框架,很多设计是可以给我们复用的。比如这里讲解的Spring中的Environment体系。
Environment接口
环境主要分类为两大部分:profile,properties
继承uml图如下:图片有点大而长。但是这样才详细。profile这个功能比较简单这里不介绍了。
Envirnment体系最重要的方法就是org.springframework.core.env.AbstractEnvironment#customizePropertySources
子类负责继承这个方法之后进行定制自己的 PropertySources
这里看看StandardEnvironment,超级简单。
然后我们再回来看看 AbstractEnvironment 的customizePropertySources函数
/** * 装饰方法模式 * Customize (定做改造) the set of {@link PropertySource} objects to be searched by this * {@code Environment} during calls to {@link #getProperty(String)} and related * methods. * *
Subclasses that override this method are encouraged (促使) to add property
* sources using {@link MutablePropertySources#addLast(PropertySource)} such that * further subclasses may call {@code super.customizePropertySources()} with * predictable results. For example: *
* public class Level1Environment extends AbstractEnvironment { * @Override * protected void customizePropertySources(MutablePropertySources propertySources) { * super.customizePropertySources(propertySources); // no-op from base class * propertySources.addLast(new PropertySourceA(...)); * propertySources.addLast(new PropertySourceB(...)); * } * } * * public class Level2Environment extends Level1Environment { * @Override * protected void customizePropertySources(MutablePropertySources propertySources) { * super.customizePropertySources(propertySources); // add all from superclass * propertySources.addLast(new PropertySourceC(...)); * propertySources.addLast(new PropertySourceD(...)); * } * } *
*
* 继承链,能够像栈一样。后调用先执行。
*
*
* In this arrangement(约定), properties will be resolved against sources A, B, C, D in that
* order. That is to say that property source "A" has precedence over property source
* "D". If the {@code Level2Environment} subclass wished to give property sources C
* and D higher precedence than A and B, it could simply call
* {@code super.customizePropertySources} after, rather than before adding its own:
*
* public class Level2Environment extends Level1Environment {
* @Override
* protected void customizePropertySources(MutablePropertySources propertySources) {
* propertySources.addLast(new PropertySourceC(...));
* propertySources.addLast(new PropertySourceD(...));
* super.customizePropertySources(propertySources); // add all from superclass
* }
* }
*
* The search order is now C, D, A, B as desired.
*
*
Beyond these recommendations, subclasses may use any of the {@code add*},
* {@code remove}, or {@code replace} methods exposed by {@link MutablePropertySources} * in order to create the exact arrangement of property sources desired. * *The base implementation registers no property sources.
* *Note that clients of any {@link ConfigurableEnvironment} may further customize
* property sources via the {@link #getPropertySources()} accessor, typically within * an {@link org.springframework.context.ApplicationContextInitializer * ApplicationContextInitializer}. For example: *
* ConfigurableEnvironment env = new StandardEnvironment();
* env.getPropertySources().addLast(new PropertySourceX(...));
*
*
*
A warning about instance variable access
*关于实例对象变量的警告
* * Instance variables(变量) declared in subclasses and having default initial values should * not be accessed from within this method. Due to Java object creation * lifecycle constraints, any initial value will not yet be assigned when this * callback is invoked by the {@link #AbstractEnvironment()} constructor, which may * lead to a {@code NullPointerException} or other problems. If you need to access * default values of instance variables, leave this method as a no-op and perform * property source manipulation and instance variable access directly within the * subclass constructor. Note that assigning values to instance variables is * not problematic; it is only attempting to read default values that must be avoided. * * @see MutablePropertySources * @see PropertySourcesPropertyResolver * @see org.springframework.context.ApplicationContextInitializer */ protected void customizePropertySources(MutablePropertySources propertySources) { }上面的注解非常详细了,而且生僻的单词我都做了详细的讲解,这里就不细说了。
然后根据上面的注解就可以看看StandardEnvironment
public class StandardEnvironment extends AbstractEnvironment { public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"; public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"; @Override 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()));}}
一个非常典型的创建环境的接口。我们在这里一般在外面直接使用StandardEnvironment
(比较典型的装饰模式),怎么使用我们待会再说(先挖坑)。我们先看getSystemProperties()和getSystemEnvironment()是什么。
其中getSystemProperties()和getSystemEnvironment()是父类AbstractEnvironment的。
org.springframework.core.env.AbstractEnvironment#getSystemProperties @Override@SuppressWarnings({"rawtypes", "unchecked"})public Map<String, Object> getSystemProperties() { try { return (Map) System.getProperties(); // 重点是这个方法 } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override @Nullable protected String getSystemAttribute(String attributeName) { try { return System.getProperty(attributeName); // 重点是这个方法 } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info("Caught AccessControlException when accessing system property '" + attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage()); } return null; } } }; }}@Override@SuppressWarnings({"rawtypes", "unchecked"})public Map<String, Object> getSystemEnvironment() { if (suppressGetenvAccess()) { return Collections.emptyMap(); } try { return (Map) System.getenv(); // 重点是这个方法 } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override @Nullable protected String getSystemAttribute(String attributeName) { try { return System.getenv(attributeName); // 重点是这个方法 } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info("Caught AccessControlException when accessing system environment variable '" + attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage()); } return null; } } }; }}
这里的实现很有意思,如果安全管理器阻止获取全部的系统属性,那么会尝试获取单个属性的可能性,如果还不行就抛异常了。
从上面的代码大意就是所谓的getSystemProperties()和getSystemEnvironment()其实是调用System的方法getProperties()
和 getenv()
System.getProperties() 注解如下:
public static Properties getProperties() { SecurityManager sm = getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } return props;}
这是上面的类的说明。
getSystemEnvironment方法也是一个套路,不过最终调用的是System.getenv,可以获取jvm和OS的一些版本信息。
和 System.getenv()
public static java.util.Map<String,String> getenv() { SecurityManager sm = getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getenv.*")); } return ProcessEnvironment.getenv();}
看明白了getSystemProperties()和getSystemEnvironment(),那么我们就要看后面的大餐
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";// 省略了这里不关注的代码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()));}
new PropertiesPropertySource()
和new SystemEnvironmentPropertySource()
到底是什么鬼呢?看后面的文章!