SpringBoot系列(2)——AOP-靜態代理與動態代理

摘要

  • 分別演示靜態代理和動態代理

靜態代理

手動代理

interface

public interface Interface_ {
    public void do();
}

須要被增強的類

public class Object_ implements Interface_{
    @Override
    public void do() {
        System.out.println("do");
    }
}

代理類

public class Object_Agent implements Interface_{

    private Object_ object_;
    public Object_Agent(Object_ object_) {
        this.object_ = object_;
    }

    @Override
    public  void do() {
        System.out.println("enhance");
        object_.do();
    }
    
    public static void main(String[] args) {
        Object_ object_ = new Object_();
        Object_Agent agent = new Object_Agent(object_);
        agent.do();
    }

}

AspectJ靜態

  • 編寫方式和spring aop沒有區別
  • Aspectj並非動態的在運行時生成代理類,而是在編譯的時候就植入代碼到class文件
  • 因爲是靜態織入的,因此性能相對來講比較好

動態代理

  • JDK動態代理是基於接口的方式,代理類和目標類都實現同一個接口。
  • CGLib動態代理是代理類去繼承目標類,而後重寫其中目標類的方法。

JDK動態代理

接口

public interface Interface_ {
    public void do();
}

須要被增強的類

public class Object_ implements Interface_{
    @Override
    public void do() {
        System.out.println("do");
    }
}

處理器實現類

public class InvocationHandlerImpl implements InvocationHandler{

    private Object object;
    public InvocationHandlerImpl(Object object)
    {
        this.object = object;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        System.out.println("enhance");
        Object object = method.invoke(object, args);
        return object;
    }
}

測試

public class DynamicProxyDemonstration
{
    public static void main(String[] args)
    {
        Interface_ object_ = new Object_();
        InvocationHandler handler = new InvocationHandlerImpl(object_);
        ClassLoader loader = object_.getClass().getClassLoader();
        Class[] interfaces = object_.getClass().getInterfaces();
        Interface_ object__ = (Interface_) Proxy.newProxyInstance(loader, interfaces, handler); 
        object__.do();
    }
 
}

CGlib動態代理

POM

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

須要被增強的類

public class Object_{
    public  void do() {
        System.out.println("do");
    }
}

方法攔截器

public class MyMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("enhance");
        Object object = proxy.invokeSuper(obj, args);
        return object;
    }  
}

測試

public class CgLibProxy {
    public static void main(String[] args) {
        //建立Enhancer對象,相似於JDK動態代理的Proxy類,下一步就是設置幾個參數
        Enhancer enhancer = new Enhancer();
        //設置目標類的字節碼文件
        enhancer.setSuperclass(Object_.class);
        //設置回調函數
        enhancer.setCallback(new MyMethodInterceptor());
        //建立加運行
        Object_ proxyObject_ = (Object_)enhancer.create();
        proxyObject_.do();       
    }
}

爲啥轉變被CGlib

通常寫代碼:html

@Autowired
UserService userService;

出錯代碼:java

@Autowired
UserServiceImpl userService;

啓動報錯

JDK 動態代理是基於接口的,代理生成的對象只能賦值給接口變量。git

而 CGLIB 就不存在這個問題。由於 CGLIB 是經過生成子類來實現的,代理對象不管是賦值給接口仍是實現類這二者都是代理對象的父類。github

總結

  • Spring5 默認aop實現爲CGlib
  • JDK動態代理是基於接口的,CGlib動態代理是基於繼承的

參考

[1].CGLib動態代理spring

[2].java反射和代理ide

[3].驚人!Spring5 AOP 默認使用Cglib? 從現象到源碼深度分析函數

本文做者: Both Savage

本文連接: https://bothsavage.github.io/...性能

版權聲明: 本博客全部文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!測試

相關文章
相關標籤/搜索