Spring AOP 代理總結:靜態代理和動態代理
參考:https://mp.weixin.qq.com/s/dLOn23waK4gv-Rp9dC0Kfg
0、作用
***將業務邏輯和系統處理的代碼(關閉連接、事務管理、操作日誌記錄)解耦。***
1、靜態代理
自己手動創建Proxy
類,並將RealSubject
類注入。
2、動態代理 - JDK、Cglib
運行時增強:動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。
動態代理主要包含:
JDK動態代理:利用反射接收被代理的類,從而生成代理類Proxy類。被代理的類必須實現一個接口
Cglib動態代理:生成被代理類的子類作爲代理類。(所以==被代理類不能被
final
修飾==)spring aop會根據被代理類是否實現了某個接口來自動選擇動態代理方式
1)JDK動態代理
必須實現一個接口(必須有接口和實現類)
目標類接口:
package a_proxy.a_jdk;
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
實現類:
package a_proxy.a_jdk;
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("a_proxy.a_jdk addUser()");
}
@Override
public void updateUser() {
System.out.println("a_proxy.a_jdk updateUser()");
}
@Override
public void deleteUser() {
System.out.println("a_proxy.a_jdk deleteUser()");
}
}
切面類:
package a_proxy.b_cglib;
public class MyAspect {
public void before() {
System.out.println("雞首");
}
public void after() {
System.out.println("牛後");
}
}
工廠類(生成代理類):
package a_proxy.a_jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyBeanFactory {
public static UserService createService() {
//1目標類
UserService userService = new UserServiceImpl();
//2切面類
MyAspect myAspect = new MyAspect();
/*
*3代理類:將目標類(切入點)和切面類(通知)結合--->切面
*
* Proxy.newProxyInstance
* 參數1:loader:類加載器,動態代理類運行時創建,任何類都需要類加載器將其加載到內存。
* 一般情況:採用當前類.class.getClassLoader();
* 目標類實例.getClass().getClassLoader();
* 參數2:interfaces:代理類要實現的所有接口
* 方式1:目標實例.getClass().getInterfaces() ,注意:只能獲得自己的接口,不能獲得父元素接口
* 方式2:new Class[]{UserService.class}
* 參數3:InvocationHandler:處理類,是一個接口,必須進行實現類,一般採用匿名內部方式.表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個 InvocationHandler 對象上
* 提供invoke方法,代理類的每一個方法執行時,都將調用一次invoke
* 參數1:Object proxy:代理對象
* 參數2:Method method:代理對象當前執行的方法的描述對象(反射)
* 執行方法名:method.getName()
* 執行方法:method.invoke(對象,實際參數)
* 參數3:Object[] args:方法的實際參數
* */
UserService proxyService = (UserService) Proxy.newProxyInstance(
MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前執行
myAspect.before();
//執行目標類方法
Object obj = method.invoke(userService, args);
//後執行
myAspect.after();
return obj;
}
}
);
return proxyService;
}
}
Proxy.newProxyInstance
內部通過反射創建代理對象(實現了某接口)。
每一個動態代理類都必須要實現 InvocationHandler
這個接口,並且每個代理類的實例都關聯到了一個 Handler
,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由 InvocationHandler
這個接口的 invoke
方法來進行調用。
測試類:
package a_proxy.a_jdk;
import org.junit.Test;
public class TestJDK {
@Test
public void demo1() {
UserService userService = MyBeanFactory.createService();
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
}
結果:
注意:
通過 Proxy.newProxyInstance 創建的代理對象是在 jvm 運行時動態生成的一個對象,它並不是我們的 InvocationHandler 類型,也不是我們定義的那組接口的類型,而是在運行是動態生成的一個對象,並且命名方式都是這樣的形式,以$開頭,proxy 爲中,最後一個數字表示對象的標號,如
com.sun.proxy.$Proxy0
。
2)Cglib動態代理(字節碼增強)
不需要接口,只有實現類
!!!在運行時創建目標類的子類(代理類),從而對目標類進行增強!!!
工廠類:
package a_proxy.b_cglib;
public class MyBeanFactory {
public static UserServiceImpl createService() {
//1目標類
UserServiceImpl userService = new UserServiceImpl();
//2切面類
MyAspect myAspect = new MyAspect();
/*
* 3 代理類,採用cglib,底層創建目標的子類
* */
//3.1核心類
Enhancer enhancer = new Enhancer();
//3.2確定父類
enhancer.setSuperclass(userService.getClass());
//3.3設置回調 MethodInterceptor接口等效於jdk中的InvocationHandler
/*
* intercept()等效於jdk的invoke()
* 參數1,2,3與invoke的一樣
* 參數4:methodProxy方法的代理,通常不用
* */
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//前
myAspect.before();
//執行目標類的方法
Object obj = method.invoke(userService, objects);
//執行代理類的父類,即目標類(目標類和代理類是父子關係)
//methodProxy.invokeSuper(o, objects);
//後
myAspect.after();
return obj;
}
});
//3.4創建代理
UserServiceImpl proxyService = (UserServiceImpl)enhancer.create();
return proxyService;
}
}
測試類:
package a_proxy.b_cglib;
import org.junit.Test;
public class TestCglib {
@Test
public void demo1() {
UserServiceImpl userService = MyBeanFactory.createService();
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
}
結果與jdk動態代理相同