代理模式(靜態代理、JDK動態代理、CGLib動態代理、Spring AOP)

定義:爲其他對象提供一種代理,以控制對這個對象的訪問,代理對象在客戶端和目標對象之間起到中介的作用;
類型:結構型;

適用場景:
  1. 保護代理對象;
  2. 增強代理對象;
優點:
  1. 將代理對象與真實被調用的目標對象分離;
  2. 一定程度上降低了系統耦合度,擴展性好;
  3. 保護目標對象;
  4. 增強目標對象;
缺點:
  1. 代理模式會造成系統設計中目標類增加;
  2. 在客戶端和目標對象之間增加一個代理對象,相對會造成請求處理速度變慢;
    代理模式UML類圖
jdk靜態代理:

  jdk靜態代理實現比較簡單,一般是代理對象直接包裝了被代理對象。只能爲一個被代理類服務,如果需要代理的類比較多,那麼會產生過多的代理類。jdk靜態代理在編譯時產生class文件,運行時無需產生,可直接使用。

public class Tank implements Movable{
    public void move() throws InterruptedException {
        System.out.println("tank move---");
        Thread.sleep(new Random().nextInt(10000));
    }

    public static void main(String[] args) throws InterruptedException {
        new TankProxy(new Tank()).move();
    }
}

class TankProxy implements Movable{
    private Movable movable;
    public TankProxy(Movable movable) {
        this.movable = movable;
    }

    public void move() throws InterruptedException {
        System.out.println("tank start---");
        movable.move();
        System.out.println("tank end---");
    }
}

interface Movable{
    void move() throws InterruptedException;
}

// 輸出:
tank start---
tank move---
tank end---
jdk動態代理

  jdk動態代理會根據被代理對象生成一個繼承了Proxy類,並實現了該業務接口的jdk代理類,該類的字節碼會被傳進去的ClassLoader加載,創建了jdk代理對象實例。jdk動態代理必須實現接口,通過反射來動態代理方法,消耗系統性能。但是無需產生過多的代理類,避免了重複代碼的產生,系統更加靈活。

class TankHandler implements InvocationHandler{
    Tank tank;
    public TankHandler(Tank tank) {
        this.tank = tank;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("tank start---");
        Object invoke = method.invoke(tank, args);
        System.out.println("tank end---");
        return invoke;
    }
}

public static void main(String[] args) throws InterruptedException {
        Tank tank = new Tank();
        Movable movable = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader()
                , new Class[]{Movable.class}, new TankHandler(tank));
        movable.move();
    }
    
// 輸出:
tank start---
tank move---
tank end---
CGLib動態代理

  CGLib動態代理是繼承代理,通過ASM字節碼框架修改字節碼生成新的子類,重寫並增強方法的功能。CGLib動態代理無需實現接口,通過生成子類字節碼來實現,jdk8以後比反射快一點。但是由於cglib會繼承被代理類,需要重寫被代理方法,所以被代理類不能是final類,被代理方法不能是final。

class ProxyMethodInterceptor implements MethodInterceptor{
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("tank start---");
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("tank end---");
        return invoke;
    }
}

public static void main(String[] args) throws InterruptedException {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Tank.class);
        enhancer.setCallback(new ProxyMethodInterceptor());
        Tank tank = (Tank) enhancer.create();
        tank.move();
    }

// 輸出:
tank start---
tank move---
tank end---
Spring AOP:

   AOP(Aspect-OrientedProgramming,面向切面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。它利用一種稱爲“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其名爲“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。

  1. Aspect(切面):通常是一個類,裏面可以定義切入點和通知;
  2. JointPoint(連接點):程序執行過程中明確的點,一般是方法的調用;
  3. Advice(通知):AOP在特定的切入點上執行的增強處理,有before, after, afterReturning, afterThrowing, around;
  4. Pointcut(切入點):就是帶有通知的連接點,在程序中主要體現爲書寫切入點表達式;
  5. AOP代理:AOP框架創建的對象,代理就是目標對象的加強。Spring中的AOP代理可以使JDK動態代理,也可以是CGLIB代理,前者基於接口,後者基於子類;
@Aspect
public class AopProxy {
    @Before("execution (void designmodel.structral.proxy.aop.Tank.move())")
    public void before(){
        System.out.println("tank start---");
    }

    @After("execution (void designmodel.structral.proxy.aop.Tank.move())")
    public void after(){
        System.out.println("tank end---");
    }
}

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