動態(tài)代理

靜態(tài)代理:

就是一種組合方式的,A類組合目標類,A類A方法中引用目標類的a方法;對其進行輔助實現(xiàn);
若想調(diào)用目標類的a方法,直接可以用A類A方法代理執(zhí)行;

1.動態(tài)代理:

JDK動態(tài)代理:就是字節(jié)碼重組過程,主要是生成新的代理類并實現(xiàn)目標類全部方法;

<font color=Red> 因為是通過實現(xiàn),被代理類都實現(xiàn)接口 </font>

JDK動態(tài)代理過程
1.首先通過getInstance獲取目標類,然后通過反射獲取其全部方法;
2.Proxy.newProxyInstance通過入?yún)ⅲ侯惖腸lassLoader, 類的接口方法,該JDKDemoPorxy;
來創(chuàng)建新的代理對象;并且實現(xiàn)全部接口方法;

Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
  1. 最終通過invoke 來調(diào)用方法;入?yún)ⅲ盒律傻拇眍悾{(diào)用的目標方法,方法入?yún)?;
    作用對原有類的接口方法做業(yè)務增強,比如before(),after()等方法;
public Object invoke(Object proxy, Method method, Object[] args)

4.根據(jù)上述動態(tài)生成java代碼,編譯新生產(chǎn)的.class文件,重新加載到JVM運行

//具體使用例子

//jdk代理類
public class JDKMeipo implements InvocationHandler {
    private Object target;
    public Object getInstance(Object target) throws Exception {
        this.target = target;
        Class<?> clazz = target.getClass();
        //反射獲取目標類方法,并新生成一個代理類,并實現(xiàn)全部方法,其中invoke可以做邏輯切入
        //入?yún)㈩惖腸lassLoader,類的接口,該JDKDemoPorxy
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }
    //入?yún)ⅲ盒律傻拇眍?,調(diào)用的目標方法,方法入?yún)?    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target, args);
        after();
        return obj;
    }
    private void before() throws Exception {
        System.out.println("before+++");
    }
    private void after() {
        System.out.println("after+++");
    }
}
public interface Person {
    void getName();
    Long getCreateTime(String param);
}

//目標類
public class Customer implements Person {
    @Override
    public void getName() {
        System.out.println("sally");
    }
    @Override
    public Long getCreateTime(String param) {
        System.out.println(param);
        return System.currentTimeMillis();
    }
}
//測試使用
public class JDKProxyTest {
public static void main(String[] args) throws Exception {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        Person student = (Person) new JDKMeipo().getInstance(new Customer());
        student.getCreateTime();

//        Person customer = (Person) new CglibProxyDemo().getInstance(Customer.class);
//        customer.getName();
    }
}

代理重組字節(jié)碼反編譯后生成的文件:

通過反編譯新的代理類文件$Porxy;可以看到 他實現(xiàn)了所有方法,并在static靜態(tài)塊中用反射找到所有方法以m0,m1,m2....來命名方法

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m0;
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    public final boolean equals(Object var1) throws  {省略}
    public final void getName() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final Long getCreateTime() throws  {
        try {
            return (Long)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final String toString() throws  {省略}
    public final int hashCode() throws  { 省略}
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.example.springbootdemo.model.Person").getMethod("getName");
            m4 = Class.forName("com.example.springbootdemo.model.Person").getMethod("getCreateTime");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

2.CGlib動態(tài)代理

CGlib動態(tài)代理原理:是通過生成子類繼承目標類,并覆蓋;

CGlib動態(tài)代理過程
1.首先通過Enhancer,設置目標類,并設置代理為回調(diào),生成代理類繼承目標類;

public Object getInstance(Class<?> clazz) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //生成代理類繼承目標類
        return enhancer.create();
    }

2.當調(diào)用代理類中方法時,通過MethodInterceptor攔截或說回調(diào)到intercept,來觸發(fā)MethodProxy.invokeSuper;

@Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        before();
        //methodProxy invokeSuper觸發(fā)并生FastClass類,通過FastClass機制
        Object obj = methodProxy.invokeSuper(o,args);
        after();
        return obj;
    }
若緩存中沒有,其中為目標類和代理類各生成一個FastClass類,這類會為每個方法分配一個index;
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);

獲取當前代理類的FastClass類和index,當作入?yún)⒕涂梢灾苯诱{(diào)用方法,省去反射調(diào)用;所以比JDK執(zhí)行效率高;
FastClass不是和代理一起生成的,而是在第一次執(zhí)行MethodProxy.invokeSuper生成的,并放在緩存中;

使用例子

public class CglibProxyDemo implements MethodInterceptor {

    public Object getInstance(Class<?> clazz) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //生成代理類繼承目標類
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        before();
        //methodProxy invokeSuper觸發(fā)并生FastClass類,通過FastClass機制
        Object obj = methodProxy.invokeSuper(o,args);
        after();
        return obj;
    }


    private void before() throws Exception {
        System.out.println("before+++");
    }

    private void after() {
        System.out.println("after+++");
    }
}
public class  CglibProxyTest {
    public static void main(String[] args) throws Exception {
        Person customer = (Person) new CglibProxyDemo().getInstance(Customer.class);
        customer.getName();
    }
}

代理類調(diào)用方法時,會MethodInterceptor攔截進入intercept,觸發(fā)methodProxy.invokeSuper(o,args);
MethodProxy是很關(guān)鍵的,調(diào)用invokeSuper時,為目標類和代理類各生成一個FastClass類,這類會為每個方法分配一個index;
獲取代理類的FastClass根據(jù)index,調(diào)用方法;

public class MethodProxy {

    private Signature sig1;
    private Signature sig2;
    private CreateInfo createInfo;
    private final Object initLock = new Object();
    private volatile FastClassInfo fastClassInfo;
···
  private void init() {
        if (fastClassInfo == null) {
            synchronized (initLock) {
                if (fastClassInfo == null) {
                    CreateInfo ci = createInfo;

                    FastClassInfo fci = new FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(sig1);
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }
。。。
  private static class FastClassInfo {
        FastClass f1;
        FastClass f2;
        int i1;
        int i2;
    }
。。。。
  public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
                        //生成FastClass類 ,若有就從緩存中獲取
            init();
            FastClassInfo fci = fastClassInfo;
                        //根據(jù)fci.i2的index,去調(diào)用方法
            return fci.f2.invoke(fci.i2, obj, args);
        }
        catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
」
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容