Java基礎——代理(靜態代理、JDK動態代理、Cglib動態代理)

代理模式

  爲其他對象提供一個代理以控制對某個對象的訪問。代理類主要負責爲委託了(真實對象)預處理消息、過濾消息、傳遞消息給委託類,代理類不現實具體服務,而是利用委託類來完成服務,並將執行結果封裝處理。

   其實就是代理類爲被代理類預處理消息、過濾消息並在此之後將消息轉發給被代理類,之後還能進行消息的後置處理。代理類和被代理類通常會存在關聯關係(即上面提到的持有的被帶離對象的引用),代理類本身不實現服務,而是通過調用被代理類中的方法來提供服務。


靜態代理

  創建一個接口,然後創建被代理的類實現該接口並且實現該接口中的抽象方法。之後再創建一個代理類,同時使其也實現這個接口。在代理類中持有一個被代理對象的引用,而後在代理類方法中調用該對象的方法。
接口:

public interface Fangdong {
    /**
     * 出租
     */
    void rent(BigDecimal money);
}

被代理類:

public class ZhongJie implements Fangdong {
   @Override
   public void rent(BigDecimal money) {
    System.out.println("我在幫房東賣房,此房" + money +"萬元");
   }
}

代理類:

public class ZhongJieProxy implements Fangdong {
    private Fangdong fangdong = new ZhongJie();

    @Override
    public void rent(BigDecimal money) {
        System.out.println("賣房前");
        fangdong.rent(money);
        System.out.println("賣房後");
    }

    public static void main(String[] args) {
    	//代理類調用
        ZhongJieProxy proxy = new ZhongJieProxy();
        //被代理類ZhongJie被傳遞給了代理類ZhongJieProxy
        //代理類在執行具體方法時通過所持用的被代理類完成調用。
        proxy.rent(new BigDecimal(300));
		//賣房前
		//我在幫房東賣房,此房300萬元
		//賣房後
    }
}

  使用靜態代理很容易就完成了對一個類的代理操作。但是靜態代理的缺點也暴露了出來:由於代理只能爲一個類服務,如果需要代理的類很多,那麼就需要編寫大量的代理類,比較繁瑣。因此,我們需要採用動態代理,來避免這個繁瑣的問題。


動態代理

動態代理可以爲多個類服務,運行期動態創建被代理類的實例。
動態代理有2種方式:

  • JDK動態代理:代理類實現 InvocationHandler接口
  • Cglib動態代理: 必須導入 cglib jar包,代理類實現MethodInterceptor接口。

一. JDK動態代理

利用反射機制在運行時創建代理類。我們構建一個proxy類來實現InvocationHandler接口。

//代理類必須實現InvocationHandler接口
public class JdkProxy implements InvocationHandler {
	//被代理類(目標類)
    private Object target;

    JdkProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke method " + method.getName());
        //目標類 執行方法
        method.invoke(target, args);
        System.out.println("after invoke method " + method.getName());
        return null;
    }

    public static void main(String[] args) {
       //此處爲了保存動態代理生成Class文件
       System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
       Fangdong fangdong = new ZhongJie();
       Class<?>[] interfaces = fangdong.getClass().getInterfaces();
       ClassLoader classLoader = fangdong.getClass().getClassLoader();
       InvocationHandler invocationHandler = new JdkProxy(fangdong);
       CarFactory carFactory = new BenzFactory();
       JdkProxy carProxy = new JdkProxy(carFactory);
		//可以代理多個類
       CarFactory car = (CarFactory) Proxy.newProxyInstance(carFactory.getClass().getClassLoader(), carFactory.getClass().getInterfaces(), carProxy);
       Fangdong fangdong1 = (Fangdong) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

       fangdong1.rent(BigDecimal.valueOf(300));
       car.produce("Benz");
   }
}

打印輸出:

	before invoke method rent
	我在幫房東賣房,此房300萬元
	after invoke method rent
	before invoke method produce
	正在製造品牌車 Benz
	after invoke method produce


JDK動態代理底層實現

jdk動態代理具體步驟:

1. 通過實現 InvocationHandler 接口創建自己的調用處理器;
2. 通過爲 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
3. 通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;
4. 通過構造函數創建動態代理類實例,構造時調用處理器對象作爲參數被傳入。

既然生成代理對象是用的Proxy類的靜態方newProxyInstance,那麼我們就去它的源碼裏看一下它到底都做了些什麼?

	 /**
     * 代理類緩存
     * subKeyFactory -> new KeyFactory()
     * valueFactory -> new ProxyClassFactory() 
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
	/**
     * 返回指定接口的代理類實例,該接口將方法調用分派給指定的調用處理程序。
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * @param   loader 代理類的類加載器
     * @param   interfaces 要實現的代理類的接口列表
     * @param   h 將方法調用分派到的調用處理程序
     * @return 具有由指定的類加載器定義的代理類的指定調用處理程序並實現指定接口的代理實例。
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    	//InvocationHandler 不能爲空
        Objects.requireNonNull(h);
		//數組的clone(深拷貝)
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 查找或者生成指定的代理類
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * 調用構造器,構造器有目標類
         */
        try {
            if (sm != null) {
            		//檢查新的代理對戲那個的權限
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
						//獲取代理類的構造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            // //如果Class作用域爲私有,通過 setAccessible 支持訪問
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //獲取Proxy Class構造函數,創建Proxy代理實例。
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

Class<?> cl = getProxyClass0(loader, intfs);方法

  private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //接口個數不能超過2的32次方-1
       if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
	 //如果指定接口的代理類已經存在與緩存中,則不用新創建,直接從緩存中取即可;
     //如果緩存中沒有指定代理對象,則通過ProxyClassFactory來創建一個代理對象。
     //key 類加載器,parameter 是接口
        return proxyClassCache.get(loader, interfaces);
    }

WeakCache.java

	 
final class WeakCache<K, P, V> {
 
    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    //緩存的底層實現, key爲一級緩存, value爲二級緩存。 爲了支持null, map的key類型設置爲Object
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
    //reverseMap記錄了所有代理類生成器是否可用, 這是爲了實現緩存的過期機制
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    //生成二級緩存key的工廠, 這裏傳入的是KeyFactory
    private final BiFunction<K, P, ?> subKeyFactory;
    //生成二級緩存value的工廠, 這裏傳入的是ProxyClassFactory
    private final BiFunction<K, P, V> valueFactory;
 
    //初始化subKeyFactory 和 valueFactory
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }
 
 
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
        //清除過期緩存
        expungeStaleEntries();
 
        //將key包裝成CacheKey,並關聯個應用隊列
        Object cacheKey = CacheKey.valueOf(key, refQueue);
 
        // lazily install the 2nd level valuesMap for the particular cacheKey
        //獲取二級緩存
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            //以CAS方式放入, 如果不存在則放入,否則返回原先的值
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            //如果oldValuesMap有值, 說明放入失敗
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }
 
        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        //使用subKeyFactory生成二級緩存key
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //獲取二級緩存value
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
 
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                // supplier有可能是一個後面代碼生成的一個Factory,也肯是一個CacheValue(就是生成的代理類),
                //因爲他們都實現Supplier,所以都可以用get獲取。
                //判斷是Factory 還是 CacheValue在get裏面判斷
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)
 
            // lazily construct a Factory
            if (factory == null) {
                //新建一個Factory後面將會放入二級緩存的value裏面
                factory = new Factory(key, parameter, subKey, valuesMap);
            }
 
            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    //說明已經成功放入
                    supplier = factory;
                }
                // else retry with winning supplier
                //否則, 期間可能有其他線程修改了值, 那麼需再次循環(此時可直接取出使用)
            } else {
                //期間有可能其他線程修改了supplier的值,這是需要替換
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    } 
}

ProxyClassFactory.java
利用ProxyClassFactory對象的apply方法,生成代理類。

  @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 生成代理對象字節碼
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
            	//native方法生成代理對象 將字節碼轉換成Class文件
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); 生成代理類的class字節文件。

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }
						//寫入字節碼文件
                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }

Proxy.generateClassFile();方法的具體實現,生成class字節碼

private byte[] generateClassFile() {
    //第一步, 將所有的方法組裝成ProxyMethod對象
    //首先爲代理類生成toString, hashCode, equals等代理方法
    addProxyMethod(hashCodeMethod, Object.class);
    addProxyMethod(equalsMethod, Object.class);
    addProxyMethod(toStringMethod, Object.class);
    //遍歷每一個接口的每一個方法, 並且爲其生成ProxyMethod對象
    for (int i = 0; i < interfaces.length; i++) {
        Method[] methods = interfaces[i].getMethods();
        for (int j = 0; j < methods.length; j++) {
            addProxyMethod(methods[j], interfaces[i]);
        }
    }
    //對於具有相同簽名的代理方法, 檢驗方法的返回值是否兼容
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
        checkReturnTypes(sigmethods);
    }

    //第二步, 組裝要生成的class文件的所有的字段信息和方法信息
    try {
        //添加構造器方法
        methods.add(generateConstructor());
        //遍歷緩存中的代理方法
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
            for (ProxyMethod pm : sigmethods) {
                //添加代理類的靜態字段, 例如:private static Method m1;
                fields.add(new FieldInfo(pm.methodFieldName,
                        "Ljava/lang/reflect/Method;", ACC_PRIVATE | ACC_STATIC));
                //添加代理類的代理方法
                methods.add(pm.generateMethod());
            }
        }
        //添加代理類的靜態字段初始化方法
        methods.add(generateStaticInitializer());
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception");
    }

    //驗證方法和字段集合不能大於65535
    if (methods.size() > 65535) {
        throw new IllegalArgumentException("method limit exceeded");
    }
    if (fields.size() > 65535) {
        throw new IllegalArgumentException("field limit exceeded");
    }

    //第三步, 寫入最終的class文件
    //驗證常量池中存在代理類的全限定名
    cp.getClass(dotToSlash(className));
    //驗證常量池中存在代理類父類的全限定名, 父類名爲:"java/lang/reflect/Proxy"
    cp.getClass(superclassName);
    //驗證常量池存在代理類接口的全限定名
    for (int i = 0; i < interfaces.length; i++) {
        cp.getClass(dotToSlash(interfaces[i].getName()));
    }
    //接下來要開始寫入文件了,設置常量池只讀
    cp.setReadOnly();

    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(bout);
    try {
        //1.寫入魔數
        dout.writeInt(0xCAFEBABE);
        //2.寫入次版本號
        dout.writeShort(CLASSFILE_MINOR_VERSION);
        //3.寫入主版本號
        dout.writeShort(CLASSFILE_MAJOR_VERSION);
        //4.寫入常量池
        cp.write(dout);
        //5.寫入訪問修飾符
        dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
        //6.寫入類索引
        dout.writeShort(cp.getClass(dotToSlash(className)));
        //7.寫入父類索引, 生成的代理類都繼承自Proxy
        dout.writeShort(cp.getClass(superclassName));
        //8.寫入接口計數值
        dout.writeShort(interfaces.length);
        //9.寫入接口集合
        for (int i = 0; i < interfaces.length; i++) {
            dout.writeShort(cp.getClass(dotToSlash(interfaces[i].getName())));
        }
        //10.寫入字段計數值
        dout.writeShort(fields.size());
        //11.寫入字段集合
        for (FieldInfo f : fields) {
            f.write(dout);
        }
        //12.寫入方法計數值
        dout.writeShort(methods.size());
        //13.寫入方法集合
        for (MethodInfo m : methods) {
            m.write(dout);
        }
        //14.寫入屬性計數值, 代理類class文件沒有屬性所以爲0
        dout.writeShort(0);
    } catch (IOException e) {
        throw new InternalError("unexpected I/O Exception");
    }
    //轉換成二進制數組輸出
    return bout.toByteArray();
}

這時可以有個疑問,即使生成了代理類,但 目標方法執行的時候,前後的打印語句是在什麼時候打印出來的? 這個時候,我們需要去生成的class文件中查看。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.mk.coffee.test.jdk.reflect.Car;
import com.mk.coffee.test.jdk.reflect.CarFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements CarFactory {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final Car produce(String var1) throws  {
        try {
            return (Car)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.mk.coffee.test.jdk.reflect.CarFactory").getMethod("produce", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

這個生成的Class文件,我們重點關注 produce方法

 public final Car produce(String var1) throws  {
        try {
        	//此處的h,父類Proxy中的InvocationHandler
   			//this 爲 代理類對象
   			//m3 表示 m3 = Class.forName("com.mk.coffee.test.jdk.reflect.CarFactory").getMethod("produce", Class.forName("java.lang.String"));
   			//參數是new Object[]{var1}
            return (Car)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

以上就是JDK動態代理的具體流程。你確定都知道了嗎?

JDK動態代理流程圖

在這裏插入圖片描述




二. Cglib動態代理

要實現CGLIG動態代理,必須引入cglib包,實現MethodIntercepter接口。

import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Auther: makui
 * @Date: 2018/12/13
 * @Description: cglib 動態代理
 */
public class CgbliProxy implements MethodInterceptor {
    //通過Enhancer 創建代理對象
    private Enhancer enhancer = new Enhancer();

    //通過Class對象獲取代理對象
    public Object getProxy(Class c) {
        //設置創建子類的類
        enhancer.setSuperclass(c);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理類調用父類的方法之前...");
        //代理類調用父類的方法
        methodProxy.invokeSuper(obj, args);
        System.out.println("代理類調用父類的方法之後...");
        return null;
    }

    public static void main(String[] args) {
        //代理類class文件存入本地磁盤可以查看
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/makui/Desktop/");
        CgbliProxy cglibProxy = new CgbliProxy();
        Car car = (Car) cglibProxy.getProxy(Car.class);
        CarFactory carFactory = (CarFactory) cglibProxy.getProxy(BenzFactory.class);
        carFactory.produce("aodi");
        car.run(500);
    }
}  

打印輸出:

	代理類調用父類的方法之前...
	正在製造品牌車 aodi
	代理類調用父類的方法之後...
	代理類調用父類的方法之前...
	正在以時速500行駛
	代理類調用父類的方法之後...



Cglib動態代理的實現步驟

a. 創建一個代理類,實現了MethodIntercepter接口。實現了intercept方法。
b. 通過Enhancer 創建代理類。

MethodIntercepter接口

//MethodIntercepter 接口就一個攔截方法
public interface MethodInterceptor extends Callback
{
    /**
     * @param obj "this",  obj表示增強的對象,即實現這個接口類的一個對象;
     * @param method method表示要被攔截的方法;
     * @param args 要被攔截方法的參數;
     * @param proxy 要觸發父類的方法對象;
     */    
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

重點在於Enhancer 創建代理類.

	//設置父類
   public void setSuperclass(Class superclass) {
        if (superclass != null && superclass.isInterface()) {
            this.setInterfaces(new Class[]{superclass});
        } else if (superclass != null && superclass.equals(Object.class)) {
            this.superclass = null;
        } else {
            this.superclass = superclass;
        }

    }
	//設置接口
    public void setInterfaces(Class[] interfaces) {
        this.interfaces = interfaces;
    }
    //創建代理對象
    public Object create() {
        this.classOnly = false;
        this.argumentTypes = null;
        //創建代理對象實際調用的方法
        return this.createHelper();
    }
    
    //通過newInstance()方法創建EnhancerKey對象,作爲Enhancer父類AbstractClassGenerator.create()方法
    private Object createHelper() {
        preValidate();
        Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                ReflectUtils.getNames(interfaces),
                filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                callbackTypes,
                useFactory,
                interceptDuringConstruction,
                serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }

創建代理對象

protected Object create(Object key) {
        try {
            ClassLoader loader = getClassLoader();
            Map<ClassLoader, ClassLoaderData> cache = CACHE;
            ClassLoaderData data = cache.get(loader);
            if (data == null) {
                synchronized (AbstractClassGenerator.class) {
                    cache = CACHE;
                    data = cache.get(loader);
                    if (data == null) {
                        Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                        data = new ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            this.key = key;
            Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
            	//生成對象實例
                return firstInstance((Class) obj);
            }
            //生成對象實例
            return nextInstance(obj);
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }

nextInstance(obj) 生成對象

protected Object nextInstance(Object instance) {
        EnhancerFactoryData data = (EnhancerFactoryData) instance;
 
        if (classOnly) {
            return data.generatedClass;
        }
 
        Class[] argumentTypes = this.argumentTypes;
        Object[] arguments = this.arguments;
        if (argumentTypes == null) {
            argumentTypes = Constants.EMPTY_CLASS_ARRAY;
            arguments = null;
        }
        return data.newInstance(argumentTypes, arguments, callbacks);
    }

EnhancerFactoryData的newInstance方法,通過發射生成代理對象。

        /**
         * 第一個參數爲代理對象的構成器類型,
         * 第二個爲代理對象構造方法參數,
         * 第三個爲對應回調對象。
         * 最後根據這些參數,通過反射生成代理對象
         */
        public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
            setThreadCallbacks(callbacks);
            try {
                // Explicit reference equality is added here just in case Arrays.equals does not have one
                if (primaryConstructorArgTypes == argumentTypes ||
                        Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
                    // If we have relevant Constructor instance at hand, just call it
                    // This skips "get constructors" machinery
                    return ReflectUtils.newInstance(primaryConstructor, arguments);
                }
                // Take a slow path if observing unexpected argument types
                return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
            } finally {
                // clear thread callbacks to allow them to be gc'd
                setThreadCallbacks(null);
            }
        }



Cglib爲每個代理類生成3個Class文件

在這裏插入圖片描述

FastClass機制

  Jdk動態代理的攔截對象是通過反射的機制來調用被攔截實例方法的,反射的效率比較低,所以cglib採用了FastClass的機制來實現對被攔截方法的調用。FastClass機制就是對一個類的方法建立索引,調用方法時根據方法的簽名來計算索引,通過索引來直接調用相應的方法。
這也就是爲什麼CGLIB生成的動態代理會包含3個class文件的原因,其中一個是生成的代理類,另外兩個類都是FastClass機制需要的。另外兩個類都繼承了FastClass這個類。其中一個class爲生成的代理類中的每個方法建立了索引,另外一個則爲我們被代理類的所有方法包含其父類的方法建立了索引。

//根據方法簽名獲取index

 	public int getIndex(Signature var1) {
      String var10000 = var1.toString();
      switch(var10000.hashCode()) {
      case -2077043409:
         if(var10000.equals("getPerson(Ljava/lang/String;)Lcom/demo/pojo/Person;")) {
            return 21;
         }
         break;
      case -2055565910:
         if(var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
            return 12;
         }
         break;
      case -1902447170:
         if(var10000.equals("setPerson()V")) {
            return 7;
         }
	         break;
	   //省略部分代碼.....
	 
 //根據index直接定位執行方法
	 public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
	  eaaaed75 var10000 = (eaaaed75)var2;
	  int var10001 = var1;
	
	  try {
	     switch(var10001) {
	     case 0:
	        return new Boolean(var10000.equals(var3[0]));
	     case 1:
	        return var10000.toString();
	     case 2:
	        return new Integer(var10000.hashCode());
	     case 3:
	        return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
	     case 4:
	        return var10000.newInstance((Callback)var3[0]);
	     case 5:
	        return var10000.newInstance((Callback[])var3[0]);
	     case 6:
	        var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
	        return null;
	     case 7:
	        var10000.setPerson();
	        return null;
	     case 8:
	        var10000.setCallbacks((Callback[])var3[0]);
	        return null;
	     case 9:
	        return var10000.getCallback(((Number)var3[0]).intValue());
	     case 10:
	        return var10000.getCallbacks();
	     case 11:
	        eaaaed75.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
	        return null;
	     case 12:
	        eaaaed75.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
	        return null;
	     case 13:
	        return eaaaed75.CGLIB$findMethodProxy((Signature)var3[0]);
	     case 14:
	        return var10000.CGLIB$toString$3();
	     case 15:
	        return new Boolean(var10000.CGLIB$equals$2(var3[0]));
	     case 16:
	        return var10000.CGLIB$clone$5();
	     case 17:
	        return new Integer(var10000.CGLIB$hashCode$4());
	     case 18:
	        var10000.CGLIB$finalize$1();
	        return null;
	     case 19:
	        var10000.CGLIB$setPerson$0();
	        return null;
	    //省略部分代碼....
	  } catch (Throwable var4) {
	     throw new InvocationTargetException(var4);
	  }
	
	  throw new IllegalArgumentException("Cannot find matching method/constructor");

   }

FastClass並不是跟代理類一塊生成的,而是在第一次執行MethodProxy invoke/invokeSuper時生成的並放在了緩存中。

//MethodProxy invoke/invokeSuper都調用了init()
private void init() {
    if(this.fastClassInfo == null) {
        Object var1 = this.initLock;
        synchronized(this.initLock) {
            if(this.fastClassInfo == null) {
                MethodProxy.CreateInfo ci = this.createInfo;
                MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                fci.f1 = helper(ci, ci.c1);//如果緩存中就取出,沒有就生成新的FastClass
                fci.f2 = helper(ci, ci.c2);
                fci.i1 = fci.f1.getIndex(this.sig1);//獲取方法的index
                fci.i2 = fci.f2.getIndex(this.sig2);
                this.fastClassInfo = fci;
                this.createInfo = null;
            }
        }
    }

}**



總結 (JDK動態代理和Gglib動態代理的區別)

  至此,動態代理的原理我們就基本搞清楚了,代碼細節有興趣可以再研究下。

最後我們總結一下JDK動態代理和Gglib動態代理的區別:

  • JDK動態代理是實現了被代理對象的接口,Cglib是繼承了被代理對象。

  • JDK和Cglib都是在運行期生成字節碼,JDK是直接寫Class字節碼,Cglib使用ASM框架寫Class字節碼,Cglib代理實現更復雜,生成代理類比JDK效率低。

  • JDK調用代理方法,是通過反射機制調用,Cglib是通過FastClass機制直接調用方法,Cglib執行效率更高。

  • Cglib通過繼承,不能代理final, private 方法。

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