Spring AOP 的代理模式
1. 前言
大家好,我們學習了 AOP 的概念,理解了 AOP 的作用,明白了什么是 AOP 面向切面編程,目的是進行解耦,可以自由地對某個功能方法做增強,而它的設計模式就是代理模式。
那么本小節我們就學習 AOP 設計模式之代理模式,明白代理模式的含義,掌握代理模式的語法,同時明白它的應用場景。
2. 代理模式介紹
3.1 概念解釋
代理名詞解釋為:以被代理人名義,在授權范圍內與第三方實施行為。而在軟件行業中代理模式是一種非常常用的設計模式,跟現實生活中的邏輯一致。
在開發中代理模式的表現為:我們創建帶有現有對象的代理對象,以便向外界提供功能接口。代理對象可以在客戶端和目標對象之間起到中介的作用。
中介什么作用? 可以為被代理對象執行一些附帶的,增加的額外功能。
代理模式圖例:
圖例解釋
- 數字 1 處表示發起請求的客戶端;
- 數字 2 處表示需要調用的接口;
- 數字 3 處表示真實接口的實現類,執行的代碼邏輯在此;
- 數字 4 處表示代理對象,同樣實現了接口,覆寫了需要執行的代碼 Request 方法;
- 數字 5 處是代理類中多余的代碼邏輯,對原有方法的增強;
- 數字 6 處是代理類中的執行的被代理類的原始邏輯。
3.2 代理模式分類
上面已經解釋了代理模式的概念和原理,在開發中,實現代理模式可以分為兩種。
- 靜態代理:若代理類在程序運行前就已經存在,那么這種代理方式被成為靜態代理 ,這種情況下的代理類通常都是我們在 Java 代碼中定義的, 靜態代理中的代理類和委托類會實現同一接口;
- 動態代理:代理類在程序運行時創建的代理方式被稱為動態代理。 也就是說,這種情況下,代理類并不是在 Java 代碼中定義的,而是在運行時根據我們在 Java 代碼中的 “指示” 動態生成的。
下面,我們就針對這兩種模式演示效果… 各位看官隨我來。
3. 代碼模式測試
3.1 靜態代理實現
1.userService 接口代碼
public interface UserService {
public void saveUser();
}
2.userServiceImpl 實現類代碼
@Service
public class UserServiceImpl implements UserService {
public void saveUser() {
System.out.println("執行service中的保存邏輯");
}
}
3.userServiceProxy 代理類代碼
public class UserServiceProxy implements UserService {
//被代理類實現接口
private UserService userService;
public UserServiceProxy(UserService userService) {
this.userService = userService;
}
//覆寫的方法
@Override
public void saveUser() {
System.out.println("原始功能執行之前的邏輯代碼");
userService.saveUser();;
System.out.println("原始功能執行之后的邏輯代碼");
}
}
代碼解釋:
userService
接口和 userServiceImpl
實現類代碼不做贅述,已經用過多次。
重點關注于在 userServiceProxy
代理類代碼,其中屬性為被代理類的接口,目的是傳入進來被代理類實例,對它做功能增強。
下面的 saveUser
方法是代理類執行的邏輯,在方法內部有增強的代碼邏輯,也保留了原始實例的代碼功能。
4. 測試代碼
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SpringConfig.class);
context.refresh();
//獲取接口實例
UserService service = context.getBean(UserService.class);
//創建實例的代理
UserServiceProxy proxy = new UserServiceProxy(service);
//執行方法
proxy.saveUser();
}
5. 測試結果
可以看到,執行結果中即包含了被代理對象的原始保存方法的邏輯,也有代理類中對原始方法的兩個增強代碼。
3.2 動態代理實現
1. 創建動態處理器
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("執行前邏輯");
Object result = method.invoke(object, args);
System.out.println("執行后邏輯");
return result;
}
}
2. 測試類代碼
public class SpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SpringConfig.class);
context.refresh();
//獲取接口實例
UserService service = context.getBean(UserService.class);
//動態創建實例的代理
UserService proxy = (UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[]{UserService.class}, new DynamicProxy(service));
//proxy執行方法
proxy.saveUser();
}
}
代碼解釋
Proxy.newProxyInstance
是 JDK 提供的一個用于動態創建代理實例的方法,JDK 1.7 的 API 有如下說明:
紅線框的內部是簡易方式創建代理對象的方式,也就是我們示例中代碼的實現方式,參數解釋如下:
- ClassLoader loader: 指定當前目標對象使用的類加載器,獲取加載器的方法是固定的
- Class<?>[] interfaces: 指定目標對象實現的接口的類型,使用泛型方式確認類型
- InvocationHandler: 指定動態處理器,執行目標對象的方法時,會觸發事件處理器的方法
3. 測試結果
4. 小結
本小節學習了代理模式以及它的的實現,那么要求大家掌握的內容如下:
1. 實現要素
被代理類最少實現一個接口。
2. 實現步驟
newProxyInstance
方法獲取代理類實例;- 編寫代理實例方法;
- 添加代理實例方法內邏輯;
- invoke 方法中調用委托類,也就是被代理類的方法。