【原】通過Spring結合Cglib處理非接口代理

前言:

  之前做的一個項目,雖然是查詢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);
    }

  
}

  

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章