第三篇:從Java基礎談Spring AOP--動態代理原理分析AOP技術
首先讀者務必要理解第二篇的內容(鏈接描述),否則你很難理解這篇文章。
讓我們再做一個動態代理的例子,你就馬上能夠能夠理解AOP是個啥東西。好讓我們開始定義一個Javabean,它十分簡單,也不需要我多做解釋:
package com.learn.chapter1.aop;
/**
*
* @author ykzhen2015
*/
public class ConfigBean {
private boolean flag = false;//標記代理對象是否使用這個類進行處理.
private boolean useAround = false;//是否啟用環繞通知
public void before() {
System.err.println("前置消息");
}
public void after() {
System.err.println("后置消息");
}
public void afterReturn() {
System.err.println("正常返回后的消息");
}
public void afterThrowing() {
System.err.println("返回后的消息");
}
public Object around() {
System.err.println("環繞通知");
return null;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean isUseAround() {
return useAround;
}
public void setUseAround(boolean useAround) {
this.useAround = useAround;
}
}
細心的讀者就看到了,正是我們AOP看到的前置消息,后置消息,環繞消息,正常返回后的消息,異常返回消息。外加一個flag標記,它的作用就等同于一個切點,至于什么叫切點,這里放放,不用管它,我們就知道它是個boolean值,是個開關就成了,而useAround意思是是否啟用環繞通知,也是一個開關。
跟著就是上篇,你們熟悉的兩個類,一個十分簡單的接口和實現類:
package com.learn.chapter1.aop;
/**
* @author ykzhen2015
*/
public interface HelloService {
public void sayHello(String name);
}
實現類:
package com.learn.chapter1.aop;
/**
*
* @author ykzhen2015
*/
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.err.println("hello " + name);
}
}
實現類也很簡單,跟著我們改寫一些我們上篇談到的代理類,還是兩個步驟:
- 綁定HelloServiceImpl生成代理類
- 實現代理方法
代碼如下:
package com.learn.chapter1.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* * * @author ykzhen2015.
*/
public class HelloProxy implements InvocationHandler {
private ConfigBean configBean = null;
private Object target;
/**
* * 生成代理對象,并和真實服務對象綁定. * @param target 真實服務對線下 * @return 代理對象
*/
public Object bind(Object target) {
this.target = target; //生成代理對象,并綁定.
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //類的加載器
target.getClass().getInterfaces(), //對象的接口,明確代理對象掛在哪些接口下
this);//指明代理類,this代表用當前類對象,那么就要求其實現InvocationHandler接口
return proxy;
}
/**
* * 當生成代理對象時,第三個指定使用HelloProxy進行代理時,代理對象調用的方法就會進入這個方法。
*
* @param proxy ——代理對象
* @param method -- 被調用的方法
* @param args -- 方法參數
* @return 代理方法返回。
* * @throws Throwable -- 異常處理
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ConfigBean config = this.getConfigBean();
if (!config.isFlag()) {//切點
return method.invoke(target, args);
}
config.before();//前置消息
Object obj = null;
try {
if (config.isUseAround()) {
obj = config.around();//環繞通知
} else {
obj = method.invoke(target, args);//相當于sayHello方法調用.
}
} catch(Exception ex) {
config.afterThrowing();//返回異常消息
}
config.after();//后置通知
return obj;
}
public ConfigBean getConfigBean() {
return configBean;
}
public void setConfigBean(ConfigBean configBean) {
this.configBean = configBean;
}
}
好了,這個bind方法我們上篇論述過了,我們關注的是Invoke方法。
1、首先獲取一個ConfigBean,(如果是Spring就是攔截器)
2、其次判斷是否啟用一個ConfigBean進行處理(Spring切點判斷,它一般用正則式,大同小異),如果不用則直接反射真實對象HelloService的sayHello方法,完成任務,如果用,則走第3步
3、啟動前置通知before(Spring也是一樣)
4、進入try ... catch...,如果環繞通知標志為true(spring是判斷有沒有環繞通知),則執行環繞通知;否則就反射被代理對象的方法。(Spring也是一樣)
5、反射后,可能發生異常或者不發生,不發生就進入afterReturn方法,正常返回通知;發生異常就進入afterThrowing方法,異常返回通知。(Spring也是一樣)
6、最后執行后置通知after方法,完成整個AOP的過程。(Spring也是一樣)
好了,上面就大概是Spring執行各類通知的過程,怎么樣在動態代理的分析是不是比教科書的還要清晰?
最后我們測試一下這段代碼:
package com.learn.chapter1.aop;
/**
*
* @author ykzhen2015
*/
public class AopMain {
public static void main(String[] args) {
HelloProxy helloProxy = new HelloProxy();
HelloService helloService = (HelloService) helloProxy.bind(new HelloServiceImpl());
ConfigBean config = new ConfigBean();
config.setFlag(true);
config.setUseAround(true);
helloProxy.setConfigBean(config);
helloService.sayHello("張三");
}
}
好看看執行結果:
前置消息
環繞通知
后置消息
在Spring的AOP中你拿到的就類似于這里的代理對象——proxy,進行了動態代理。好了這里分析了,切點,各類消息它們執行的過程,下一篇我們會更深入的討論AOP的原理,不過到這里你已經基本掌握了AOP的整個過程。
本文原創發布于慕課網 ,轉載請注明出處,謝謝合作
共同學習,寫下你的評論
評論加載中...
相關文章推薦