首先,带有Capable后缀的接口在Spring中带有getXXX的含义,也就是实现了这个接口,就可以通过该接口的实例获取到XXX,这个和Aware接口很类似。
所以,这里的EnvironmentCapable接口就是可以获得一个Environment实例。
看下接口定义:
public interface EnvironmentCapable {
/**
* Return the {@link Environment} associated with this component.
*/
Environment getEnvironment();
}
Environment也是一个接口,继承了PropertyResolver接口,是对获取属性的抽象。有两个常见的实现类:StandardEnvironment和StandardServletEnvironment,分别应用于非web和web应用中。
Spring高级容器ApplicationContext接口继承了EnvironmentCapable接口,所以具备了获取Environment的能力。
其中的getEnvironment方法的实现是在AbstractApplicationContext中:
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
可以看到,第一次调用,会创建一个StandardEnvironment的实例。
在该类中,会默认加载两种属性源:
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()));
}
分别是系统属性和jvm属性。
我们可以直接在应用程序中获取。可以看一个例子:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
String s = context.getEnvironment().getProperty("key1");
System.out.println(s);
}
jvm的启动参数加一个-Dkey1=value1。
结果:
value1
Process finished with exit code 0
当然以上是非web应用的场景。对于web高级容器,则会创建不同的Environment。
web容器会继承父类AbstractRefreshableWebApplicationContext,该类重写了getEnvironment方法:
web容器会继承父类AbstractRefreshableWebApplicationContext,该类重写了getEnvironment方法:
@Override
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
}
直接创建了一个StandardServletEnvironment实例,该类不仅仅会加载之前的两种属性,还会额外加载web环境的特殊属性,比如servlet的init属性以及contextloader的启动属性。
我们再看一个web环境下例子。
springmvc的serlvet配置如下:
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
然后在controller中获取这个param:
@RestController
public class MainController {
@Autowired
private ContextHelper contextHelper;
@RequestMapping("/hello")
public String hello(){
String value = contextHelper.getApplicationContext().getEnvironment().getProperty("contextConfigLocation");
System.out.println(value);
return "hello";
}
}
这里的ContextHelper是为了获取当前的Spring高级容器:
@Component
public class ContextHelper implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
}
最终结果:
classpath:conf/spring-mvc.xml
说明可以拿到Servlet的启动参数。