Spring AOP中的代理模式

1、代理模式

類A須要完成的工做由類B去完成,類B其實是在類A的基礎上做了一層封裝,類B包括原始類A的業務邏輯以及先後的擴展邏輯,實現了類A的功能擴展
類A→被代理類/代理目標類/委託類
類B→代理類html

2、靜態代理

手動建立代理類,代理類的實現方法中對對原始的業務邏輯進行了擴展,兩個要點:java

  1. 代理類、委託類須要實現相同的接口
  2. 代理類中持有委託類的對象

特色:spring

  1. 每進行一次功能擴展,就要對委託類手動建立至少一個相對應的代理類
  2. 原理簡單,可是程序過於繁瑣與臃腫

定義一個接口,測試

package com.imooc.spring.aop.service;

public interface UserService {
    public void createUser();
}

委託類,this

package com.imooc.spring.aop.service;

public class UserServiceImpl implements UserService{
    public void createUser() {
        System.out.println("執行建立用戶業務邏輯");
    }
}

代理類,3d

package com.imooc.spring.aop.service;

import java.text.SimpleDateFormat;
import java.util.Date;
//靜態代理是指必須手動建立代理類的代理模式使用方式
public class UserServiceProxy implements UserService{
    //持有委託類的對象
    private UserService userService ;
    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }

    public void createUser() {
        //添加其餘的邏輯,實現功能擴展
        System.out.println("========靜態代理前置擴展功能======");
        userService.createUser();
        System.out.println("========靜態代理後置擴展功能======");
    }
}

測試入口類,代理

package com.imooc.spring.aop;

import com.imooc.spring.aop.service.UserService;
import com.imooc.spring.aop.service.UserServiceImpl;
import com.imooc.spring.aop.service.UserServiceProxy;
import com.imooc.spring.aop.service.UserServiceProxy1;

public class Application {
    public static void main(String[] args) {
        UserService userService = new UserServiceProxy(new UserServiceImpl());
        userService.createUser();
    }
}

測試結果,code

========靜態代理前置擴展功能======
執行建立用戶業務邏輯
========靜態代理後置擴展功能======

3、動態代理

動態代理分爲JDK動態代理、CGLib動態代理orm

JDK動態代理

接口、委託類沿用上面的Userservice、UserserviceImpl,JDK動態代理須要實現InvocationHandler接口,重寫invoke方法 ,htm

package com.imooc.spring.aop.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * InvocationHandler是JDK提供的反射類,用於在JDK動態代理中對目標方法進行加強
 * InvocationHandler實現類與切面類的環繞通知相似
 */
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;//目標對象,對全部類生效,因此目標對象類型選擇Object
    public ProxyInvocationHandler(Object target){
        this.target = target;
    }
    /**
     * 在invoke()方法對目標方法進行加強
     * @param proxy 代理類對象
     * @param method 目標方法對象
     * @param args 目標方法實參
     * @return 目標方法運行後返回值
     * @throws Throwable 目標方法拋出的異常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("========JDK動態代理前置擴展功能======");
        Object ret = method.invoke(target, args);//調用目標方法,相似環繞通知中的ProceedingJoinPoint.proceed()
        System.out.println("========JDK動態代理後置擴展功能======");
        return ret;
    }

}

測試入口類,

package com.imooc.spring.aop;

import com.imooc.spring.aop.service.*;

import java.lang.reflect.Proxy;

public class Application {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        //動態建立代理類
        //Proxy.newProxyInstance 根據已經存在的接口,實現其相對應的代理類
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        userServiceProxy.createUser();

        
    }
}

測試結果,

========JDK動態代理前置擴展功能======
執行建立用戶業務邏輯
========JDK動態代理後置擴展功能======

JDK動態代理邏輯框圖

JDK動態代理主要包括兩個步驟:
1.UserService userServiceProxy =Proxy.newProxyInstance();//建立代理類,newProxyInstance()根據已有的接口,生成對應的代理類
2.userServiceProxy.createUser(); //代理類與委託類實現了相同的接口,代理類實現接口中的業務邏輯

1.Proxy.newProxyInstance()在執行步驟:

  1. 在本地硬盤上建立$Proxy0.class代理類的class文件
  2. 肯定代理類的包名:com.sun.proxy
  3. 肯定代理類的類名:com.sun.proxy.$Proxy0
  4. ProxyGenerator.generateProxyClass生成代理類的代碼,具體可參考圖中的僞代碼
  5. defineclass0將硬盤中的.Class字節碼文件經過被代理類的classLoder(類加載器),載入到當前JVM的方法區中,並經過new $Proxy0實例化對象,$Proxy0對象中包含UserServiceImpl對象的引用
  6. 第5步獲得代理類的對象userServiceProxy ,至此完成了Proxy.newProxyInstance()的全部工做

動態生成的代理類$Proxy0與委託類UserServiceImpl實現了相同的接口UserService

代理類$Proxy0中包含委託類的對象的引用:targetObject

實現接口中的方法:具體實現代碼來自InvocationHandler實現類中的invoke方法

2.調用userServiceProxy.createUser();實現委託類的功能擴展,createUser()中的代碼對應僞代碼中方法中的業務邏輯

CGLib動態代理

委託類實現了接口,能夠經過JDK動態代理實現功能擴展,委託類沒有接口,則經過CGLib第三方組件實現功能擴展
CGLib第三方組件繼承須要加強的類,產生一個子類,並重寫父類中的方法,實現功能擴展

參考文獻

1.https://www.cnblogs.com/teach/p/10763845.html

擴展閱讀

1.類加載機制 https://www.cnblogs.com/insist-bin/p/11223876.html

相關文章
相關標籤/搜索