《spring技術內幕》讀書筆記3-AOP的實現
目錄
2.1.2 ProxyFactoryBean的getObject()
1. Demo
首先是spring aop應用:
(1)準備工作:
package com.abc;
//工人介面
public interface Worker {
void work();
}
//普通工人類
public class OrdinaryWorker implements Worker {
@Override
public void work() {
System.out.println("* * * * * 搬磚 * * * * *");
}
}
//資本家類
public class Capitalist {
public void work() {
System.out.println("$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $");
}
}
//工人增強器(手動滑稽)
public class WorkerAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return new WorkerAdvice();
}
@Override
public Pointcut getPointcut() {
String pattern = "com.abc.OrdinaryWorker.*";
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(pattern);
return pointcut;
}
static class WorkerAdvice implements AfterReturningAdvice, MethodBeforeAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("21:00 - 滴,下班:沒有困難的工作,只有勇敢的打工人!");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("9:00 - 滴,上班:早安打工人!");
}
}
}
//資本家增加器
public class CapitalistAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return new CapitalistAdvice();
}
@Override
public Pointcut getPointcut() {
String pattern = "com.abc.Capitalist.*";
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(pattern);
return pointcut;
}
static class CapitalistAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("(*^▽^*)又是愉快數錢的一天!");
}
}
}
(2)spring配置:
<bean id="workerAdvisor" class="com.abc.WorkerAdvisor"/>
<bean id="capitalistAdvisor" class="com.abc.CapitalistAdvisor"/>
<bean id="worker" class="com.abc.OrdinaryWorker"/>
<bean id="capitalist" class="com.abc.Capitalist"/>
<bean id="aopWorker" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="worker"/>
</property>
<property name="interceptorNames">
<list>
<value>workerAdvisor</value>
<value>capitalistAdvisor</value>
</list>
</property>
</bean>
<bean id="aopCapitalist" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="capitalist"></ref>
</property>
<property name="interceptorNames">
<list>
<value>workerAdvisor</value>
<value>capitalistAdvisor</value>
</list>
</property>
</bean>
(3)單測:
public class AopTest {
@Test
public void test() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("mytest/aoptest.xml"));
Object aopWorker = bf.getBean("aopWorker");
Object aopCapitalist = bf.getBean("aopCapitalist");
assert !(aopCapitalist instanceof Proxy);
assert aopWorker instanceof Proxy;
Capitalist capitalist = (Capitalist) aopCapitalist;
capitalist.work();
System.out.println("--------階級分割線--------");
Worker worker = (Worker) aopWorker;
worker.work();
}
}
(4)執行結果:
$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $
(*^▽^*)又是愉快數錢的一天!
--------階級分割線--------
9:00 - 滴,上班:早安打工人!
* * * * * 搬磚 * * * * *
21:00 - 滴,下班:沒有困難的工作,只有勇敢的打工人!
思考:為什麼斷言能順利執行 —— aopCapitalist不是Proxy的例項,而aopWorker是Proxy的例項???且看下面分解……
2. AOP的實現
2.1 生成代理
spring是如何生成目標物件的代理,即解讀:Object aopWorker = bf.getBean("aopWorker");
2.1.1 ProxyFactoryBean的UML
"aopWorker"的型別是ProxyFactoryBean,UML圖如下:
根據1:ProxyFactoryBean是工廠Bean,參考【讀書筆記2-依賴注入】可知執行工廠bean的getObject方法
根據2:ProxyFactoryBean能感知自己所在的BeanFactory,參考《Spring技術內幕-第2版》2.5.7節
根據3:ProxyFactoryBean繼承AdvisedSupport,有幾個關鍵的成員變數:targetSource(被代理的目標物件)、interfaces(代理的介面)、advisors(增強器)
2.1.2 ProxyFactoryBean的getObject()
瞭解完PRoxyFactoryBean的getObject()邏輯後,單測的問題就有答案了。主要邏輯如下:
考慮到繼承關係,通過property標籤,既可以配置諸如:interceptorNames、targetName等來自ProxyFactoryBean的成員變數,也可以配置諸如targetSource、interfaces、advisors等來自AdvisedSupport的成員變數。
無論是基於jdk動態代理的JdkDynamicAopProxy,還是基於cglib的ObjenesisCglibAopProxy,都有1個成員變數:AdvisedSupport advised,記錄了代理目標的配置資訊。
2.2 執行攔截
spring生成目標物件的代理後,代理物件是如何執行被aop攔截的方法,即解讀:((Worker) aopWorker).work()。
從2.1節可知,AopProxy有2種實現:JdkDynamicAopProxy、ObjenesisCglibAopProxy,下面就分析一下JdkDynamicAopProxy的情況
2.2.1 JdkDynamicAopProxy
Java動態代理物件執行被代理的介面方法時,會執行InvocationHandler介面的invoke()方法。
JdkDynamicAopProxy實現了InvocationHandler介面,invoke()方法的主要邏輯如下:
從整體大局瞭解程式碼邏輯後,很自然的明白為什麼chain的泛型是Object,而不是Interceptor,因為元素還可能是InterceptorAndDynamicMethodMatcher型別。而isRuntime這種情況,應該是針對方法過載的情況,相同的方法簽名資訊,入參型別不同,需要執行時再判斷是否匹配。
spring對於不同advice轉成不同MethodInterceptor,採用了介面卡模式,還有多處應用了單例模式。
相關文章
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《四》表MySql儲存引擎筆記
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《六》鎖MySql儲存引擎筆記
- 《深入分析JavaWeb技術內幕》之讀書筆記(篇三)JavaWeb筆記
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《三》檔案MySql儲存引擎筆記
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《七》事務MySql儲存引擎筆記
- Spring技術內幕筆記(2):Spring MVC 與 WebSpring筆記MVCWeb
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《二》InnoDB儲存引擎MySql儲存引擎筆記
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《五》索引與演算法MySql儲存引擎筆記索引演算法
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《八》備份與恢復MySql儲存引擎筆記
- 《現代通訊網路技術》讀書筆記筆記
- 讀《etcd 技術內幕》
- 《深入分析Java Web技術內幕》讀書筆記 - 第1章 深入Web請求過程JavaWeb筆記
- 簡述Spring技術內幕Spring
- [原創]京東技術解密讀書筆記解密筆記
- Mysql技術內幕InnoDB儲存引擎讀書筆記--《一》Mysql體系結構和儲存引擎MySql儲存引擎筆記
- 《自我實現的人》讀書筆記筆記
- spring boot實戰讀書筆記(1)Spring Boot筆記
- 《Spring In Action》讀書筆記Spring筆記
- 讀書筆記-大型網站技術架構筆記網站架構
- 《淘寶技術這十年》讀書筆記筆記
- 《資料探勘概念與技術》讀書筆記筆記
- 【技術分享】《深入理解Elasticsearch》讀書筆記Elasticsearch筆記
- 『淘寶十年技術路』讀書筆記筆記
- 《大型網站技術架構》讀書筆記網站架構筆記
- 書訊:《Spring技術內幕——深入解析Spring架構與設計原理》Spring架構
- 《快速閱讀術》讀書筆記筆記
- 《深入淺出MyBatis--技術原理與實戰》讀書筆記MyBatis筆記
- 《Spring實戰》讀書筆記 #每日筆記 100-004Spring筆記
- 《Spring MVC CookBook》讀書筆記SpringMVC筆記
- Lua設計與實現--讀書筆記筆記
- 《Redis設計與實現》讀書筆記Redis筆記
- 讀書筆記】《PostgreSQL指南-內幕探索》-2.程式和記憶體架構筆記SQL記憶體架構
- Spring技術內幕筆記2--我懶不寫了哈哈哈哈。Spring筆記
- WebKit技術內幕WebKit
- 【Laravel】Laravel 框架關鍵技術解析·讀書筆記(二)Laravel框架筆記
- 【讀書筆記】《PostgreSQL指南-內幕探索》-8.緩衝區管理器筆記SQL
- 【讀書筆記】《PostgreSQL指南-內幕探索》-7.堆內元組和僅索引掃描筆記SQL索引
- 讀書筆記】《PostgreSQL指南-內幕探索》-3.2單表查詢的代價估計筆記SQL