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 程式設計的開發步驟
- 原始對象
- 額外功能 (
)MethodInterceptor
- 切入點
- 組裝切面 (額外功能+切入點)
詳情可參見之前的部落格:Spring 動态代理開發詳解
切面的名詞解釋
切面 = 切入點 + 額外功能
幾何學:面 = 點 + 相同的性質
AOP 的底層實作原理
核心問題:
-
AOP 如何建立動态代理類?
動态位元組碼技術
-
Spring 工廠如何加工建立代理對象?
通過原始對象的 id 值,獲得的是代理對象
動态代理類的建立
JDK 的動态代理(原理 + 編碼)
-
方法參數詳解Proxy.newPorxyInstance
- 編碼
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 者方法⼀緻,同時在代理類中可以提供新的實作(額外功能+原始方法)。
- 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());
}
}
總結
- JDK 動态代理
:通過接口建立代理的實作類Proxy.newProxyInstance
- Cglib 動态代理
:通過繼承父類建立的代理類Enhancer
Spring 工廠如何加工原始對象
- 思路分析:主要通過
将原始對象加工為代理對象BeanPostProcessor
- 編碼
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"/>