如何在Spring非组件类中实现缓存功能?
Got it, let's work through this problem together. Since your class can’t be turned into a Spring-managed component (it’s initialized at runtime), the standard annotation-driven caching won’t work out of the box. Here are three practical ways to add caching to your method:
Approach 1: Manually Use Spring's CacheManager
If you still want to leverage Spring's existing caching infrastructure, you can directly interact with CacheManager instead of relying on annotations. This is straightforward and avoids proxying overhead.
First, make sure you have @EnableCaching configured in your Spring context. Then, pass the CacheManager to your runtime-initialized class (you can fetch it from the Spring application context if needed):
import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; public class NonSpringClass { private final CacheManager cacheManager; // Inject CacheManager when creating the instance at runtime public NonSpringClass(CacheManager cacheManager) { this.cacheManager = cacheManager; } public Object addToCache(String cacheKey) { // Compute your response first (matches @CachePut's behavior of updating cache after computation) Object response = computeYourResult(); // Get the target cache and put the value Cache cache = cacheManager.getCache("NAME_OF_CACHE"); if (cache != null) { cache.put(cacheKey, response); } return response; } private Object computeYourResult() { // Your actual computation logic here return new Object(); } }
Pros: Simple, integrates with your existing Spring cache setup.
Cons: Loses the declarative simplicity of annotations—you have to write cache logic manually.
Approach 2: Wrap Your Runtime Object with a Spring Proxy
If you want to keep using @CachePut (or other caching annotations), you can create a dynamic proxy around your runtime-initialized object. Spring's AOP framework can weave the caching advice into the proxy, making the annotations work as expected.
First, ensure @EnableCaching is enabled in your Spring config. Then, when creating your class instance at runtime, wrap it with a proxy:
import org.springframework.aop.framework.ProxyFactory; import org.springframework.cache.annotation.CachePut; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.EnableCaching; // Spring config to enable caching @EnableCaching public class CacheConfiguration {} public class NonSpringClass { // Keep your @CachePut annotation as is @CachePut(cacheNames = {"NAME_OF_CACHE"}) public Object addToCache(String cacheKey) { // Some computation here return new Object(); } } // When initializing your class at runtime: public class RuntimeInitializer { public static void main(String[] args) { // Initialize Spring context with caching enabled AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CacheConfiguration.class); // Create your non-Spring instance NonSpringClass originalInstance = new NonSpringClass(); // Create a proxy that applies Spring's caching advice ProxyFactory proxyFactory = new ProxyFactory(originalInstance); proxyFactory.addAdvisor(context.getBean("cacheAdvisor")); // Fetch the built-in caching advisor // Use the proxied instance instead of the original NonSpringClass proxiedInstance = (NonSpringClass) proxyFactory.getProxy(); // Now calling this method will trigger @CachePut logic! proxiedInstance.addToCache("my-cache-key"); } }
Pros: Keeps your existing annotation-based code, integrates fully with Spring caching.
Cons: Requires access to the Spring application context at runtime, adds proxying layer.
Approach 3: Implement Custom Caching with a Third-Party Library
If you don’t need to integrate with Spring’s caching system, you can implement caching manually using a lightweight library like Caffeine or Guava Cache. This is great for standalone scenarios where Spring context isn’t available or you want full control.
Here’s an example with Caffeine:
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import java.util.concurrent.TimeUnit; public class NonSpringClass { // Configure your cache with expiration, size limits, etc. private final Cache<String, Object> cache = Caffeine.newBuilder() .expireAfterWrite(15, TimeUnit.MINUTES) .maximumSize(500) .build(); public Object addToCache(String cacheKey) { Object response = computeYourResult(); cache.put(cacheKey, response); return response; } private Object computeYourResult() { // Your computation logic here return new Object(); } }
Pros: No Spring dependency, fully customizable, lightweight.
Cons: Doesn’t integrate with Spring’s cache management (e.g., cache eviction events, centralized config).
内容的提问来源于stack exchange,提问作者pkgajulapalli

