動態代理的實現方式,及JDKPorxy 和CGLib的區別

動態代理常用的實現方式是發射. 但動態代理不止有反射這一種實現方式.

eg: 動態代理也可以是通過CGLib來實現,而CGLib是基於ASM(一個java字節碼操作框架),而實現的.

簡單說: 動態代理是一種行爲方式,而反射或ASM只是它的一種實現手段而已

 

JDKPorxy 和CGLib區別:

  1. JDK Proxy 是java語言自帶的功能,無需加載三方 jar來實現.
  2. java對 JDK Proxy 提供了穩定的支持,並且會持續提升和更新JDK Proxy,   eg: java 8 中JDK Proxy 性能相比於之前版本提升了很多
  3.  JDK Proxy 是通過攔截器加 反射的方式實現的
  4.  JDK Proxy只能代理集成接口的類
  5.  JDK Proxy 實現和調用起來比較簡單
  6.  CGLib 是第三方提供的工具,基於ASM實現的,性能比較高
  7.  CGLib 無需通過接口來實現,它是通過實現子類的方式來完成調用的
public class JDKProxyExample {

    static interface  Car {
        void run();
    }

    static  class  Bus implements Car{

        @Override
        public void run() {
            System.out.println("Bus running");
        }
    }

    static  class  Taxi implements Car{

        @Override
        public void run() {
            System.out.println("Taxi running");
        }
    }
    // 實現 InvocationHandler  接口
    static  class  JDKProxy implements InvocationHandler {
        // 代理對象
        private Object target;
        // 獲取代理對象實例
        public Object getInstance(Object target) {
            this.target = target;
           // 獲得代理的對象
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),JDKProxy.this);
        }
        /**
         * 執行代理方法
         * @param proxy  代理對象
         * @param method 代理方法 
         * @param args   方法參數  
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("動態代理之前的業務處理");
            Object invoke = method.invoke(target, args);
            return invoke;
        }
    }

    public static void main(String[] args) {
          JDKProxy jdkProxy = new JDKProxy();
          Car instance = (Car) jdkProxy.getInstance(new Taxi());
          instance.run();
          Car instance2 = (Car)jdkProxy.getInstance(new Bus());
          instance2.run();
    }
}

 依賴:

           <!-- https://mvnrepository.com/artifact/cglib/cglib -->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.3.0</version>
            </dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author xulihui
 * @date 2020/4/7 13:10
 */
public class CGLibExample {

    static class Car {

        public void run() {
            System.out.println("Car running");
        }
    }

    static  class  CGLibProxy implements MethodInterceptor {
        // 接收代理對象
        private  Object target;

        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            // 設置父類爲示例
            enhancer.setSuperclass(this.target.getClass());
            // 回調方法
            enhancer.setCallback(this);
            // 創建並返回代理對象
            return  enhancer.create();
        }


        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("方法調用前業務處理");
            // 執行調用方法
            Object invoke = methodProxy.invoke(o, objects);
            return invoke;
        }
    }

    public static void main(String[] args) {
        // 創建CGLib代理類
        CGLibProxy cgLibProxy = new CGLibProxy();
        // 初始化代理對象
        Car instance = (Car)cgLibProxy.getInstance(new Car());
        // 執行方法
        instance.run();
    }
}

spring框架中同時使用了兩種動態代理 JDK Proxy 和CGLib,

當bean實現了接口時,Spring 就會使用CGLib

沒有實現接口的時候,就會使用CGLib, 也可以在配置中強制使用CGLib, 只需要在Spring 配置中添加  <aop:aspectj-autoproxy proxy-target-class="true"/> 即可。

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