You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring拦截器Redis缓存失效求助(控制器@Cacheable正常)

问题分析与解决方案

你的拦截器中@Cacheable注解不生效的核心原因是Spring AOP的代理机制限制:当你在同一个类内部调用带有@Cacheable的方法时(比如preHandle直接调用authenticateUser),这个调用不会经过Spring的AOP代理,因此缓存逻辑不会被触发。而控制器中的@Cacheable能正常工作,是因为控制器方法是被外部的DispatcherServlet调用的,走了代理流程。

下面是两种可行的解决方案,优先推荐第一种:


方案1:将认证逻辑抽离到独立Service类(最佳实践)

把认证逻辑单独封装成一个Spring管理的Service组件,让拦截器依赖这个Service。这样调用Service的方法时,会经过AOP代理,缓存注解就能正常生效,同时也符合单一职责原则。

步骤1:创建AuthService

@Component
public class AuthService {

    @Cacheable(value = "authenticateUser")
    public Map<String, List> authenticateUser(String username, String password) {
        // 原有的用户认证逻辑
        return userRoles;
    }
}

步骤2:修改拦截器注入并调用Service

@Component
@Profile({"dev","prod"})
public class AuthenticationInterceptor extends HandlerInterceptorAdapter {

    private final AuthService authService;

    // 构造注入(推荐使用构造注入替代字段注入)
    @Autowired
    public AuthenticationInterceptor(AuthService authService) {
        this.authService = authService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws UnauthorisedAccessException {
        // 改为调用AuthService的方法,触发缓存逻辑
        Map<String, List> userRoles = authService.authenticateUser(username, password);
        // ... 后续权限校验逻辑
        return authorizationResult;
    }
}

方案2:获取自身代理对象调用方法(应急方案)

如果暂时不想抽离代码,可以让拦截器获取自己的Spring代理对象,通过代理对象调用authenticateUser方法,绕开内部调用的限制。不过这种方式不够优雅,不推荐长期使用。

@Component
@Profile({"dev","prod"})
public class AuthenticationInterceptor extends HandlerInterceptorAdapter implements ApplicationContextAware {

    private AuthenticationInterceptor proxySelf;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 从Spring上下文获取当前类的代理对象
        this.proxySelf = applicationContext.getBean(AuthenticationInterceptor.class);
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws UnauthorisedAccessException {
        // 调用代理对象的方法,触发缓存
        Map<String, List> userRoles = proxySelf.authenticateUser(username, password);
        // ... 后续逻辑
        return authorizationResult;
    }

    @Cacheable(value = "authenticateUser")
    public Map<String, List> authenticateUser(String username, String password) {
        // 原有的认证逻辑
        return userRoles;
    }
}

额外检查项

确保你的项目满足以下条件:

  • 已经在某个@Configuration配置类上添加了@EnableCaching注解,且该配置类被Spring扫描到;
  • 拦截器是通过Spring容器注册的,而非直接new实例。比如在WebMvc配置类中注入拦截器:
    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    
        private final AuthenticationInterceptor authInterceptor;
    
        @Autowired
        public WebMvcConfig(AuthenticationInterceptor authInterceptor) {
            this.authInterceptor = authInterceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authInterceptor)
                    .addPathPatterns("/**"); // 根据你的业务配置拦截路径
        }
    }
    

内容的提问来源于stack exchange,提问作者rafrul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:19:55