使用EventListener导致与存储库的循环依赖

问题描述 投票:0回答:1

一旦缓存条目过期,我尝试使用 EntryExpiredListener 使用另一个服务执行操作,但如果它正在调用服务,并且该服务正在调用系统中的任何存储库,我无法将侦听器添加到缓存中

The dependencies of some of the beans in the application context form a cycle:

   filterChainExceptionHandler (field private org.springframework.web.servlet.HandlerExceptionResolver sb.practice.configs.security.filters.FilterChainExceptionHandler.resolver)
      ↓
   org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration
      ↓
   openEntityManagerInViewInterceptorConfigurer defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration$JpaWebConfiguration.class]
      ↓
   openEntityManagerInViewInterceptor defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration$JpaWebConfiguration.class]
┌─────┐
|  cacheManager defined in class path resource [org/springframework/boot/autoconfigure/cache/HazelcastCacheConfiguration.class]
↑     ↓
|  cacheService defined in file [D:\Dev\Locals\pt-spring-boot\target\classes\sb\practice\services\impl\CacheService.class]
↑     ↓
|  activeUserCacheService_Hazelcast defined in file [D:\Dev\Locals\pt-spring-boot\target\classes\sb\practice\services\impl\caches\ActiveUserCacheService_Hazelcast.class]
↑     ↓
|  masterRoleRepository defined in sb.practice.repositories.masters.MasterRoleRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
↑     ↓
|  (inner bean)#28f48a7c
└─────┘

这是我的缓存监听器:

@Slf4j
public class CacheListener implements EntryExpiredListener<String, String>{
    
    public ActiveUserCacheService_Hazelcast activeUsersCache;

    @Override
    public void entryExpired(EntryEvent<String, String> event) {
        log.info("entryEvicted. Cache: {}. Value: {}. \nEvent: {} ", event.getName(), event.getOldValue(), event);
    }
}

缓存服务:

@Service
@RequiredArgsConstructor
public class CacheService {

    
    @Value("${hazelcast.cache.cluster.nodes}")
    String[] clusteringNodes;
    
    private final ActiveUserCacheService_Hazelcast activeUserCacheService_Hazelcast;

    public <T> boolean containsKey(long key, String cacheName) {
        IMap<Long, T> map = hazelcastInstance().getMap(cacheName);
        return map.containsKey(key);
    }

    private static MapConfig mapConfig(String name, Integer timeToLive) {

        MapConfig mapConfig = new MapConfig(name);
        mapConfig.setTimeToLiveSeconds(timeToLive);
//
//      EntryListenerConfig entryListenerConfig = new EntryListenerConfig();
//      entryListenerConfig.setImplementation(new CacheListener());
//      mapConfig.addEntryListenerConfig(entryListenerConfig);

        final EvictionConfig evictionConfig = new EvictionConfig();
        evictionConfig.setEvictionPolicy(EvictionPolicy.LRU);
        evictionConfig.setMaxSizePolicy(MaxSizePolicy.PER_NODE);
        evictionConfig.setSize(500);

        mapConfig.setEvictionConfig(evictionConfig);
        return mapConfig;
    }

    @Bean
    HazelcastInstance hazelcastInstance() {

        Config config = new Config();
        CacheConstants.CACHES.forEach((name, timeToLive) -> config.addMapConfig(mapConfig(name, timeToLive)));

        NetworkConfig network = config.getNetworkConfig();
        network.setPort(5701).setPortCount(20);
        network.setPortAutoIncrement(true);

        JoinConfig join = network.getJoin();
        join.getMulticastConfig().setEnabled(false);
        join.getTcpIpConfig().setEnabled(true);

        for (String clusteringNode : clusteringNodes) {
            join.getTcpIpConfig().addMember(clusteringNode);
        }

        return Hazelcast.newHazelcastInstance(config);
    }

}

该服务仅包含对 masterRoleRepository 的注入,这导致了问题。 有没有办法使用EventListener作为组件并调用服务来做逻辑?

提前谢谢您!

spring spring-boot hazelcast event-listener
1个回答
0
投票

如果你有这样的配置,你可以将监听器创建为bean

@Configuration
@EnableAsync
public class HazelcastInstanceConfiguration {

  public static final String MAP_NAME = "myMap";

  @Bean
  public Config hazelcastConfig() {
    Config config = new Config();

    // Configure the map
    MapConfig mapConfig = config.getMapConfig(MAP_NAME);
    mapConfig.setTimeToLiveSeconds(30);

    EntryListenerConfig entryListenerConfig = new EntryListenerConfig();
    entryListenerConfig.setImplementation(cacheListener());
    mapConfig.addEntryListenerConfig(entryListenerConfig);

    return config;
  }

  @Bean
  CacheListener cacheListener() {
    return new CacheListener();
  }
}

在监听器中使用 setter 注入服务

@Slf4j
@RequiredArgsConstructor
public class CacheListener implements EntryExpiredListener<String, String> {

  private MyService myService;

  @Autowired
  public void setMyService(MyService myService) {
    this.myService = myService;
  }

  @Override
  public void entryExpired(EntryEvent<String, String> event) {
    log.info("entryEvicted. Cache: {}. Value: {}. \nEvent: {} ", 
      event.getName(), event.getOldValue(), event);
    myService.deleteFromRepository(event.getKey());
  }
}

使服务异步,以免阻塞 hazelcast 线程

@Service
@Slf4j
public class MyService {

  @Async
  public void deleteFromRepository(String key) {
    log.info("deleteFromRepository is called for key : {}", key);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.