Under normal circumstances we use in the Spring configuration file <import>
label it is such <import resource="other-beans.xml">
. If we need to use placeholders for dynamic loading of spring bean configuration files based on the configuration file you will need to be configured in the following manner.
<context:property-placeholder location="classpath*:config.properties" />
<import resource="classpath:spring-db-${env}.xml" />
Wherein the placeholder env
value by the configuration file config.properties
to obtain the. If you use the above wording will get an error when starting the project.
Look at spring parse import
the source code labels we can see:
DefaultBeanDefinitionDocumentReader.java
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
Spring can be seen by calling the importBeanDefinitionResource()
parse method import
tag. And then analyzed by the logic of the following resource
properties:
// Resolve system properties: e.g. "${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
It means to resolve placeholders system properties. And we have adopted to replace the placeholder spring bean be used usually by Spring ioc
spreading BeanFactoryPostProcessor
subclasses PropertyPlaceholderConfigurer
to achieve. But for import
resolution have not yet reached that step. So we need to ioc
be loaded before properites
the file.
1, -Dkey = value added system parameters
The simplest is the time to start the service by -Dproperty=value
setting the system 属性名/值对
, run the application on top of this jvm available System.getProperty("property")
to give value for value. If the value has a space, you need to use the value enclosed in double quotation marks, as -Dname="space string"
. This parameter is typically used to set the global variable level system, such as a profile path, so that the properties are accessible from anywhere in the program.
Tomcat start at boot time by adding -Denv=dev
it. The same we can use Spring's extensions to add parameters.
2、initPropertySources
As we all know, Spring is to load the root of the container by contextInitialized ContextLoaderListener. Its parent ContextLoader we can see the following logic.
ContextLoader.java
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
The above ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
will eventually call to WebApplicationContextUtils of initServletPropertySources method.
public static void initServletPropertySources(
MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {
Assert.notNull(propertySources, "propertySources must not be null");
if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
}
if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
}
}
It may be set by the value of the placeholder import ServletContext initialization parameters and initialization parameters ServletConfig.
2.1 ServletContext initialization parameters
If the container is defined if Spring Spring MVC profile in which the root containers, only, to the initial configuration of ServletContext initialization parameter. Because the root containers are initialized by the container ContextLoaderListener, ServletConfig is in the range Servlet. ServletContext initialization parameters may be configured by the following configuration.
<context-param>
<param-name>env</param-name>
<param-value>dev</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2.2 ServletConfig initialization parameters
If the container is defined if Spring Spring MVC profile which container serlvet. That can be through the ServletContext initialization parameters but also by the initialization parameter ServletConfig. Therefore, the parameters can be performed in the following two ways:
<context-param>
<param-name>env</param-name>
<param-value>dev</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
There placeholder import classpath:application-context.xml
file
or
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
<init-param>
<param-name>env</param-name>
<param-value>dev</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
There placeholder import classpath:dispatcher-servlet.xml
file
3, custom ApplicationContextInitializer
After calling ConfigurableWebEnvironment # initPropertySources, Spring containers before initialization ( wac.refresh()
calls) customizeContext(sc, wac)
the containers custom logic processing.
protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
determineContextInitializerClasses(sc);
for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
Class<?> initializerContextClass =
GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
throw new ApplicationContextException(String.format(
"Could not apply context initializer [%s] since its generic parameter [%s] " +
"is not assignable from the type of application context used by this " +
"context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
wac.getClass().getName()));
}
this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
}
AnnotationAwareOrderComparator.sort(this.contextInitializers);
for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
initializer.initialize(wac);
}
}
It logic is acquired web.xml
document which is to or and to type the full name of the class that implements the interface. Before spring container will call its initialization callback method to customize the container logic.
<context-param><param-name>
globalInitializerClasses
contextInitializerClasses
<param-value>
ApplicationContextInitializer
initialize()
This interface provides ApplicationContextInitializer by implementing spring. In its callback interface initialize()
to add properties file properties to the container. Then parse import label to replace the placeholder when he can get the value in the configuration file from the container.
3.1 interface to achieve ApplicationContextInitializer
Achieve ApplicationContextInitializer interface calls initialize()
to add the properties file properties to the container.
public class CustomerApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>{
private static Logger logger = LoggerFactory.getLogger(CustomerApplicationContextInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ResourcePropertySource propertySource = null;
try {
propertySource = new ResourcePropertySource("classpath:config.properties");
} catch (IOException e) {
logger.error("config.properties is not exists");
}
applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);
}
}
3.2 Configuration attribute context-param
Add the following context-param attribute web.xml container enhanced. Because customizeContext(sc, wac)
it will call all contextInitializerClasses
the initialize()
methods.
<context-param>
<param-name>globalInitializerClasses</param-name>
<param-value>cn.carlzone.spring.initializer.CustomerApplicationContextInitializer</param-value>
</context-param>
or
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>cn.carlzone.spring.initializer.CustomerApplicationContextInitializer</param-value>
</context-param>
Then placeholder env
value by the configuration file config.properties
to obtain. The spring load the appropriate configuration file to the project.
Reference article: