001 package org.springframework.cache.interceptor; 002 003 import org.aopalliance.aop.Advice; 004 import org.springframework.aop.Pointcut; 005 import org.springframework.aop.framework.ProxyFactory; 006 import org.springframework.aop.support.AbstractPointcutAdvisor; 007 import org.springframework.aop.support.AopUtils; 008 import org.springframework.cache.CacheManager; 009 import org.springframework.cache.annotation.AnnotationCacheOperationSource; 010 011 /** 012 * Methods for creating caching proxies. 013 */ 014 public final class CacheProxy { 015 /* 016 WARNING! This class uses internal spring code and could be subject to breaking 017 changes between Spring releases. 018 019 This class is needed because Spring does not yet have a way to apply caching advise to 020 existing objects which is required for our remote service proxies. 021 022 Hopefully, Spring will provide this capability in the future and we can remove this class. 023 */ 024 025 026 private CacheProxy() { 027 throw new IllegalArgumentException("do not call"); 028 } 029 030 /** 031 * This creates a caching proxy around a existing object if the proxy can be applied. 032 * 033 * @param o the object to proxy. cannot be null. 034 * @param cacheManager the cacheManager to handle the caching operations. cannot be null. 035 * @return a proxy. will not return null. 036 * @throws IllegalArgumentException if the o or cacheManager is null 037 */ 038 public static <T> T createCacheProxy(T o, CacheManager cacheManager) { 039 if (o == null) { 040 throw new IllegalArgumentException("o is null"); 041 } 042 043 if (cacheManager == null) { 044 throw new IllegalArgumentException("cacheManager is null"); 045 } 046 047 //this method is following the logic found in AnnotationDrivenCacheBeanDefinitionParser.AopAutoProxyConfigurer 048 049 final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource(); 050 051 final CacheInterceptor interceptor = new CacheInterceptor(); 052 interceptor.setCacheManager(cacheManager); 053 interceptor.setCacheDefinitionSources(source); 054 //important! must call afterPropertiesSet or does not execute caching logic 055 interceptor.afterPropertiesSet(); 056 057 final ProxyPointcut pointcut = new ProxyPointcut(source); 058 final ProxyPointCutAdvisor advisor = new ProxyPointCutAdvisor(pointcut, interceptor); 059 060 if (AopUtils.canApply(advisor, o.getClass())) { 061 final ProxyFactory proxyFactory = new ProxyFactory(o); 062 proxyFactory.addAdvisor(advisor); 063 return (T) proxyFactory.getProxy(); 064 } 065 return o; 066 } 067 068 private static class ProxyPointcut extends CacheOperationSourcePointcut { 069 private static final long serialVersionUID = 6050508570006106939L; 070 071 private final AnnotationCacheOperationSource source; 072 073 private ProxyPointcut(AnnotationCacheOperationSource source) { 074 this.source = source; 075 } 076 077 @Override 078 protected CacheOperationSource getCacheOperationSource() { 079 return source; 080 } 081 } 082 083 private static class ProxyPointCutAdvisor extends AbstractPointcutAdvisor { 084 085 private static final long serialVersionUID = 6050508570006106939L; 086 087 private final CacheOperationSourcePointcut pointcut; 088 private final CacheInterceptor interceptor; 089 090 private ProxyPointCutAdvisor(CacheOperationSourcePointcut pointcut, CacheInterceptor interceptor) { 091 this.pointcut = pointcut; 092 this.interceptor = interceptor; 093 } 094 095 @Override 096 public Pointcut getPointcut() { 097 return pointcut; 098 } 099 100 @Override 101 public Advice getAdvice() { 102 return interceptor; 103 } 104 } 105 }