Right now I am reading properties file in spring as
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="customer/messages" />
</bean>
Here I am specifying that read messages.properties in customer directory. But what I want to do is to specify a directory and ask spring to read all properties file present in that directory. How can I achieve that?
I tried value="customer/*" but it doesn't work.
Using <context:property-placeholder> is more recommended as:
<context:property-placeholder
locations="classpath:path/to/customer/*.properties" />
You can also do this using Spring 3.1+ Java Config with:
#Bean
public static PropertyPlaceholderConfigurer properties(){
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[ ]
{ new ClassPathResource( "path/to/customer/*.properties" ) };
ppc.setLocations( resources );
ppc.setIgnoreUnresolvablePlaceholders( true );
return ppc;
}
You may need to tailor the type of resource to load properties from:
Resource abstract implementations
Built-in resource implementation
A complete walk through of properties in Spring
To use a property, you can use Environment abstraction. It can be injected and used to retrieve property values at runtime.
Finally used approach given on following blog -
http://rostislav-matl.blogspot.in/2013/06/resolving-properties-with-spring.html
Related
For spring framework, I want to manually reload data inside properties file. Actually, have to write reload servlet that will manually reload data when I manually run this servlet file.
I have already defined spring configuration for messageSource.
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="classpath:/message" />
But don't want to autoreload at certain amount of time for example can autoreload when setting:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="classpath:/message"
p:cacheSeconds="1" />
I tried before by clearCaches() but not autoreload.
It is working now. Need to inject messageSource into servlet file and call clearCache(). It does clear previous properties data and reload updated properties file.
In ReloadServlet.java,
ReloadableResourceBundleMessageSource rs = Global.getBean("messageSource", ReloadableResourceBundleMessageSource.class);
rs.clearCache();
In Global.java,
private static ApplicationContext context;
public static <T> T getBean(String s, Class<T> type) {
return context.getBean(s, type);
}
Thanks.
I don't know, what you mean manually reload properties file. Spring already provide to load properties file as below.
Configure your properties file in your spring configuration file. Eg. applicationContext.xml or spring-beans.xml
<util:properties id="MY_CONFIG" location="classpath:MY_CONFIG.properties"/>
In your sping bean, inject as below
#Resource(name = "MY_CONFIG")
private Properties properties;
Your servlet invoke that spring bean.
Update
If you would like to load the file from Servlet or other classes directly
Load properties file in Servlet/JSP
Is there a way to easily use Spring Injection to grab one or more *.xml data files from a folder location (either in a deployed *.war or on a server folder) and inject that data from the *.xml files into a Java class (e.g. in a web service)? I have been asked by another programmer if I can do this.
I've had a look at a few links on stackoverflow, but so far the easiest way I've found is to put the *.xml files into a particular folder location (e.g. WEB-INF/classes) and use something like this to retrieve them:
Thread.currentThread().getContextClassLoader.getResourceAsStream("/WEB-INF/classes/data.xml")
The above method is easy; however, it is obviously not Spring Injection. Is there a way to do this using Spring Injection instead? I would have thought that since configuration files can be loaded this way, that xml data could also be loaded similarly.
Thanks.
Spring provides a class called Resource which you can use to inject resource files into a spring bean. So you can do this:
public class Consumer {
public void setResource(Resource resource) {
DataInputStream resourceStream = new DataInputStream(resource.getInputStream());
// ... use the stream as usual
}
...
}
Then:
<bean class="Consumer">
<property name="resource" value="classpath:path/to/file.xml"/>
</bean>
or,
<bean class="Consumer">
<property name="resource" value="file:path/to/file.xml"/>
</bean>
You can also directly use the #Value annotation:
public class Consumer {
#Value("classpath:path/to/file.xml")
private Resource resource;
...
}
I am doing this..
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(context);
xmlReader
.loadBeanDefinitions(new ClassPathResource("SpringConfig.xml"));
PropertySourcesPlaceholderConfigurer propertyHolder = new PropertySourcesPlaceholderConfigurer();
propertyHolder.setLocation(new ClassPathResource(
"SpringConfig.properties"));
context.addBeanFactoryPostProcessor(propertyHolder);
......
context.refresh();
Now in my #Configuration files, the properties present in my SpringConfig.properties are not getting picked up if I do this...
#Autowired
private Environment env
.....
env.getProperty("my.property")
But I get that property if I use
#Value("${my.property}")
private String myProperty;
I even tried adding couple of more lines like this, but of no use.
ConfigurableEnvironment env = new StandardEnvironment();
propertyHolder.setEnvironment(env);
Does anybody know why my properties are not loaded into Environment? Thanks.
PropertySourcesPlaceholderConfigurer reads property files directly(as it was done by PropertyPlaceholderConfigurer in Spring 3.0 times), it's just a postprocessor which does not change the way properties are used in the Spring context - in this case properties are only available as bean definition placeholders.
It's the PropertySourcesPlaceholderConfigurer who uses Environment and not vice versa.
Property sources framework works on the application context level, while property placeholder configurers only provide the functionality to process placeholders in the bean definitions. To use property source abstraction you should use #PropertySource annotation i.e. decorate your configuration class with something like
#PropertySource("classpath:SpringConfig.properties")
I believe that you can do the same thing programmatically, i.e. you can get the container's ConfigurableEnvironment before the context was refreshed, modify its MutablePropertySources(you need first to get AbstractApplicationContext environment property via context.getEnvironment() ) via getPropertySources().addFirst(new ResourcePropertySource(new ClassPathResource(
"SpringConfig.properties"))); but it's unlikely what you want to do - if you already have a #Configuration annotated class, decorating it with #PropertySource("classpath:SpringConfig.properties") is much simpler.
As for the PropertySourcesPlaceholderConfigurer instance - it will fetch property sources automatically(as it implements EnvironmentAware) from its application context so you need just to register a default instance of it.
For the examples of custom property source implementation see http://blog.springsource.org/2011/02/15/spring-3-1-m1-unified-property-management/
Adding local properties to PropertySourcesPlaceholderConfigurer (with setProperties() or setLocation()) doesn't make them available in the Environment.
Actually it works in the opposite way - Environment acts as a primary source of properties (see ConfigurableEnvironment), and PropertySourcesPlaceholderConfigurer can make properties from the Environment available using ${...} syntax.
I did this per #Boris suggestion..
PropertySourcesPlaceholderConfigurer propertyHolder = new PropertySourcesPlaceholderConfigurer();
ConfigurableEnvironment env = new StandardEnvironment();
env.getPropertySources().addFirst(
new ResourcePropertySource(new ClassPathResource(
"SpringConfig.properties")));
propertyHolder.setEnvironment(env);
context.addBeanFactoryPostProcessor(propertyHolder);
context.register(SpringConfig.class);
context.refresh();
Now in #Configuration classes all properties (including my own and system properties) can be resolved using #Value.
But the Environment that gets #Autowired into #Configuration class has only system properties in it, not SpringConfig.properties I set as above. But clearly, before calling context.refresh() above, the ConfigurableEnvironment has my properties also. But once context.refresh() is called, my properties are removed from the Environment that gets autowired into #Configuration.
I want to be able to use the better syntax, env.getProperty("my.property"). Does anybody know why that is the case?
I am loading 2 types of properties one is the Environment property and the other is the context which you usually get from lets say servletContext.getServletContext().
My environment property is defined as : MOD_CONFIG_ROOT which is set seperately on the environment thereby seperating the location details the ear file which contains code. Here's the configuration.
[ Note: I had to load the property files as first thing before loading the servlets to make use of the properties using ${someProperty} ]
<bean id="externalProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:#{ systemEnvironment['MOD_CONFIG_ROOT']
}#{servletContext.contextPath}/users.properties</value>
</list>
</property>
<property name="searchSystemEnvironment" value="true" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK" />
</bean>
I need a quick help from you to fix a small problem.
In one of my project (using spring as core container), i am using ehcache to cache data. I am using spring ehcache annotations project (http://code.google.com/p/ehcache-spring-annotations/) for the same.
I want to have flexibility to enable and disable ehcache based on a external property. I read ehcache documentation and found that it reads system property net.sf.ehcache.disabled internally and if it set to true cache will be disabled and they recommend to pass this as -Dnet.sf.ehcache.disabled=true in the command line
I wanted to control it through externalized spring property file.
Then i thought of setting this system property in my spring application context file using MethodInvokingFactoryBean based on a externalized property.
Here is the code
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.System"/>
<property name="targetMethod" value="getProperties"/>
</bean>
</property>
<property name="targetMethod" value="putAll"/>
<property name="arguments">
<util:properties>
<prop key="net.sf.ehcache.disabled">"${ehcache.disabled}"</prop>
</util:properties>
</property>
</bean>
Obviously ehcache.disabled is controlled via my externalized property file.
Plumbing works great but i guess order is not coming into place. By the time Application context is setting system property, cache is initialized and when cache was being initialized there was no property net.sf.ehcache.disabled, hence cache is not getting disabled. When i run application in debug mode and try to get System.getProperty("net.sf.ehcache.disabled") after application context is initialized, it is giving me the right value. (I tried both true and false).
One more thing i want to mentioned i am using spring wrapper to initialize my cache.
<ehcache:annotation-driven self-populating-cache-scope="method"/>
<ehcache:config cache-manager="cacheManager">
<ehcache:evict-expired-elements interval="20"/>
</ehcache:config>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml"/>
I believe that disabling cache can not be that hard.
What is it that i am missing? Is there any easy way to do it in spring except command line?
As of Spring 3.1 it is possible to use bean profiles which can read a property from a external property. You could wrap the declared bean inside a beans element:
<beans profile="cache-enabled">
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml"/>
</beans>
And then activate that using an external property as mentioned in this blog post.
The easiest way (pre-Spring 3.1) would be to add a bean id to your MethodInvokingFactoryBean declaration, then add a depends-on relationship.
You can return NoOpCacheManager object if your external property is not true
#Value("${cache.enabled}")
private Boolean cacheEnabled;
#Bean(destroyMethod="shutdown")
public net.sf.ehcache.CacheManager ehCacheManager() {
net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
CacheConfiguration cacheConfiguration = new CacheConfiguration();
cacheConfiguration.setName("mycache");
cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
cacheConfiguration.setMaxEntriesLocalHeap(1000);
cacheConfiguration.setTimeToIdleSeconds(0);
cacheConfiguration.setTimeToLiveSeconds(3600);
cacheConfiguration.persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.NONE));
config.addCache(cacheConfiguration);
cacheMaxEntriesLocalHeap, cacheEvictionPolicy);
return net.sf.ehcache.CacheManager.newInstance(config);
}
#Bean
#Override
public CacheManager cacheManager() {
if(cacheEnabled) {
log.info("Cache is enabled");
return new EhCacheCacheManager(ehCacheManager());
}else{
log.info("Cache is disabled");
return new NoOpCacheManager();
}
}
This seems like a pretty common problem, but I haven't found any sort of consensus on the best method, so I'm posing the question here.
I'm working on a command-line Java application using Spring Batch and Spring. I'm using a properties file along with a PropertyPlaceholderConfigurer, but I'm a little unsure of the best way of handling the properties files for multiple environments (dev, test, etc.). My Googling is only turning up programmatic ways of loading the properties (i.e., in the Java code itself), which doesn't work for what I'm doing.
One approach I've considered is simply placing each environment's properties file on the server and adding the file's directory to the classpath via a command-line argument, but I've been having trouble loading the file using that method.
The other method I'm considering is to just include all the properties files in the jar and use a system property or command line argument to fill in the name of the properties file at runtime, like this:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:job.properties.${env}</value>
</list>
</property>
</bean>
I lean towards the latter solution, but I'm also looking to see if there's a better method I'm overlooking.
I should also mention that I have to make the substitution at runtime rather than in the build. The process I'm constrained to use requires a single build which will be promoted through the environments to production, so I'm unable to use substitution ala Maven or Ant.
Essentially you have a finished JAR which you want to drop into another environment, and without any modification have it pick up the appropriate properties at runtime. If that is correct, then the following approaches are valid:
1) Rely on the presence of a properties file in the user home directory.
Configure the PropertyPlaceholderConfigurer to reference a properties file external to the JAR like this:
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="order" value="1"/>
<property name="locations">
<list>
<!-- User home holds secured information -->
<value>file:${user.home}/MyApp/application.properties</value>
</list>
</property>
</bean>
The operating system will secure the contents of the application.properties file so that only the right people can have access to it. Since this file does not exist when you first run up the application, create a simple script that will interrogate the user for the critical values (e.g. username, password, Hibernate dialect etc) at start up. Provide extensive help and sensible default values for the command line interface.
2) If your application is in a controlled environment so that a database can be seen then the problem can be reduced to one of creating the basic credentials using technique 1) above to connect to the database during context startup and then performing substitution using values read via JDBC. You will need a 2-phase approach to application start up: phase 1 invokes a parent context with the application.properties file populating a JdbcTemplate and associated DataSource; phase 2 invokes the main context which references the parent so that the JdbcTemplate can be used as configured in the JdbcPropertyPlaceholderConfigurer.
An example of this kind of code would be this:
public class JdbcPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private Logger log = Logger.getLogger(JdbcPropertyPlaceholderConfigurer.class);
private JdbcTemplate jdbcTemplate;
private String nameColumn;
private String valueColumn;
private String propertiesTable;
/**
* Provide a different prefix
*/
public JdbcPropertyPlaceholderConfigurer() {
super();
setPlaceholderPrefix("#{");
}
#Override
protected void loadProperties(final Properties props) throws IOException {
if (null == props) {
throw new IOException("No properties passed by Spring framework - cannot proceed");
}
String sql = String.format("select %s, %s from %s", nameColumn, valueColumn, propertiesTable);
log.info("Reading configuration properties from database");
try {
jdbcTemplate.query(sql, new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
String name = rs.getString(nameColumn);
String value = rs.getString(valueColumn);
if (null == name || null == value) {
throw new SQLException("Configuration database contains empty data. Name='" + name + "' Value='" + value + "'");
}
props.setProperty(name, value);
}
});
} catch (Exception e) {
log.fatal("There is an error in either 'application.properties' or the configuration database.");
throw new IOException(e);
}
if (props.size() == 0) {
log.fatal("The configuration database could not be reached or does not contain any properties in '" + propertiesTable + "'");
}
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void setNameColumn(String nameColumn) {
this.nameColumn = nameColumn;
}
public void setValueColumn(String valueColumn) {
this.valueColumn = valueColumn;
}
public void setPropertiesTable(String propertiesTable) {
this.propertiesTable = propertiesTable;
}
}
The above would then be configured in Spring like this (note the order property comes after the usual $ prefixed placeholders):
<!-- Enable configuration through the JDBC configuration with fall-through to framework.properties -->
<bean id="jdbcProperties" class="org.example.JdbcPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="order" value="2"/>
<property name="nameColumn" value="name"/>
<property name="valueColumn" value="value"/>
<property name="propertiesTable" value="my_properties_table"/>
<property name="jdbcTemplate" ref="configurationJdbcTemplate"/> <!-- Supplied in a parent context -->
</bean>
This would allow the follow to occur in the Spring configuration
<!-- Read from application.properties -->
<property name="username">${username}</property>
...
<!-- Read in from JDBC as part of second pass after all $'s have been fulfilled -->
<property name="central-thing">#{name.key.in.db}</property>
3) Of course, if you're in a web application container then you just use JNDI. But you're not so you can't.
Hope this helps!
You could use <context:property-placeholder location="classpath:${target_env}configuration.properties" />
in your Spring XML and configure ${target_env} using a command-line argument (-Dtarget_env=test.).
Starting in Spring 3.1 you could use <context:property-placeholder location="classpath:${target_env:prod.}configuration.properties" /> and specify a default value, thereby eliminating the need to set the value on the command-line.
In case Maven IS an option, the Spring variable could be set during plugin execution, e.g. during test or integration test execution.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<systemPropertyVariables>
<target_env>test.</target_env>
</systemPropertyVariables>
</configuration>
</plugin>
I assume different Maven profiles would also work.
Spring Property Placeholder Configurer – A few not so obvious options
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${db.url.${mode}}" />
<property name="username" value="${db.username.${mode}}" />
<property name="password" value="${db.password.${mode}}" />
</bean>
${db.username.${mode}}: Here "mode" defines the project mode (environment) - dev / prod
Properties file looks like:
#Database properties
#mode dev/prod
mode=dev
#dev db properties
db.url.dev=jdbc:mysql://localhost:3306/dbname
db.username.dev=root
db.password.dev=root
#prod db properties
db.url.prod=jdbc:mysql://localhost:3306/dbname
db.username.prod=root
db.password.prod=root
I agree - it should not be a build time configuration as you want to deploy the exact same payload to the various contexts.
The Locations property of PropertyPlaceHolderConfigurer can take various types of resources. Can also be a filesystem resouce or a url? Thus you could set the location of the config file to a file on the local server and then whenever it runs it would run in the mode specified by the config file on that server. If you have particular servers for particular modes of running this would work fine.
Reading between the lines though it seems you want to run the same application in different modes on the same server. What I would suggest in this case is to pass the location of the config file via a command line parameter. It would be a little tricky to pass this value into the PropertyPlaceHolderConfigurer but would not be impossible.
The way I've normally done this in the past is to perform a substitution of the environment (dev/test/prod) in some sort of way at package/deployment time.
That can either copy the correct config file to the right location on the server or just bundle the correct config file in the deployment package. If you use Ant/Maven this should be fairly straightforward to achieve. Which build tool are you using? Ant/Maven, that should provide you with the ability to substitute a value.
Another alternative, which use PropertyPlaceholderConfigurer is that of the SYSTEM_PROPERTIES_MODE_OVERRIDE property. You can use this to set the location of the properties file you wish to load through a system property, see:
http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html#SYSTEM_PROPERTIES_MODE_OVERRIDE
Hope that helps.
For build time substitution I use Maven build properties for variable substitution. You can determine what properties to load in your Maven settings.xml file and the file could be specific to the environment. For production properties using PPC see this blog
Hi after reading Spring in Action found a solution provided by Spring.
Profile Or Conditional : you can create multiple profile eg. test, dev, prod etc.
Spring honors two separate properties when determining which profiles are active:
spring.profiles.active and spring.profiles.default . If spring.profiles.active
is set, then its value determines which profiles are active. But if spring
.profiles.active isn’t set, then Spring looks to spring.profiles.default . If neither
spring.profiles.active nor spring.profiles.default is set, then there are no
active profiles, and only those beans that aren’t defined as being in a profile are created.
There are several ways to set these properties:
1 As initialization parameters on DispatcherServlet
2 As context parameters of a web application
3 As JNDI entries
4 As environment variables
5 As JVM system properties
6 Using the #ActiveProfiles annotation on an integration test class
I use the classpath option and adjust the classpath per environment in Jetty. In the jetty-maven-plugin you can set a directory for testclasses and have your testresources located there.
For non-local environments (test / production) I use an environment flag and send the appropriate files to the $JETTY_HOME/resources folder (which is built into Jetty's classpath)