我有很多与HazelCast核心以及Spring Boot缓存API相关的问题。
让我先布置场景。
我们有一个用于监视多个网络基础结构的监视系统。
我有一个Spring Boot应用程序,可以将其部署为负载均衡器后面的多个节点。除此之外,只需使用不同的配置文件(例如infra-1-prod,infra-2-prod等)运行该同一个应用程序,即可在多种基础架构上使用。
它具有水平扩展性和通用性。这种性质是通过使用不同的配置文件运行应用程序来实现的。
除此以外,此配置文件更改还将基础数据库连接更改为包含特定基础结构的配置数据的关系数据库。
查看该应用程序的相关体系结构
同一个spring boot应用程序可以作为不同基础结构的节点运行,从而生成其自己的HazelCast实例节点。如果应用程序有6个节点,那么HazelCast群集将有6个节点。 所有这些都将同步。
现在我有一个名为Repository
的RuleRepository
,它返回特定Rule Alias的Rule
数据。
@Repository
public interface RuleRepository extends JpaRepository<Rule, Long> {
@Cacheable(value = Constants.CACHE_ALIAS)
Optional<Rule> findByAlias(String ruleAlias);
//some other functions
}
现在的问题是,由于规则别名是由数据库序列自动生成的,别名R_123指向Infra-1和Infra-2节点的不同数据,但是由于所有HazelCast节点都处于同步状态,因此数据不正确被覆盖。
为此,我考虑为每个基础结构给缓存指定不同的名称,以免缓存的数据混乱。
这样做很简单,因为我们不能将属性注入到缓存名称中。为此,我们需要实现自己的自定义CacheResolver
和CacheManager
。在问第一个问题之前,我将阐明对HazelCast的理解。
每个HazelCast实例可以具有多个地图配置,这些地图配置基本上只是不同的缓存。每个CacheManager都可以与单个HazelCast实例链接,该实例内部将包含多个缓存。
问题1:如果CacheManager与HazelCastInstance之间的关系是一对一的,那么我将如何确定将哪些方法数据缓存到哪个缓存中(映射配置)。这里是我目前有的不完整的实现
public class CacheableOperations {
private final CacheManager cacheManager;
private final CacheManager noOpCacheManager;
public CacheableOperations(CacheManager cacheManager, CacheManager noOpCacheManager) {
this.cacheManager = cacheManager;
this.noOpCacheManager = noOpCacheManager;
}
private Map<String, CacheableOperation<?>> opMap;
public void init() {
List<CacheableOperation<? extends Class>> ops = new ArrayList<>();
ops.add(new CacheableOperation.Builder(RuleRepository.class)
.method("findByAlias")
.cacheManager(cacheManager)
.build());
postProcessOperations(ops);
}
public CacheableOperation<?> get(CacheOperationInvocationContext<?> context) {
final String queryKey = getOperationKey(context.getTarget().getClass().getName(),
context.getMethod().getName());
return opMap.get(queryKey);
}
private void postProcessOperations(List<CacheableOperation<? extends Class>> ops) {
Map<String, CacheableOperation<?>> tempMap = new HashMap<>();
for (CacheableOperation<?> op : ops) {
for (String methodName : op.getMethodNames()) {
tempMap.put(getOperationKey(op.getTargetClass().getName(), methodName), op);
}
}
opMap = ImmutableMap.copyOf(tempMap);
}
private String getOperationKey(String first, String second) {
return String.format("%s-%s", first, second);
}
这里是CacheConfiguration
的课程
@Configuration
@AllArgsConstructor
public class CacheConfiguration extends CachingConfigurerSupport {
private final CacheProperties cacheProperties;
private SysdiagProperties sysdiagProperties;
@Bean
@Override
public CacheManager cacheManager() {
return new HazelcastCacheManager(hazelcastInstance());
}
@Bean
@Profile("client")
HazelcastInstance hazelcastInstance() {
Config config = new Config();
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember(sysdiagProperties.getCache().getMemberIps()).setEnabled(true);
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
config.setInstanceName("restapi-master-cache-" + sysdiagProperties.getServiceName());
return Hazelcast.newHazelcastInstance(config);
}
@Bean
@Override
public CacheResolver cacheResolver() {
return new CustomCacheResolver(cacheProperties, operations(), noOpCacheManager());
}
@Bean
public CacheManager noOpCacheManager() {
return new NoOpCacheManager();
}
@Bean
public CacheableOperations operations() {
CacheableOperations operations = new CacheableOperations(cacheManager(), noOpCacheManager());
operations.init();
return operations;
}
这里是CacheableOperation
类
public class CacheableOperation<T> {
private final Class<T> targetClass;
private final String[] methodNames;
private final CacheManager cacheManager;
private CacheableOperation(Class<T> targetClass, String[] methodNames, CacheManager cacheManager) {
this.targetClass = targetClass;
this.methodNames = methodNames;
this.cacheManager = cacheManager;
}
public Class<T> getTargetClass() {
return targetClass;
}
public String[] getMethodNames() {
return methodNames;
}
public CacheManager getCacheManager() {
return cacheManager;
}
public static class Builder<T> {
private final Class<T> targetClass;
private String[] methodNames;
private CacheManager cacheManager;
private Map<String, Method> methods = new HashMap<>();
public Builder(Class<T> targetClass) {
this.targetClass = targetClass;
Arrays.stream(targetClass.getDeclaredMethods())
.forEachOrdered(method -> methods.put(method.getName(), method));
}
public Builder<T> method(String... methodNames) {
this.methodNames = methodNames;
return this;
}
public Builder<T> cacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
return this;
}
public CacheableOperation<T> build() {
checkArgument(targetClass != null);
checkArgument(ArrayUtils.isNotEmpty(methodNames));
checkArgument(Arrays.stream(methodNames).allMatch(name -> methods.get(name) != null));
return new CacheableOperation<T>(targetClass, methodNames, cacheManager);
}
}
}
最后是CacheResolver
public class CustomCacheResolver implements CacheResolver {
private final CacheableOperations operations;
private final CacheProperties cacheProperties;
private final CacheManager noOpCacheManager;
public CustomCacheResolver(CacheProperties cacheProperties, CacheableOperations operations, CacheManager noOpCacheManager) {
this.cacheProperties = cacheProperties;
this.operations = operations;
this.noOpCacheManager = noOpCacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
if (!cacheProperties.isEnabled()) {
return getCaches(noOpCacheManager, context);
}
Collection<Cache> caches = new ArrayList<>();
CacheableOperation operation = operations.get(context);
if (operation != null) {
CacheManager cacheManager = operation.getCacheManager();
if (cacheManager != null) {
caches = getCaches(cacheManager, context);
}
}
return caches;
}
private Collection<Cache> getCaches(CacheManager cacheManager, CacheOperationInvocationContext<?> context) {
return context.getOperation().getCacheNames().stream()
.map(cacheName -> cacheManager.getCache(cacheName))
.filter(cache -> cache != null)
.collect(Collectors.toList());
}
}
问题2:在整个代码库中,我找不到在第一段代码中所做的缓存名称和方法名称之间的链接。我所看到的只是方法名称和cacheManager
实例之间的链接。我在哪里定义?
在这种情况下,我阅读的有关Spring Boot和HazelCast的所有问题和文档似乎没有深入。
问题3:有人可以直接为我定义CacheResolver
和CacheManager
的角色。感谢您的耐心等待。回答甚至一个问题都可能对我有很大帮助。 :)
我有很多与HazelCast核心以及Spring Boot缓存API相关的问题。让我先布置场景。我们有一个监视系统,用于监视多个网络基础结构。 ...
@Cacheable
批注中指定参数。例如: