前言:
之前做的一個項目,雖然是查詢ES,但內部有大量的邏輯計算,非常耗時,每天凌晨更新一次,於是想着用緩存緩存起來,最後採用Spring+Cglib進行處理。
問題:
Jdk動態代理是基於接口層的代理,但基於的類的代理只能通過字節碼層面代理,在一個項目中,很多方法調用是基於類方法的調用,如果要加入代理,是很麻煩的事情,最簡單的無非如下:
CglibCacheProxy cacheMethodInterceptor = new CglibCacheProxy(); AgreementHotelPercentService proxyAgreementHotelPercentService = (AgreementHotelPercentService)cacheMethodInterceptor.createProxyObject(agreementHotelPercentService); AgreementAndMemberHotelPercent agreementAndMemberHotelPercent = proxyAgreementHotelPercentService.getHotelPercent(filterList);
上面的代碼就是通過new一個Cglib工具類,然後需要代理的類丟進去,這麼看起來是沒什麼問題,如果一個項目裏有幾十個這樣的代碼需要改造,出現問題以及效率低下可以想象,於是想到代理模式,把公共的代理方法抽取出來,問題是如何才能知道哪個類哪個方法要代理?如何代理?
基於Spring實現後置處理
大致思路就是在Spring加載完後, 再通過某個方式拿出需要代理的Bean,可以通過註解方式,判斷是否包含這個註解,如果是就創建代理類。
1. BeanPostProcessor簡介
該接口我們也叫後置處理器,作用是在Bean對象在實例化和依賴注入完畢後,在顯示調用初始化方法的前後添加我們自己的邏輯。注意是Bean實例化完畢後及依賴注入完成後觸發的。接口的源碼如下
public interface BeanPostProcessor { //bean初始化方法調用前被調用 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; //bean初始化方法調用後被調用 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
方法 | 說明 |
---|---|
postProcessBeforeInitialization | 實例化、依賴注入完畢, 在調用顯示的初始化之前完成一些定製的初始化任務 |
postProcessAfterInitialization | 實例化、依賴注入、初始化完畢時執行 |
2.自定義 CglibCachePostBeanProcessor
public class CglibCachePostBeanProcessor implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException{ if(bean.getClass().isAnnotationPresent(CglibCache.class)){ //判斷是代理的類 CglibCache cglibCache = bean.getClass().getAnnotation(CglibCache.class); if(cglibCache.isScan()){ return CglibCacheProxy.CglibCacheProxy(bean); } }else{ return bean; } return bean; } @Override public Object postProcessBeforeInitialization(Object bean, String beanNames) throws BeansException{ return bean; } }
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface CglibCache { //是否啓用掃描 boolean isScan() default true; }
public static Object CglibCacheProxy(Object bean){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(bean.getClass());//被代理的類 enhancer.setCallback(new CacheMethodInterceptor(bean)); return enhancer.create(); }
2.Cglib代理類處理
public class CacheMethodInterceptor implements MethodInterceptor{ CacheStorageService cacheStorageService; //代理對象 private Object target; public CacheMethodInterceptor (Object target){ this.target = target; } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable{ Object result = null; Cache cacheable = method.getAnnotation(Cache.class); if(cacheable!=null){ //自定義業務邏輯 } return method.invoke(target,args); } }