動態代理

原文連接http://zhhll.icu/2020/11/12/java%E5%9F%BA%E7%A1%80/%E5%8F%8D%E5%B0%84/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/java

動態代理

動態代理有不少種方式,如jdk代理,cglib,ASM等框架

在說動態代理以前先說一下靜態代理ide

靜態代理

靜態代理在使用時,須要定義接口或者父類,被代理對象和代理對象一塊兒實現相同的接口或者繼承相同的父類this

靜態代理使用的是組合模式,在代理類中包含有被代理類的對象代理

public class TestStaticProxy {
    public static void main(String[] args) {
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ProxyFactory proxyFactory = new ProxyFactory(nikeClothFactory);
        proxyFactory.productCloth();
    }
}

// 接口
interface ClothFactory{
    void productCloth();
}

// 被代理類
class NikeClothFactory implements ClothFactory{

    @Override
    public void productCloth() {
        System.out.println("Nike工廠生產了一件Nike");
    }
}

// 代理類
class ProxyFactory implements ClothFactory{

    private ClothFactory clothFactory;

    public ProxyFactory(ClothFactory clothFactory){
        this.clothFactory = clothFactory;
    }
    @Override
    public void productCloth() {
        System.out.println("代理類開始執行,準備調用被代理類");
        clothFactory.productCloth();
    }
}

靜態代理雖然能夠在不修改目標對象功能的前提下對目標功能進行擴展,可是一旦接口增長方法,目標對象和代理類都要同時修改,並且代理對象和被代理對象要實現同樣的接口,致使有不少的代理類,不便於維護code

jdk動態代理

jdk動態代理的底層是用的是java的反射,可是jdk代理的前提是目標類必須實現接口xml

使用步驟對象

  • 首先實現一個InvocationHandler,方法調用會被轉發到該類的invoke()方法
  • 調用時經過動態代理獲取代理對象

核心方法爲Proxy.newProxyInstance(ClassLoader,Class[],InvocationHandler)繼承

三個參數分別表示接口

  • ClassLoader 當前目標對象使用的類加載器
  • Class[] 目標對象實現的接口類型
  • InvocationHandler 事件處理,執行目標對象的方法時,會觸發事件處理器的方法,會把當前執行目標對象的方法做爲參數傳入
public class TestDynamicProxy {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        MyInvationHandler myInvationHandler = new MyInvationHandler();
        Object obj = myInvationHandler.blind(realSubject);
        Subject sub = (Subject) obj;
        sub.action();
    }
}

// 接口
interface Subject{
    void action();
}

// 真正執行的方法,被代理類
class RealSubject implements Subject{

    @Override
    public void action() {
        System.out.println("被代理類開始執行");
    }
}

class MyInvationHandler implements InvocationHandler{

    // 實現了接口的被代理類的對象的聲明
    Object obj;
    // 被代理類的實例
    // 返回一個代理類的對象
    public Object blind(Object obj){
        this.obj = obj;
        // ①使用被代理類的類加載器②被代理類的接口③代理類的實例
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }

    /**
     * 當經過代理類的對象被重寫的方法調用時,都會轉換爲對invoke方法的調用
     * @param proxy 正在返回的代理對象,通常狀況下,在invoke方法中不使用該對象
     * @param method 正在被調用的方法 
     * @param args 調用方法時,傳入的參數
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        return method.invoke(obj,args);
    }
}

cglib代理

靜態代理和jdk動態代理都妖氣目標對象必定要實現接口,可是有時候目標對象只是一個單獨的對象,並無實現任何接口,這個時候採用以目標對象子類的方式實現代理,該方法稱爲cglib代理

Cglib包的底層是經過使用一個字節碼處理框架ASM來轉換字節碼並生成新的類,因爲要生成子類,因此要被代理的類不能夠被final修飾

須要引入cglib的包

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>

使用步驟

  • 首先實現MethodIntercepor,方法調用會被轉發到intercept()方法
  • 使用CGLIB來獲取代理對象
public class CglibProxy implements MethodInterceptor { 

    public Object getProxy(Class clazz){
      Enhancer enhancer = new Enhancer();
        // 指定代理類的父類
        enhancer.setSuperclass(clazz);
        // 設置Callback對象
        enhancer.setCallback(this);
        // 經過字節碼技術動態建立子類實例
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置處理");
      	// 調用MethodProxy.invokeSuper方法將調用轉發給原始對象
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("後置處理");
        return result;
    }
}


public class Test {

    public void print(){
        System.out.println("方法執行");
    }

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        Test proxyImp = (Test) proxy.getProxy(Test.class);
        proxyImp.print();

    }
}

因爲自己的博客百度沒有收錄,博客地址http://zhhll.icu

相關文章
相關標籤/搜索