当前位置: 首页 > 工具软件 > Infinispan > 使用案例 >

使用Hibernate和Spring设置分布式Infinispan缓存

凌宏大
2023-12-01

一个非常典型的设置–需要分布式缓存的spring / hibernate应用程序。 但是事实证明,设置并不是那么简单。

您显然需要缓存。 可以使用EhCache,Hazelcast,Infinispan,memcached,Redis,AWS的Elasticache以及其他一些方法来执行此操作。 但是,EhCache仅支持复制的缓存,不支持分布式缓存,并且Hazelcast尚未与最新版本的Hibernate一起使用。 Infinispan和Hazelcast支持一致的哈希,因此这些条目仅存在于特定实例上,而不是在每个实例的堆上具有所有缓存的完整副本。 Elasticache是​​特定于AWS的,因此Infinispann似乎是弹簧/休眠设置中最平衡的选项。

因此,让我们首先设置休眠二级缓存。 infinispan的官方文档并不是Google排名最高的结果-它通常是非常旧的文档,或者只是2个版本的旧文档。 您最好从首页打开最新的一个

下面的某些选项相当“隐藏”,在文档或现有的“操作方法”中我很难找到它们。

首先,将相关的依赖项添加到您的依赖项管理器配置中。 您需要infinispan-coreinfinispan-springhibernate-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

 类似资料: