EE8 JCache注释CacheResult不起作用

时间:2019-09-06 13:55:39

标签: java ehcache jcache java-ee-8

我正在使用EhCache作为JCache实现(JSR 107)在JBoss EAP 7.2(EE8)下开发WEB APP

我有此代码:

@Inject
CacheManager cacheManager;

@CacheResult(cacheName = "roles")
public List<RoleDTO> get(@CacheKey String id) {
    return service.getRoles(id);
}

public List<RoleDTO> getRoles(final String userId) {

    final List<RoleDTO> output = get(userId);

    return output;
}

根据我读过的article,我希望第二次访问get(userId)方法应该使用缓存,而忽略输入该方法,但事实并非如此。 我还查询注入的cacheManager,“角色”缓存始终为空。

我在哪里错了?

编辑

我想EhCache 3.x在标准EE环境中不支持jcache注释,在网络上我只能看到ri guice等其他CDI实现。 但是,通过包括以下实现之一,例如:

    <dependency>
        <groupId>org.jsr107.ri</groupId>
        <artifactId>cache-annotations-ri-cdi</artifactId>
    </dependency>

似乎将新的缓存条目放置到新的缓存管理器中(请参见下面的代码)

 Caching.getCachingProvider().getCacheManager

代替我已经拥有的注入和配置的CacheManager

编辑编辑

@CacheResult(cacheName = "roles", cacheResolverFactory = AppCacheResolverFactory.class, cacheKeyGenerator = CacheKeyGeneratorFactory.class)
    public List<RoleDTO> getRoles(@CacheKey final String userId) {

这是我的 CacheResolverFactory

public class AppCacheResolverFactory implements CacheResolverFactory {


    @Inject
    CacheManager cacheManager;

    @Override
    public CacheResolver getCacheResolver(CacheMethodDetails<? extends Annotation> cacheMethodDetails) {
        return new DefaultCacheResolver(cacheManager.getCache(cacheMethodDetails.getCacheName()));
    }

    @Override
    public CacheResolver getExceptionCacheResolver(CacheMethodDetails<CacheResult> cacheMethodDetails) {
        return null;
    }
}

现在我明白了:

java.lang.ClassCastException: Invalid key type, expected : java.lang.String but was : org.jsr107.ri.annotations.DefaultGeneratedCacheKey

EDIT EDIT EDIT

我创建了一个CacheKeyGeneratorFactory和一个包装字符串值的StringCacheKey:

CacheKeyGeneratorFactory

public class CacheKeyGeneratorFactory implements CacheKeyGenerator {
    @Override
    public GeneratedCacheKey generateCacheKey(CacheKeyInvocationContext<? extends Annotation> cacheKeyInvocationContext) {
        final CacheInvocationParameter[] allParameters = cacheKeyInvocationContext.getAllParameters();
        for (CacheInvocationParameter parameter : allParameters) {
            if (StringCacheKey.class.equals(parameter.getRawType())) {
                return (StringCacheKey)parameter.getValue();
            }
        }
        return null;
    }
}

StringCacheKey

public class StringCacheKey implements GeneratedCacheKey {

    private String value;

    public StringCacheKey(String param) {
        this.value = param;
    }

    @Override
    public int hashCode() {
        return this.value.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return obj != null && obj.getClass() == this.getClass() && this.value.equals(((StringCacheKey)obj).getValue());
    }

    public String getValue() {
        return value;
    }
}

然后我用以下方法更改了ehcache.xml配置:

 <cache alias="roles">
    <key-type>mypackage.StringCacheKey</key-type>
    <value-type>java.util.List</value-type>

还有@CacheResult的方法

public List<RoleDTO> get(@CacheKey String id) 

现在可以了,但是我想知道我可以保存所有这些代码和类来使其工作:/

1 个答案:

答案 0 :(得分:1)

RI默认将密钥包装到DefaultGeneratedCacheKey中。您需要更改EHCache配置,以允许密钥的Object类型。另外,您可以注册自己的密钥生成器并使用自己的密钥类型。当然,您也可以在EHCache配置中指定org.jsr107.ri.annotations.DefaultGeneratedCacheKey,然后绑定到特定的实现。

不幸的是,用于注释的JSR107 / JCache标准要求高速缓存键实现接口GeneratedCacheKey。这意味着,如果您有一个简单的缓存键(如int或string),那么在存储到缓存中时,总是需要将它们包装起来。

侧面说明:接口GeneratedCacheKey不需要技术,因为它没有定义任何新方法。这是标准中的已知问题。不幸的是,在标准最终定稿之前,注释部分没有得到足够的审查。