2015-05-26 23 views
5

Tôi có một dự án Khởi động mùa xuân với tuỳ chỉnh CacheResolver vì tôi cần quyết định thời gian chạy mà bộ nhớ cache tôi muốn sử dụng, tôi không có bất kỳ lỗi biên dịch nào, nhưng khi thực hiện một số kiểm tra và đặt thời gian nghỉ điểm tại tùy chỉnh của tôi CacheResolver nó không bao giờ bước vào nó.Tùy chỉnh CacheResolver không hoạt động

Đây là lớp Cấu hình của tôi cho Cache:

@Configuration 
@EnableCaching(proxyTargetClass = true) 
@PropertySource(CacheConfig.CLASSPATH_DEPLOY_CACHE_PROPERTIES_PROPERTIES) 
public class CacheConfig extends CachingConfigurerSupport{ 

     public static final String CLASSPATH_DEPLOY_CACHE_PROPERTIES_PROPERTIES = "classpath:/deploy/cache-properties.properties"; 

     public static final String CACHEABLE_DOCUMENTS_PROPERTY = "cacheable.documents"; 
     public static final String TTL_CACHEABLE_DOCUMENTS_PROPERTY = "ttl.cacheable.documents"; 
     public static final String SIZED_CACHEABLE_DOCUMENTS_PROPERTY = "sized.cacheable.documents"; 
     public static final String CACHE_NAME = "permanentCache"; 
     public static final String TTL_CACHE = "ttlCache"; 
     public static final String SIZED_CACHE = "sizedCache"; 
     public static final String CACHEABLE_DOCUMENTS = "cacheableDocuments"; 
     public static final String SIZED_CACHEABLE_DOCUMENTS = "sizedCacheableDocuments"; 
     public static final int WEIGHT = 1000000; 
     public static final int TO_KBYTES = 1000; 

     @Inject 
     protected Environment environment; 

     //@Bean 
     @Override 
     public CacheManager cacheManager() { 
     SimpleCacheManager cacheManager = new SimpleCacheManager(); 
     GuavaCache sizedCache = new GuavaCache(SIZED_CACHE, CacheBuilder.newBuilder().maximumWeight(WEIGHT).weigher(
       (key, storable) -> { 
        String json = ((Storable) storable).toJson(); 
        return json.getBytes().length/TO_KBYTES; 
       } 
     ).build()); 
     GuavaCache permanentCache = new GuavaCache(CACHE_NAME,CacheBuilder.newBuilder().build()); 
     //GuavaCache ttlCache = new GuavaCache(TTL_CACHE, CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build()); 
     cacheManager.setCaches(Arrays.asList(permanentCache,sizedCache)); 
     return cacheManager; 
     } 

     @Bean(name = "wgstCacheResolver") 
     @Override 
     public CacheResolver cacheResolver(){ 
     CacheResolver cacheResolver = new WgstCacheResolver(cacheManager(),cacheableDocuments(),sizedCacheableDocuments()); 
     return cacheResolver; 
     } 


     @Bean(name = CACHEABLE_DOCUMENTS) 
     public List<String> cacheableDocuments(){ 
     String[] cacheableDocuments = StringUtils.commaDelimitedListToStringArray(environment.getProperty(CACHEABLE_DOCUMENTS_PROPERTY)); 
     return Arrays.asList(cacheableDocuments); 
     } 

     @Bean(name = SIZED_CACHEABLE_DOCUMENTS) 
     public List<String> sizedCacheableDocuments(){ 
     String[] sizedCacheableDocuments = StringUtils.commaDelimitedListToStringArray(environment.getProperty(SIZED_CACHEABLE_DOCUMENTS_PROPERTY)); 
     return Arrays.asList(sizedCacheableDocuments); 
     } 
    } 

Đây là CacheResolver tôi

public class WgstCacheResolver extends AbstractCacheResolver { 

    private final List<String> cacheableDocuments; 
    private final List<String> sizedCacheableDocuments; 

    public WgstCacheResolver(final CacheManager cacheManager,final List<String> cacheableDocuments, final List<String> sizedCacheableDocuments) { 
    super(cacheManager); 
    this.cacheableDocuments = cacheableDocuments; 
    this.sizedCacheableDocuments = sizedCacheableDocuments; 
    } 

    /** 
    * Resolves the cache(s) to be updated on runtime 
    * @param context 
    * @return*/ 
    @Override 
    protected Collection<String> getCacheNames(final CacheOperationInvocationContext<?> context) { 

    final Collection<String> cacheNames = new ArrayList<>(); 
    final AbstractDao dao = (AbstractDao)context.getTarget(); 
    final String documentType = dao.getDocumentType().toString(); 
    if (cacheableDocuments.contains(documentType)){ 
     cacheNames.add("permanentCache"); 
    } 
    if (sizedCacheableDocuments.contains(documentType)){ 
     cacheNames.add("sizedCache"); 
    } 
    return cacheNames; 
    } 
} 

Và đây DAO của tôi, nơi tôi sử dụng bộ nhớ cache:

@Component 
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.DEFAULT) 
    @CacheConfig(cacheResolver = "wgstCacheResolver") 
    public class CacheableDao<T extends Storable> extends AbstractDao<T> { 

     private final Logger logger = LoggerFactory.getLogger(CacheableDao.class); 

     public CacheableDao(final Bucket bucket, final Class<T> typeParameterClass, final DocumentType documentType) { 
     super(bucket, typeParameterClass, documentType); 
     } 

     @Cacheable(key = "{#root.methodName, #root.target.generateFullKey(#key)}") 
     public T get(final String key) throws DatastoreAccessException, ObjectMappingException { 
     //do something 
     } 
. 
. 
. 
} 

Tôi có đã thử triển khai CacheResolver thay vì mở rộng AbstractCacheResolver nhưng không e bất kỳ sự khác biệt nào.

Cảm ơn bạn.

+0

Vâng, bạn không có bất kỳ tên bộ nhớ cache ở đó vì vậy nếu bộ nhớ đệm hoạt động, nó phải giải quyết tên bộ nhớ cache nếu không nó sẽ ném một ngoại lệ. Tôi đoán tốt nhất là bộ nhớ đệm không hoạt động chút nào. Cấu hình của bạn cũng rất _weird_. Bạn sử dụng 'CachingConfiguration' để cung cấp _default_' CacheResolver', do đó bạn không cần phải chỉ định nó. Nếu bạn muốn chỉ định nó cho mỗi hoạt động (với một tên đặc biệt), hãy xác định nó ở nơi khác (không phải là mặc định). –

+0

Cảm ơn bạn @ stéphane-nicoll, bạn đã chỉ cho tôi đúng hướng, tôi đã khắc phục sự cố bằng cách thêm tên bộ nhớ cache có sẵn với chú thích 'CacheConfig', chạy các kiểm tra và sửa lỗi của tôi và bây giờ tùy chỉnh' CacheResolver' đang hoạt động như mong đợi. Tôi giả định rằng tên bộ nhớ cache sẽ không cần phải được bao gồm khi 'CacheResolver' đã có. – tommylii

+0

Bạn được chào đón nhưng không cần tên bộ nhớ cache. Như tôi đã nói, nếu trình giải quyết bộ nhớ cache của bạn không được gọi và bạn không có ngoại lệ, có thể bạn không có bộ nhớ đệm nào cả. Câu trả lời dưới đây là không chính xác (trừ khi có lỗi) –

Trả lời

1

tên cache cần phải được đưa vào tại một số điểm, chỉ cần xác định CacheResolver sử dụng là không đủ, lớp @Cacheable cần phải nhận thức được tên bộ nhớ cache có sẵn, vì vậy tôi bao gồm họ với @CacheConfig chú thích:

@CacheConfig(cacheNames = {WgstCacheConfig.PERMANENT_CACHE, WgstCacheConfig.SIZED_CACHE}, 
    cacheResolver = WgstCacheConfig.WGST_CACHE_RESOLVER) 
public class CacheableDao<T extends Storable> extends AbstractDao<T> { 

một điều mà tôi không thích là tôi cần phải cung cấp một null CacheManager, ngay cả khi tôi không sử dụng nó, nếu không tôi nhận được lỗi sau:

Caused by: java.lang.IllegalStateException: No CacheResolver specified, and no bean of type CacheManager found. Register a CacheManager bean or remove the @EnableCaching annotation from your configuration. 

Vì vậy, tôi rời nó như thế này , một d hoạt động:

@Bean 
    public CacheManager cacheManager() { 
    return null; 
    } 

    @Bean(name = WGST_CACHE_RESOLVER) 
    public CacheResolver cacheResolver(){ 
    CacheResolver cacheResolver = new WgstCacheResolver(cacheableDocuments(),sizedCacheableDocuments(),getPermanentCache(), 
                 getSizedCache()); 
    return cacheResolver; 
    } 

reran thử nghiệm của tôi, bước qua tùy chỉnh của tôi CacheResolver và nó là hành xử như mong đợi giải quyết vào bộ nhớ cache chính xác (s)

lớp cấu hình của tôi không kéo dài CachingConfigurerSupport nữa.

+0

Làm thế nào bạn có thể nhận được bằng một null 'CacheManager' trong' WgstCacheResolver 'khi superclass' AbstractCacheResolver' có kiểm tra rõ ràng cho nó trong phương thức 'afterPropertiesSet'? 'public void afterPropertiesSet() {' 'Assert.notNull (this.cacheManager," CacheManager không được rỗng "); ' '} ' –

-1

Sau một chút trở lại và ra (Xin lỗi về điều đó!) Nó chỉ ra điều này thực sự là một lỗi trong Spring Framework.

Tôi đã tạo SPR-13081. Mong đợi một bản sửa lỗi cho bản phát hành bảo trì tiếp theo (4.1.7.RELEASE). Cảm ơn dự án mẫu!

+0

Không vấn đề :) cảm ơn rất nhiều vì đã xem xét nó – tommylii

+0

Xin chào, tôi' m cố gắng cấu hình bộ nhớ đệm toàn cầu mà không cần phải chỉ định tên trên mọi phương thức hoặc lớp. Tôi hiểu rằng một 'CacheResolver' tùy chỉnh có thể được cung cấp thay cho tên. Những gì không rõ ràng từ các tài liệu là nếu các phương pháp/lớp học vẫn phải tham khảo nó trong chú thích hoặc bạn tìm nó bằng cách gõ nếu không có quy định? –

+0

Nếu bạn chỉ định trình giải quyết bộ nhớ cache tùy chỉnh mà chúng tôi sẽ gọi khi chúng tôi cần giải quyết tên bộ nhớ cache. Làm thế nào bộ nhớ cache thích hợp (s) được giải quyết là hoàn toàn vào thực hiện của bạn. Có nói rằng, tôi không chắc chắn tôi hiểu câu hỏi của bạn hoặc sự nhầm lẫn bạn đang đề cập đến. Bạn vẫn phải chỉ định '@ Cacheable' tất nhiên nhưng bạn không cần phải cung cấp bất kỳ tên bộ nhớ cache nào. –

Các vấn đề liên quan