sometimes you may want to cache some information to enhance the performance by minimizing repeated hits to the database.
there are two ways you can take any one of them or take them both:
- Service Layer caching (Spring).
- Object-Relational Mapping (ORM) caching (Hibernate).
in this post I will take about enabling cache in the service layer using spring and ehcache.
- Lets configure the ehcache.xml
by adjusting the defaultCache as shown below, also adding three entries for the three business methods (getSecureLink, getUserDetails, getUserRoles) that I wanna cache its data as there are many calls to this methods, so its better to cache them so minimize database hits.
<ehcache> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: user.home - User's home directory user.dir - User's current working directory java.io.tmpdir - Default temp file path --> <diskStore path="java.io.tmpdir"/> <!--Default Cache configuration. These will applied to caches programmatically created
through the CacheManager.
The following attributes are required for defaultCache: maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. i.e. The maximum amount of time between accesses before an element expires Is only used if the element is not eternal. Optional attribute. A value of 0 means that an Element can idle for infinity timeToLiveSeconds - Sets the time to live for an element before it expires. i.e. The maximum time between creation time and when an element expires. Is only used if the element is not eternal. overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!-- TimeToIdleSeconds is used to determine when an object is set expire after a period of time in which it is not used or idle. You don't care how long your objects are idle before they expire, you care about the overall time to live. The timeToLiveSeconds attribute expires an object after the set period of time—no matter how active or inactive the cache has become. This service's requirements state that the cache should expire after 24 hours or 86400 seconds every day. should expire after 7 hours or 25200 seconds every day. --> <cache name="getSecureLink" maxElementsInMemory="50" eternal="false" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="25200" /> <cache name="getUserDetails" maxElementsInMemory="50" eternal="false" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="25200" /> <cache name="getUserRoles" maxElementsInMemory="50" eternal="false" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="25200" /> </ehcache>
-
then we have to an instance of the CacheManager class. by adding the the following Spring beans to the applicationContext.xml .
<bean id="appCacheManager" class="net.sf.ehcache.CacheManager"> <constructor-arg index="0" type="java.net.URL" value="classpath:ehcache.xml" /> </bean>
<bean id="methodCachingInterceptor" class="org.aliabdelaziz.business.caching.interceptor.MethodCachingInterceptor"> <property name="cacheManager" ref="appCacheManager" /> </bean>
- Now one last step wich is implementing the method MethodCachingInterceptor and registering it as service Interceptors for the services that contains the method we wanna intercept (securityService)
<!-- SecurityService Service Proxy with inner SecurityService Service Implementation --> <bean id="securityService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="org.aliabdelaziz.business.service.SecurityServiceImpl"> <!-- sessionFactory being injected by Ali Abdel-Aziz --> <property name="sessionFactory"><ref bean="sessionFactory"/></property> <property name="userDao"><ref bean="userDao"/></property> <property name="linkDao"><ref bean="linkDao"/></property> <property name="singleSignOnDao"><ref bean="singleSignOnDao"/></property> <property name="userRoleDao"><ref bean="userRoleDao"/></property> <property name="userSessionDao"><ref bean="userSessionDao"/></property> <!-- SecurityService service property merge-point --> </bean> </property> <property name="proxyInterfaces"> <value>ae.dxbpolice.eps.business.service.SecurityService</value> </property> <property name="interceptorNames"> <list> <value>methodCachingInterceptor</value> <value>serviceSecurityInterceptor</value> <value>serviceTransactionInterceptor</value> <value>hibernateInterceptor</value> </list> </property> </bean>
- and the following is the MethodCachingInterceptor implementation
package org.aliabdelaziz.business.caching.interceptor; import java.io.Serializable; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger; public class MethodCachingInterceptor implements MethodInterceptor { private CacheManager cacheManager; /** logger for MethodCachingInterceptor */ static Logger log = Logger.getLogger(MethodCachingInterceptor.class); private final String CACHE_DATA_KEY = "CACHE_DATA"; /** array of the methods that is allowed to be cached */ static final String[] CACHED_METHODS = {"getSecureLink", "getUserDetails", "getUserRoles"}; /** * check if the passed targetMethodName is one of the cached methods found * in the CACHED_METHODS array or not. * * @return true if and only if the passed targetMethodName is one of the cached methods found * in the CACHED_METHODS, false otherwise. * @param targetMethodName */ private boolean isCachedMethod(String targetMethodName) { for(int i=0; i<CACHED_METHODS.length; i++) { if(CACHED_METHODS[i].equalsIgnoreCase(targetMethodName)) return true; } return false; } public Object invoke(final MethodInvocation methodInvocation) throws Throwable { final String targetMethodName = methodInvocation.getMethod().getName(); if(!this.isCachedMethod(targetMethodName)) { return methodInvocation.proceed(); } if (log.isInfoEnabled()) { log.info("Attempting cacheManager.getCache first run (no args lookup)."); } final Cache templateCache = cacheManager.getCache(targetMethodName); Cache cache = null; final StringBuffer cacheNameBuffer = new StringBuffer(targetMethodName); String cacheName = targetMethodName.toString(); // the following two lines commented to keep match the exact method with its parameteres values //cacheManager.getCache(targetMethodName); // if (cache == null) { // Lets try with args now. if (log.isInfoEnabled()) { log.info("No cache found in no args lookup."); } final Object[] methodArgs = methodInvocation.getArguments(); if (methodArgs != null) { if (log.isInfoEnabled()) { log.info("Args on method attempting args cache lookup config."); } cacheNameBuffer.append("("); for (int i = 0; i < methodArgs.length; i++) { cacheNameBuffer.append(methodArgs[i].toString()); if (i + 1 != methodArgs.length) { cacheNameBuffer.append(","); } } cacheNameBuffer.append(")"); if (log.isInfoEnabled()) { log.info("Attempting cacheManager.getCache with args lookup:" + cacheNameBuffer); } //replace "/" with "_" so that it can be inserted into cache cacheName = cacheNameBuffer.toString().replaceAll("/", "_"); cache = cacheManager.getCache(cacheName); } } if(cache == null) { if(cacheName != null) { cache = new Cache(cacheName, templateCache.getMaxElementsInMemory(), templateCache.isOverflowToDisk(), templateCache.isEternal(), templateCache.getTimeToLiveSeconds(), templateCache.getTimeToIdleSeconds()); cacheManager.addCache(cache); } } boolean methodInvocationProceed = false; boolean methodInvocationCache = false; Object methodReturn = null; if (cache != null) { if (log.isInfoEnabled()) { log.info("Cache Config. Found: " + cache.getName()); } final Element cacheElement = cache.get(CACHE_DATA_KEY); if (cacheElement == null) { methodInvocationProceed = true; } else { methodInvocationProceed = false; if (log.isInfoEnabled()) { log.info("Cache Element Found"); } methodReturn = cacheElement.getValue(); if (log.isInfoEnabled()) { log.info("Using Cached Element for methodReturn."); } } methodInvocationCache = true; } if (cache == null || methodInvocationProceed) { methodReturn = methodInvocation.proceed(); if (methodInvocationCache) { final Element newCacheElement = new Element(CACHE_DATA_KEY, (Serializable) methodReturn); cache.put(newCacheElement); if (log.isInfoEnabled()) { log.info("Created new CacheElement entry and stored in cache."); } } } return methodReturn; } /** * @return the cacheManager */ public CacheManager getCacheManager() { return cacheManager; } /** * @param cacheManager * the cacheManager to set */ public void setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; } }
References:
- http://javaboutique.internet.com/tutorials/ehcache/index-3.html
- http://www.javaworld.com/javaworld/jw-10-2007/jw-10-acegi2.html?page=6
My aim is always to
My aim is always to certainly search for the theory while doing so and in addition functional knowledge sorts some other articles for dinner. Appreciate it for you personally dealing with
Interesting content material. i adore the theory solely. many thanks
regarded this particular website added in throughout and as well rather
definitely preferred just what We exploration. block phishing
A fresh entirely
A fresh entirely manufacturer spanking fresh substantial traits internal making relating to considerably enhanced designed gold and silver that in turn frequently consists of inclinations to help you problems a number of us long term getting final result substantial power physics. trustone
You have an exceptionally
You have an exceptionally amazing written work style. Much obliged for offering.
purchase soundcloud followers
that is to say the
that is to say the http://www.simply-fone.com/feed.php
wholesalers are dead.