天天看點

動态代理之JDK動态代理&CGLib動态代理

JDK動态代理

核心思想:通過實作被代理類的所有接口,生成一個位元組碼檔案後構造一個代理對象,通過持有反射構造被代理類的一個執行個體,再通過invoke反射調用被代理類執行個體的方法,來實作代理。

缺點:JDK動态代理的對象必須實作一個或多個接口

動态代理之JDK動态代理&CGLib動态代理

流程圖

動态代理之JDK動态代理&CGLib動态代理

知識點

  • JDK實作動态代理需要實作類通過接口定義業務方法
  • JDK生成的代理類以”$Proxy”為開頭進行命名
  • JDK代理生成的代理類的Method在static靜态代碼塊中進行初始化;
  • public接口生成的代理類package為”com.sun.proxy”;
  • JDK動态代理需要實作InvocationHandler接口;

代碼:

package com.quancheng;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy {
    public static void main(String[] args) {
        Student stu = new Student();
        CusInvocationHandler handler = new CusInvocationHandler(stu);
        Play instance = (Play) Proxy.newProxyInstance(stu.getClass().getClassLoader(), stu.getClass().getInterfaces(), handler);
        instance.play();
    }
}

class CusInvocationHandler implements InvocationHandler {
    private Object target;

    public CusInvocationHandler(Object object) {
        this.target = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.err.println("代理方法處理");
        return method.invoke(target, args);
    }
}

interface Play {
    void play();
}

class Student implements Play {

    @Override
    public void play() {
        System.err.println("student ====>");
    }
}
           

生成的代理類示例:

import dynamic.proxy.UserService;  
import java.lang.reflect.*;  

public final class $Proxy11 extends Proxy  
    implements UserService  
{  

    // 構造方法,參數就是剛才傳過來的MyInvocationHandler類的執行個體  
    public $Proxy11(InvocationHandler invocationhandler)  
    {  
        super(invocationhandler);  
    }  

    public final boolean equals(Object obj)  
    {  
        // 省略
    }  

    /** 
     * 被代理的方法 
     */  
    public final void add()  
    {  
        try  
        {  
            // 實際上就是調用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二個問題就解決了  
            super.h.invoke(this, m3, null);  
            return;  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

    public final int hashCode()  
    {  
        // 省略
    }  

    public final String toString()  
    {  
        // 省略
    }  

    private static Method m1;  
    private static Method m3;  
    private static Method m0;  
    private static Method m2;  

    // 在靜态代碼塊中擷取了4個方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法  
    static   
    {  
        try  
        {  
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
                Class.forName("java.lang.Object")  
            });  
            m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[]);  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[]);  
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[]);  
        }  
        catch(NoSuchMethodException nosuchmethodexception)  
        {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        }  
        catch(ClassNotFoundException classnotfoundexception)  
        {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }  
}
           

cglib動态代理

核心思想:CGLib采用了非常底層的位元組碼技術,其原理是通過位元組碼技術為一個類建立子類(CGLib底層是通過繼承實作的動态代理),并在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。JDK動态代理與CGLib動态代理均是實作Spring AOP的基礎;底層:使用一個小而快的位元組碼處理架構ASM(Java位元組碼操控架構),來轉換位元組碼并生成新的類

缺點:不能代理final修飾的類

示例代碼:

//被代理的類即目标對象
public class A {
    public void execute(){
        System.out.println("執行A的execute方法...");
    }
}

//代理類
public class CGLibProxy implements MethodInterceptor {

    /**
     * 被代理的目标類
     */
    private A target;

    public CGLibProxy(A target) {
        super();
        this.target = target;
    }

    /**
     * 建立代理對象
     * @return
     */
    public A createProxy(){
        // 使用CGLIB生成代理:
        // 1.聲明增強類執行個體,用于生産代理類
        Enhancer enhancer = new Enhancer();
        // 2.設定被代理類位元組碼,CGLIB根據位元組碼生成被代理類的子類
        enhancer.setSuperclass(target.getClass());
        // 3.//設定回調函數,即一個方法攔截
        enhancer.setCallback(this);
        // 4.建立代理:
        return (A) enhancer.create();
    }

    /**
     * 回調函數
     * @param proxy 代理對象
     * @param method 委托類方法
     * @param args 方法參數
     * @param methodProxy 每個被代理的方法都對應一個MethodProxy對象,
     *                    methodProxy.invokeSuper方法最終調用委托類(目标類)的原始方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   //過濾不需要該業務的方法
      if("execute".equals(method.getName())) {
          //調用前驗證權限(動态添加其他要執行業務)
          AuthCheck.authCheck();

          //調用目标對象的方法(執行A對象即被代理對象的execute方法)
          Object result = methodProxy.invokeSuper(proxy, args);

          //記錄日志資料(動态添加其他要執行業務)
          Report.recordLog();

          return result;
      }else if("delete".equals(method.getName())){
          //.....
          return methodProxy.invokeSuper(proxy, args);
      }
      //如果不需要增強直接執行原方法
      return methodProxy.invokeSuper(proxy, args);

    }
}