天天看點

【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理

AOP程式設計

  • AOP 程式設計
    • AOP 概念
    • AOP 程式設計的開發步驟
    • 切面的名詞解釋
  • AOP 的底層實作原理
    • 動态代理類的建立
      • JDK 的動态代理(原理 + 編碼)
      • CGlib 的動态代理
    • Spring 工廠如何加工原始對象
更多内容請檢視筆記目錄:【Spring 5.x】學習筆記彙總

AOP 程式設計

AOP 概念

POP (Producer Oriented Programing)

  • 面向過程(方法、函數)程式設計 —— C
  • 以過程為基本機關的程式開發,通過過程間的彼此協同,互相調用,完成程式的建構。

OOP (Object Oritened Programing)

  • 面向對象程式設計 —— Java
  • 以對象為基本機關的程式開發,通過對象間的彼此協同,互相調用,完成程式的建構。

AOP (Aspect Oriented Programing)

  • 面向切面程式設計 = Spring動态代理開發
  • 以切面為基本機關的程式開發,通過切面間的彼此協同,互相調用,完成程式的建構。
  • 切面 = 切入點 + 額外功能

AOP 的概念:

  • 本質就是 Spring 的動态代理開發,通過代理類為原始類增加額外功能。
  • 好處:利于原始類的維護
  • 注意:AOP 程式設計不可能取代 OOP,AOP 是 OOP 程式設計的補充。

AOP 程式設計的開發步驟

  1. 原始對象
  2. 額外功能 (

    MethodInterceptor

    )
  3. 切入點
  4. 組裝切面 (額外功能+切入點)

詳情可參見之前的部落格:Spring 動态代理開發詳解

切面的名詞解釋

切面 = 切入點 + 額外功能

幾何學:面 = 點 + 相同的性質

【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理

AOP 的底層實作原理

核心問題:

  1. AOP 如何建立動态代理類?

    動态位元組碼技術

  2. Spring 工廠如何加工建立代理對象?

    通過原始對象的 id 值,獲得的是代理對象

動态代理類的建立

JDK 的動态代理(原理 + 編碼)

  • Proxy.newPorxyInstance

    方法參數詳解
    【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理
    【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理
  • 編碼
public class TestJDKProxy {
    /**
     1. 借⽤類加載器  TestJDKProxy 或 UserServiceImpl 都可以
     2. JDK8.x 前必須加 final
     final UserService userService = new UserServiceImpl();
     */
    public static void main(String[] args) {
        // 1. 建立原始對象
        UserService userService = new UserServiceImpl();

        // 2. JDK 動态代理
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("---- proxy log ----");
                // 原始方法運作
                Object ret = method.invoke(userService, args);
                return ret;
            }
        };
        UserService userServiceProxy = (UserService) Proxy.
                newProxyInstance(TestJDKProxy.class.getClassLoader(),
                                userService.getClass().getInterfaces(),
                                handler);
        userServiceProxy.login("zhenyu", "123456");

        userServiceProxy.register(new User());
    }
}
           

CGlib 的動态代理

CGlib 建立動态代理的原理:通過父子繼承關系建立代理對象,原始類作為父類,代理類作為子類,這樣既可以保證 2 者方法⼀緻,同時在代理類中可以提供新的實作(額外功能+原始方法)。

【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理
  • CGlib 編碼
public class TestCglib {
    public static void main(String[] args) {
        // 1. 建立原始對象
        UserService userService = new UserService();

        /*
         2. 通過 cglib 方式建立動态代理對象
         對比 jdk 動态代理 ---> Proxy.newProxyInstance(classLoader, interface, invocationHandler);

         Enhancer.setClassLoader()
         Enhancer.setSuperClass()
         Enhancer.setCallBack() ---> MethodInterceptor(cglib)
         Enhancer.createProxy() ---> 建立代理對象
         */
        Enhancer enhancer = new Enhancer();

        enhancer.setClassLoader(TestCglib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("--- cglib log ----");
                Object ret = method.invoke(userService, args); // 執行原始方法
                return ret;
            }
        };

        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("zhenyu", "123456");
        userServiceProxy.register(new User());
    }
}
           

總結

  1. JDK 動态代理

    Proxy.newProxyInstance

    :通過接口建立代理的實作類
  2. Cglib 動态代理

    Enhancer

    :通過繼承父類建立的代理類

Spring 工廠如何加工原始對象

  • 思路分析:主要通過

    BeanPostProcessor

    将原始對象加工為代理對象
【Spring AOP】AOP 底層實作原理 —— 動态代理類的建立(JDK、CGlib)、工廠如何加工原始對象AOP 程式設計AOP 的底層實作原理
  • 編碼
public class ProxyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("--- new log ---");
                Object ret = method.invoke(bean, args);
                return ret;
            }
        };
        return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), handler);
    }
}
           
<bean id="userService" class="com.yusael.factory.UserServiceImpl"/>
<!--1. 實作 BeanPostProcessor 進行加工-->
<!--2. 配置檔案中對 BeanPostProcessor 進行配置-->
<bean id="proxyBeanPostProcessor" class="com.yusael.factory.ProxyBeanPostProcessor"/>