一个非常典型的设置–需要分布式缓存的spring / hibernate应用程序。 但是事实证明,设置并不是那么简单。
您显然需要缓存。 可以使用EhCache,Hazelcast,Infinispan,memcached,Redis,AWS的Elasticache以及其他一些方法来执行此操作。 但是,EhCache仅支持复制的缓存,不支持分布式缓存,并且Hazelcast尚未与最新版本的Hibernate一起使用。 Infinispan和Hazelcast支持一致的哈希,因此这些条目仅存在于特定实例上,而不是在每个实例的堆上具有所有缓存的完整副本。 Elasticache是特定于AWS的,因此Infinispann似乎是弹簧/休眠设置中最平衡的选项。
因此,让我们首先设置休眠二级缓存。 infinispan的官方文档并不是Google排名最高的结果-它通常是非常旧的文档,或者只是2个版本的旧文档。 您最好从首页打开最新的一个 。
下面的某些选项相当“隐藏”,在文档或现有的“操作方法”中我很难找到它们。
首先,将相关的依赖项添加到您的依赖项管理器配置中。 您需要infinispan-core
, infinispan-spring
和hibernate-infinispan
。 然后在您的configuratoin文件中(无论是哪个文件-在我的情况下是jpa.xml,这是一个定义JPA属性的弹簧文件)配置以下内容:
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.infinispan.InfinispanRegionFactory</prop>
<prop key="hibernate.cache.inifinispan.statistics">true</prop>
<prop key="hibernate.cache.infinispan.cfg">infinispan.xml</prop>
<prop key="hibernate.cache.infinispan.query.cfg">distributed-query</prop>
这些设置使用默认的区域工厂启用二级缓存和查询缓存(我们将看到为什么以后可能需要将其更改为自定义的),启用统计信息,指向infinispan.xml配置文件并更改默认名称。查询缓存,以便能够使用分布式缓存(默认情况下为“本地缓存”)。 当然,您可以将所有这些外部化为.properties文件。
然后,在类路径的根目录(src / main / resources)中创建infinispan.xml:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:8.1 http://www.infinispan.org/schemas/infinispan-config-8.1.xsd
urn:infinispan:config:store:jdbc:8.0 http://www.infinispan.org/schemas/infinispan-cachestore-jpa-config-8.0.xsd"
xmlns="urn:infinispan:config:8.1">
<jgroups>
<stack-file name="external-file" path="${jgroups.config.path:jgroups-defaults.xml}" />
</jgroups>
<cache-container default-cache="default" statistics="true">
<transport stack="external-file" />
<distributed-cache-configuration name="entity" statistics="true" />
<distributed-cache-configuration name="distributed-query" statistics="true" />
</cache-container>
</infinispan>
这期望将-Djgroups.config.path
传递给JVM,以指向jgroups配置。 根据您使用的是自己的设置还是AWS,有多个选项。 在这里,您可以找到 EC2,Google云以及基本UDP和TCP机制的配置文件 。 这些应该放置在项目本身之外,因为在本地您很可能不想使用S3_PING(用于节点检测的基于S3的机制),并且值在环境之间可能会有所不同。
如果您需要统计信息(最好有它们),则必须在缓存容器级别和缓存级别都启用它们。 我实际上不知道休眠属性中的statistics选项在做什么–它对我没有任何改变。
然后定义每个缓存。 您的实体应使用类似的注释
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "user")
public class User { .. }
然后Infinispan自动创建缓存。 它们都可以共享一些默认设置,并且这些默认值是为名为“实体”的缓存定义的。 花了我一段时间才找到答案 , 最后得到关于stackoverflow的答案 。 最后一件事是查询缓存(使用我们在休眠属性中定义的名称)。 请注意“ distributed-cache-configuration”元素-这样,您可以明确地说“此(或所有)缓存必须是分布式的”(它们将使用jgroups文件中指定的传输机制)。 如果您不想强制开发人员指定jvm参数,则可以在jgroups-defaults.xml中配置默认值,并指向如上例所示的默认值。
例如,您可以使用<distributed-cache-configuration name="user" />
定义特定于实体的属性(检查XSD的自动完成功能以查看具有哪些配置选项( XML是一种非常方便的配置DSL,不是它吗?)。
到目前为止,一切都很好。 现在,只要我们在本地配置了正确的访问密钥,我们的缓存就可以在本地和AWS(EC2,S3)上运行。 从技术上讲,最好为本地和生产使用不同的infinispan.xml文件,并默认定义<local-cache>
而不是分布式文件,因为使用TCP或UDP设置,您可能最终会与同一个网络中的其他队友组成的集群(尽管我不确定,但是可能会出现一些意外问题)。
现在,春天。 如果仅设置spring,则可以使用SpringEmbeddedCacheManagerFactoryBean
创建一个bean,将classpath:infinispan.xml
作为资源位置传递,它将起作用。 如果您想要完全分离的缓存管理器,则仍然可以这样做。 但是缓存管理器是棘手的。 我已经概述了EhCache的问题 ,在这里我们必须做一些变通办法,以便在hibernate和spring之间共享缓存管理器。 那是否是个好主意,取决于情况。 但是,即使您需要单独的缓存管理器,也可能需要引用休眠基础缓存管理器,因此仍需要执行以下部分步骤。 使用单独的缓存的问题是它们在其下注册的JMX名称,但是我想也可以对其进行配置。
因此,如果我们需要共享的缓存管理器,则必须创建两个工厂类的子类:
/**
* A region factory that exposes the created cache manager as a static variable, so that
* it can be reused in other places (e.g. as spring cache)
*
* @author bozho
*
*/
public class SharedInfinispanRegionFactory extends InfinispanRegionFactory {
private static final long serialVersionUID = 1126940233087656551L;
private static EmbeddedCacheManager cacheManager;
public static EmbeddedCacheManager getSharedCacheManager() {
return cacheManager;
}
@Override
protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) {
EmbeddedCacheManager manager = super.createCacheManager(holder);
cacheManager = manager;
return manager;
}
@Override
protected EmbeddedCacheManager createCacheManager(Properties properties, ServiceRegistry serviceRegistry)
throws CacheException {
EmbeddedCacheManager manager = super.createCacheManager(properties, serviceRegistry);
cacheManager = manager;
return manager;
}
}
是的,一个静态变量。 整,我知道,所以要小心。
然后,我们将其在Spring重复使用:
/**
* A spring cache factory bean that reuses a previously instantiated infinispan embedded cache manager
* @author bozho
*
*/
public class SharedInfinispanCacheManagerFactoryBean extends SpringEmbeddedCacheManagerFactoryBean {
private static final Logger logger = ...;
@Override
protected EmbeddedCacheManager createBackingEmbeddedCacheManager() throws IOException {
EmbeddedCacheManager sharedManager = SharedInfinispanRegionFactory.getSharedCacheManager();
if (sharedManager == null) {
logger.warn("No shared EmbeddedCacheManager found. Make sure the hibernate 2nd level "
+ "cache provider is configured and instantiated.");
return super.createBackingEmbeddedCacheManager();
}
return sharedManager;
}
}
然后,将hibernate配置中的hibernate.cache.region.factory_class
属性更改为新的自定义类,并在我们的spring配置文件中执行以下操作:
<bean id="cacheManager" class="com.yourcompany.util.SharedInfinispanCacheManagerFactoryBean" />
<cache:annotation-driven />
Spring缓存与方法级别的@Cacheable
批注一起使用,该批注允许我们缓存方法调用,我们还可以通过简单的注入访问CacheManager
。
然后,“最后”部分是检查它是否有效。 即使您的应用程序启动正常并且看起来运行良好,您也应该运行集成或硒测试套件,并通过JMX检查统计信息。 您甚至可能进行了使用MBean来获取有关高速缓存的某些统计数据的测试,以确保正在使用它们。
翻译自: https://www.javacodegeeks.com/2016/02/setting-distributed-infinispan-cache-hibernate-spring.html