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

能否在Feign客户端使用Spring @Cache*注解?缓存失效问题求证

Great question! Let's break this down clearly:

First, the straight answer: Feign clients do NOT natively support Spring's @Cacheable, @CachePut, or other cache annotations out of the box. The reason behind this is that Feign creates dynamic proxy classes for your client interfaces at runtime, and Spring's caching aspect doesn't automatically weave into these proxies by default. That's why your cache configuration didn't take effect even after adding the annotations to the Feign client methods.

Now, here are the most practical solutions to get caching working with your token-fetching Feign client:

1. Move Caching Logic to a Wrapper Service (Simplest & Most Reliable)

Instead of annotating the Feign client directly, create a dedicated service class that calls the Feign client, and apply the caching annotations to this service's methods. This works because Spring's caching aspect will properly intercept calls to Spring-managed beans like your service.

Example code:

@Service
public class TokenManagementService {
    private final TokenFeignClient tokenFeignClient;

    // Constructor injection (preferred over @Autowired)
    public TokenManagementService(TokenFeignClient tokenFeignClient) {
        this.tokenFeignClient = tokenFeignClient;
    }

    @Cacheable(value = "authTokens", key = "#clientId")
    public String getAuthToken(String clientId) {
        // Delegate the call to your Feign client
        return tokenFeignClient.requestToken(clientId);
    }
}

Then have your application code call TokenManagementService.getAuthToken() instead of the Feign client directly.

2. Configure Feign to Work with Spring Caching Aspect

If you absolutely need to apply caching directly on the Feign client interface, you'll need to adjust Feign's proxy configuration to ensure Spring's caching aspect is woven into the Feign proxy.

Here's how to do it:

  • First, make sure your application has @EnableCaching and @EnableFeignClients on the main class.
  • Create a custom Feign configuration class that ensures the Spring AOP proxy wraps the Feign proxy:
@Configuration
public class FeignCachingConfig {
    @Bean
    public Targeter targeter(CacheInterceptor cacheInterceptor) {
        return (target, feign) -> {
            Object feignProxy = feign.newInstance(target);
            // Apply Spring's caching aspect to the Feign proxy
            ProxyFactory proxyFactory = new ProxyFactory(feignProxy);
            proxyFactory.addAdvice(cacheInterceptor);
            proxyFactory.setProxyTargetClass(true);
            return proxyFactory.getProxy();
        };
    }
}
  • Then reference this configuration in your Feign client:
@FeignClient(name = "token-service", configuration = FeignCachingConfig.class)
public interface TokenFeignClient {
    @GetMapping("/api/token")
    @Cacheable(value = "authTokens", key = "#clientId")
    String requestToken(@RequestParam String clientId);
}

Note: This approach is more complex and may have compatibility issues with different Spring Cloud versions, so test thoroughly.

3. Implement Custom Caching via Feign Request Interceptor

You can also build caching logic directly into a Feign interceptor. This gives you full control but requires manual handling of cache keys, expiration, and cache hits/misses.

Example interceptor snippet (for request-side caching; you'll need additional handling for response caching):

@Component
public class TokenCacheInterceptor implements RequestInterceptor {
    private final CacheManager cacheManager;

    public TokenCacheInterceptor(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Override
    public void apply(RequestTemplate template) {
        String clientId = template.query("clientId");
        Cache cache = cacheManager.getCache("authTokens");
        if (cache != null) {
            String cachedToken = cache.get(clientId, String.class);
            if (cachedToken != null) {
                // To use the cached value, you'll need to mock a response (requires additional setup)
                // Alternatively, shift caching logic to a response interceptor to store results after successful calls
            }
        }
    }
}

This method is not recommended unless you have very specific caching needs that can't be met with the first two approaches.

Final Checks

Double-check that your Guava cache configuration is correctly set up (e.g., cache names match, expiration policies are defined) and that @EnableCaching is present on your configuration class.

The wrapper service approach is the most widely used because it avoids proxy conflicts and keeps your code clean and maintainable.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:16:05