首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用HazelCast的弹簧引导自定义缓存解析器和缓存管理器

使用HazelCast的弹簧引导自定义缓存解析器和缓存管理器
EN

Stack Overflow用户
提问于 2020-02-06 05:25:10
回答 1查看 1.9K关注 0票数 2

我有多个与HazelCast内核以及相关的问题。

让我先说明一下情况。

我们有一个监视多个网络基础设施的监控系统。

我有一个Spring应用程序,它可以作为负载平衡器后面的多个节点部署。除此之外,这个应用程序还可以在多个基础设施中运行,只需运行不同的配置文件,如infra-1-prod、infra-2-prod等。

它的水平可伸缩以及多用途。这一特性是通过使用不同配置文件运行应用程序来实现的。

随着其他事情的发生,这个概要文件改变了底层DB连接到一个包含特定基础结构的配置数据的关系数据库。

查看应用程序的相关体系结构。

同一个spring引导应用程序可以作为不同基础设施的节点运行,生成自己的HazelCast实例节点。如果应用程序有6个节点,那么HazelCast集群将有6个节点。他们都会同步的。

现在我有了一个名为RepositoryRuleRepository,它返回特定规则别名的Rule数据。

代码语言:javascript
复制
@Repository
public interface RuleRepository extends JpaRepository<Rule, Long> {
    @Cacheable(value = Constants.CACHE_ALIAS)
    Optional<Rule> findByAlias(String ruleAlias);

    //some other functions
}

现在的问题是,由于规则别名是由DB序列自动生成的,别名R_123指向Infra-1和Infra-2节点的不同数据,但由于所有HazelCast节点都是同步的,因此不正确的数据将被覆盖。

为此,我想为每个基础设施给缓存指定不同的名称,这样缓存的数据就不会乱七八糟。

这样做并不是直截了当的,因为我们不能将属性注入缓存名称。为此,我们需要实现我们自己的自定义CacheResolverCacheManager

在我提出第一个问题之前,我将阐述我对HazelCast的理解。

每个HazelCast实例都可以有多个Map配置,这些配置基本上就是不同的缓存。每个CacheManager都可以用一个HazelCast实例链接,该实例内部将包含多个缓存。

问题1:如果CacheManager和HazelCastInstance之间的关系是一对一的,那么我将如何确定将哪个方法数据缓存到哪个缓存中(Map )。

以下是我目前的未完成的实现。

代码语言:javascript
复制
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的类

代码语言:javascript
复制
@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

代码语言:javascript
复制
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

代码语言:javascript
复制
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和HazelCast的所有问题和文档似乎都不够深入。

问题3:有人能直接为我定义CacheResolverCacheManager的角色吗?

谢谢你的耐心。即使是一个问题的答案也可能对我有很大帮助。:)

EN

回答 1

Stack Overflow用户

发布于 2020-02-07 08:15:20

可以在@Cacheable注释中指定参数。例如:

代码语言:javascript
复制
@Cacheable("books")
public String getBookNameByIsbn(String isbn) {
    return findBookInSlowSource(isbn);
}

它将决定所使用的内部映射/缓存的名称。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60088208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档