Key Generation of ehcache-spring-annotations Cache

Keywords: Ehcache Spring Java xml

pom.xml

        <!-- ehcache -->
        <dependency>
            <groupId>com.googlecode.ehcache-spring-annotations</groupId>
            <artifactId>ehcache-spring-annotations</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>${ehcache.version}</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>${ehcache.version}</version>
        </dependency>

Explain:
This article is not talking about Spring Cache, ehcache-spring-annotations need to be used with ehcache. It's just annotation (@Cacheable) in the code.

    @Cacheable(cacheName="myCache")
    public ForumPermissions getPermissions(GlobalPermissionEnum permissonType){
    }

@ The full name of Cacheable: com.googlecode.ehcache.annotations.Cacheable. Don't mix it with Spring Cache's namesake annotations (org. spring framework. cache. annotation. Cacheable)

@Cacheable

@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {

    public String cacheName();

    public boolean cacheNull() default true;

    public DecoratedCacheType decoratedCacheType() default DecoratedCacheType.NONE;

    @Deprecated
    public boolean selfPopulating() default false;

    public int selfPopulatingTimeout() default 0;

    public long refreshInterval() default 60000L;

    public String keyGeneratorName() default "";

    public String exceptionCacheName() default "";

    public KeyGenerator keyGenerator() default @KeyGenerator(name = "");

    public String cacheableInteceptorName() default "";

    public String resolverFactoryName() default "";

    public ResolverFactory resolverFactory() default @ResolverFactory(name = "");
}

Explain:
The keyGenerator Name and keyGenerator will elaborate in the next article. refreshInterval defaults to one minute (60,000 L). Generally, you only need to set a value for cacheName.

Cached Key
Memory caches are mostly key-value stores. The keyGenerator Name and keyGenerator in the annotations can specify a custom key generation strategy. The default usage is not specified: com.googlecode.ehcache.annotations.key.HashCodeCacheKeyGenerator.

package com.googlecode.ehcache.annotations.key;
/**
 * @author Eric Dalquist
 * @version $Revision: 656 $
 */
public class HashCodeCacheKeyGenerator extends AbstractHashingCacheKeyGenerator<HashCodeCacheKeyGenerator.LongGenerator, Long> {}

The hierarchical structure of classes is not listed here. Interested ones can go over the wall to get down the source code. Here are the specific methods of generation.

package com.googlecode.ehcache.annotations.key;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.IdentityHashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;

/**
 * Base class for cache key generators. Handles common logic for including/excluding the method
 * signature from key generation. Also provides support for avoiding circular references for key
 * generators that traverse the argument object graph via the {@link #register(Object)} and
 * {@link #unregister(Object)} APIs 
 * 
 * @author Eric Dalquist
 * @version $Revision: 656 $
 */
public abstract class AbstractCacheKeyGenerator<T extends Serializable> implements CacheKeyGenerator<T> {
     //ETC

     /* (non-Javadoc)
     * @see com.googlecode.ehcache.annotations.key.CacheKeyGenerator#generateKey(org.aopalliance.intercept.MethodInvocation)
     */
    public T generateKey(MethodInvocation methodInvocation) {
        final Object[] arguments = methodInvocation.getArguments();

        if (this.includeMethod) {
            final Method method = methodInvocation.getMethod();

            final Class<?> declaringClass = method.getDeclaringClass();
            final String name = method.getName();
            final Class<?> returnType = method.getReturnType();

            if (this.includeParameterTypes) {
                final Class<?>[] parameterTypes = method.getParameterTypes();
                return this.generateKey(declaringClass, name, returnType, parameterTypes, arguments);
            }

            return this.generateKey(declaringClass, name, returnType, arguments);
        }

        try {
            return this.generateKey(arguments);
        }
        finally {
            if (this.checkforCycles) {
                //Cleanup our thread local data
                REGISTRY.remove();
            }
        }
    }   
}

Explain:

Under the org.aopalliance.intercept package in aopalliance-1.0.jar, MethodInvocation inherits the getArguments of the Method that Invocation can get, and the rest are available under the reflection package.

method.getName() returns the name of the method
method.getReturnType() Returns the return value type of the method
method.getParameterTypes() Returns the parameter type of the method

The elements that locate a method in the code are all: class full name + method signature (return value + method name + parameter list)

Different values of parameters can also generate unique key s

package com.googlecode.ehcache.annotations.interceptor;
/**
 * Intercepter that handles invocations on methods annotated with {@link Cacheable} or {@link TriggersRemove}.
 * 
 * @author Eric Dalquist
 * @version $Revision: 681 $
 */
public class EhCacheInterceptor implements MethodInterceptor {
    //ETC

    /**
     * Creates a {@link Serializable} cache key from the {@link MethodInvocation} and configuration attributes.
     * 
     * @param methodInvocation Invocation to build the key for
     * @param methodAttribute Configuration for the invoked method
     * @return Generated cache key, must not return null.
     */
    protected Serializable generateCacheKey(MethodInvocation methodInvocation, final MethodAttribute methodAttribute) {
        final CacheKeyGenerator<? extends Serializable> cacheKeyGenerator = methodAttribute.getCacheKeyGenerator();

        final ParameterMask parameterMask = methodAttribute.getCacheKeyParameterMask();
        if (parameterMask.shouldMask()) {
            methodInvocation = new ParameterFilteringMethodInvocation(methodInvocation, parameterMask);
        }

        final Serializable cacheKey = cacheKeyGenerator.generateKey(methodInvocation);
        this.logger.debug("Generated key '{}' for invocation: {}", cacheKey, methodInvocation);
        return cacheKey;
    }
}

debug log

Generated key '-27052115907236245' for invocation: ReflectiveMethodInvocation: 
public net.htage.forum.entity.ForumPermissions net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions(net.htage.forum.entity.define.GlobalPermissionEnum); 
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]

Generated key '-27052113702228882' for invocation: ReflectiveMethodInvocation: 
public net.htage.forum.entity.ForumPermissions net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions(net.htage.forum.entity.define.GlobalPermissionEnum); 
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]

ReflectiveMethodInvocation :
Visibility modifier (public)+
Return value type (net.htage.forum.entity.ForumPermissions)+
Method Full Name (net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions)+
( +
List of parameter types (net.htage.forum.entity.define.GlobalPermissionEnum)+
);

It also shows that if a method has no parameters, the first call generates the key and caches it, and the next N calls are the same cache. Only one record can be found in the debug log.

Generated key '-937817555943' for invocation: ReflectiveMethodInvocation: 
public java.util.List net.htage.forum.impl.service.spring.EhcacheCacheBox.getAllLevel(); 
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]

No problem with global configuration. N calls are the same. But? A time-based approach (and it has no parameters) is not. The data must have changed between the second call and the 100th call. Which default key generation strategy is still available?

Posted by satyricon on Tue, 21 May 2019 16:39:49 -0700