自定义CacheInterceptor在默认情况下被Spring的CacheInterceptor覆盖

时间:2019-03-22 11:53:47

标签: java spring spring-boot spring-cache

我已经实现了一个自定义CacheInterceptor,可以通过通配符清除缓存:

public class CustomCacheInterceptor extends CacheInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomCacheInterceptor.class);

    @Override
    protected void doEvict(Cache cache, Object key) {
        try {
            // evict cache
        } catch (RuntimeException ex) {
            getErrorHandler().handleCacheEvictError(ex, cache, key);
        }
    }
}

现在我正在尝试使其工作:

@Configuration
public class CustomProxyCachingConfiguration extends ProxyCachingConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomProxyCachingConfiguration.class);

    @Bean
    public CacheInterceptor cacheInterceptor() {
        LOGGER.info("Creating custom cache interceptor");

        CacheInterceptor interceptor = new CustomCacheInterceptor();
        interceptor.setCacheOperationSources(cacheOperationSource());
        if (this.cacheResolver != null) {
            interceptor.setCacheResolver(this.cacheResolver);
        } else if (this.cacheManager != null) {
            interceptor.setCacheManager(this.cacheManager);
        }
        if (this.keyGenerator != null) {
            interceptor.setKeyGenerator(this.keyGenerator);
        }
        if (this.errorHandler != null) {
            interceptor.setErrorHandler(this.errorHandler);
        }
        return interceptor;
    }
}

问题是我的CustomCacheInterceptor在默认情况下被覆盖:

Overriding user-defined bean definition for bean 'cacheInterceptor' with a framework-generated bean definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=customProxyCachingConfiguration; factoryMethodName=cacheInterceptor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/package/test/CustomProxyCachingConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.cache.annotation.ProxyCachingConfiguration; factoryMethodName=cacheInterceptor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/cache/annotation/ProxyCachingConfiguration.class]]

我尝试了不同的方法来解决此问题:

1)试图用ProxyCachingConfiguration排除@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ProxyCachingConfiguration.class))并提供自己的BeanFactoryCacheOperationSourceAdvisor-没帮助

2)尝试过@Primary,但似乎仅在注射时有效-不适用于我的情况

3)尝试选择其他名称的bean-“ customCacheInterceptor”-在这种情况下,不会调用我的自定义类

4)尝试添加位于@DependsOn("cacheOperationSource")中的ProxyCachinConfiguration,以在配置之前使Spring加载ProxyCachinConfiguration-没有帮助

最奇怪的事情是,有时我的配置在应用程序启动时获胜,并且一切正常

如何用CacheInterceptor覆盖默认CustomCacheInterceptor

Spring Boot版本-2.0.0.RELEASE

1 个答案:

答案 0 :(得分:0)

Spring bean的重载是混乱的,应该避免。给定名称的最后一个bean定义会创建实际的bean,但定义之间没有可预测的顺序,因为它取决于多个因素,例如Groovy vs XML vs JavaConfig。

从您的上下文ProxyCachingConfiguration中排除@ComponentScan配置类并自己重新定义,同时提供CacheInterceptorBeanFactoryCacheOperationSourceAdvisor会更安全。

如果您的目标是只替换默认BeanFactoryCacheOperationSourceAdvisor bean中的建议集,则可以定义一个新的BeanPostProcessor bean,并在setAdvice()期间调用postProcessBeforeInitialization()