How to disable ehcache using an external property in spring - java

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();
}
}

Related

How to inject an attribute using spring in a type handler?

I'm setting up an application which uses mybatis to map objects to/from the database.
In my mybatis file, I use a typehandler to map one of the objects being sent to the database.
In the typeHandler, I am injecting an attribute using spring #resource.
However, when the typehandler is called, the injected property is always null.
From my research, I have discovered that mybatis sets its configuration before spring loads. That means the bean is cannot be injected into the handler as it is created after.
Does anyone know a solution to this?
Should let spring manage customized type handler, like this:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="typeHandlers">
<array>
<bean class="com.example.YourCustomTypeHandler">
<!-- inject -->
<property name="property" ref="bean"/>
</bean>
</array>
</property>
</bean>

Use of SystemPropertyInitializer to set System Property before setting property placeholder

According to this answer, you can use the Spring Batch class org.springframework.batch.support.SystemPropertyInitializer to set a System Property during startup of a Spring Context.
In particular, I was hoping to be able to use it to set ENVIRONMENT because part of Spring Batch config reads:
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties</value>
<value>classpath:batch-default.properties</value>
<value>classpath:batch-${ENVIRONMENT:hsql}.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="order" value="1" />
</bean>
But SystemPropertyInitializer uses afterPropertiesSet() to set the System Property, and apparently this happens after the configuration of PropertyPlaceholderConfigurer.
Is it possible to achieve this?
The easiest solution would be to pass in the environment property as a command-line argument, so it can be resolved as a system property.
If that's not an option you can implement a ApplicationContextInitializer that promotes environment properties to system properties.
public class EnvironmentPropertyInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
boolean override = false; //change if you prefer envionment over command line args
#Override
public void initialize(final ConfigurableApplicationContext applicationContext) {
for (Entry<String, String> environmentProp : System.getenv().entrySet()) {
String key = environmentProp.getKey();
if (override || System.getProperty(key) == null) {
System.setProperty(key, environmentProp.getValue());
}
}
}
}
Here it looks like you're using Spring Batch Admin, so you can register your initializer with a slight addition to the web.xml file:
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>org.your.package.EnvironmentPropertyInitializer</param-value>
</context-param>
Adding Background Since a Comment Didn't Seem Sufficient: Here's the relevant classes and the order in which they are called/evaluated.
The ApplicationContextInitializer tells the Spring Application how to load an application context and can be used to set bean profiles, and change other aspects of the context. This gets executed before the context gets completely created.
The PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor and calls postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory). This modifies the BeanFactory to allow for resolution of properties like ${my.property:some.default} when setting the properties of a bean as it is created by the BeanFactory.
The SystemPropertyInitializer implements InitializingBean and calls afterPropertiesSet(). This method runs after a bean is instantiated and the properties have been set.
So you're right that the SystemPropertyInitializer will not help here since it evaluates after the properties are set on the PropertyPlaceholderConfigurer. The ApplicationContextInitializer, however, will be able to promote those environment properties to system properties so they can be interpreted by the XML.
And one more note that I forgot to mention, one of the first declared beans will need to be:
<context:property-placeholder/>
Though it seems redundant, it will allow your PropertyPlaceholderConfigurer bean to evaluate ${ENVIRONMENT:hsql} correctly by using the environment properties you just promoted.

spring context jndi lookup of properties contains all props including system props, not just the one set I need

I'm using glassfish 3.1, spring 3.2 and jdk 1.7.
I have configured two custom JNDI resources in Glassfish. One is called 'config' and the other is called 'mappings'. But when I reference one of them in the code, it actually has the properties for both and all system properties (catalina.base etc). I only want the one, not all 3 sets.
I have it set so I get the properties in the spring context file:
<jee:jndi-lookup id="mappingsJndi" jndi-name="mappings" resource-ref="true" />
<bean id="propertyMappings" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="propertiesArray">
<list>
<ref bean="mappingsJndi"/>
</list>
</property>
</bean>
I reference it in the servlet. It's injected like this:
#Autowired
Properties[] propertyMappings;
The injection works, but it contains 3 properties objects instead of the one. Is there any way around this?
Looks like I figured it out. Instead of referencing the propertyMappings bean like this:
#Autowired
Properties[] propertyMappings;
I just reference the JNDI lookup directly:
#Autowired
Properties mappingsJndi;

conditional beans using spring

I am trying to write a ValidatorFactory which will give me a validator based on its type
public Validator getNewValidator(ValidatorType type){
switch:
case a : new Validator1();
break;
case b : new Validator2();
break;
}
I want to write using spring xml beans definition
I can use method injection but it will let me create only one object and the method does
not take any arguments.
I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml
bean definition.
you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.
<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>
<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />
And the content of the property file would be:
validatorType=validatorTypeOne
To use the property file in your xml just add this context to the top of your spring config
<context:property-placeholder location="classpath:app.properties" />
For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.
If you are using annotation (#Autowired, #Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to #Qualifier does not support expression
#Qualifier(value="${validatorType}")
More information is at https://stackoverflow.com/a/7813228/418439
I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:
<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg type="int" value="256"/>
</bean>
<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="${password.encoding}Password"/>
</bean>
</property>
</bean>
Of course, I defined password.encoding in a property file with possible values as sha or plainText.
You should be able to do this:
<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
<constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>
<bean id="validatorType" ... />
Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.

How do I inject a single property value into a string using spring 2.5.x?

I would really like to annotate a method with a reference to a single property in a property file for injection.
#Resource("${my.service.url}")
private String myServiceUrl;
Of course, this syntax does not work ;) Thats why I'm asking here.
I am aware that I can inject the full properties file, but that just seems excessive, I dont want the property file - I want the configured value.
Edit: I can only see PropertyPlaceholderConfigurer examples where XML is used to wire the property to the given field. I still cannot figure out how this can be achieved with an annotation ?
I know it has been a while since the original post but I have managed to stumble across a solution to this for spring 2.5.x
You can create instances of "String" beans in the spring xml configuration which can then be injected into the Annotated components
#Component
public class SomeCompent{
#Autowired(required=true
#Resource("someStringBeanId")
private String aProperty;
...
}
<beans ....>
<context:component-scan base-package="..."/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
...
</bean>
<bean id="someStringId" class="java.lang.String" factory-method="valueOf">
<constructor-arg value="${place-holder}"/>
</bean>
</beans>
I've created a project which addresses this problem for Spring 2.5.*:
http://code.google.com/p/spring-property-annotations/
For Spring 3 you can use the #Value("${propery.key}") annotation.
There's a thread about this on the Spring forum. The short answer is that there's really no way to inject a single property using annotations.
I've heard that the support for using annotations will be improved in Spring 3.0, so it's likely this will be addressed soon.
you can do this if you use XML configuration. Just configure PropertyPlaceholderConfigurer and specify property value in configuration
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
</bean>
<bean ...>
<property name="myServiceUrl" value="${my.service.url}"/>
</bean>
You could try injecting value of property "my.service.url" to a filed in your bean.
Take a look at: http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-factory-placeholderconfigurer
HTH.

Categories

Resources