用到了AOP的動態代理模式: java
1.畫圖:把切面畫出來 性能
2.舉個例子進行說明 this
3:實現原理: spa
切面的意義何在?
設計
首先根據上例,假設咱們實現了一個通用的權限檢查模塊,那麼就能夠在這層切面上進
行統一的集中式權限管理。權限檢查模塊能夠和業務邏輯代碼分離,而業務邏輯組件則無需關心權限方面的問題。系統大部分有權限檢查模塊,用的時候直接拿來用這個切面。也就是說,經過切面,咱們能夠將系統中各個不一樣層次上的問題隔離開來,實現統一集約式處理。各切面只需集中於本身領域內的邏輯實現。 代理
這一方面使得開發邏輯更加清晰,專業化分工更加易於進行;另外一方面,因爲切面的隔 日誌
離,下降了耦合性,咱們就能夠在不一樣的應用中將各個切面組合使用,從而使得代碼可重用 對象
性大大加強。 繼承
若是是面向接口的動態代理的實現,即JDKProxy,其代理對象必須是某個接口的實現,使用java.lang.reflect.Proxy類根據一個被代理對象產生一個代理對象userDAOProxy,經過Proxy類的調用靜態方法newProxyInstance,根據要實現的接口來產生(這裏爲UserDao接口)(也就是說接口裏面有哪些方法,我生成的代理裏面就有哪些方法);以及實現java.lang.reflect.InvocationHandler接口,實現invoke方法實現方法的截獲處理,也就是在方法的先後加上業務邏輯。 接口
當你想在多個方法先後加上業務邏輯的時候,可使用動態代理,更加靈活方便,代碼的可重用性大大的提高。
LogIntercepter li = new LogIntercepter();
li.setTarget(userDAO);//引入一個被代理的對象userDAO
UserDao userDAOProxy = (UserDao) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),userDAO.getClass().getInterfaces(), li);
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
beforeMethod();//在方法前面添加業務邏輯,也就是日誌
m.invoke(target, args);//target Method方法所屬的對象,表示被代理對象動態調用invoke()
return null;
}
若是沒有實現接口,也沒有關係,能夠用CGLib(面向Class)實現AOP。
CGLibProxy與JDKProxy的代理機制基本相似,只是其動態代理的代理對象並不是某個接口的實現,而是針對目標類擴展的子類。話句話說JDKProxy返回動態代理類,是目標類所實現接口的另外一個實現版本,它實現了對目標類的代理(如同UserDAOProxy與UserDAOImp的關係),而CGLibProxy返回的動態代理類,則是目標代理類的一個子類(代理類擴展了UserDaoImpl類)
Enhancer和MethodInterceptor在CGLib中負責完成代理對象建立和方法截獲處理。
Enhancer建立代理對象,實現MethodInterceptor接口,實現intercept方法來進行方法截取處理。
(CGLib (Code Generation Library) 字節碼類庫是一個強大的,高性能,高質量的Code生成類庫。它能夠在運行期擴展Java類與實現Java接口。Hibernate用它來實現PO字節碼的動態生成。CGLib 比 Java 的 java.lang.reflect.Proxy 類更強的在於它不只能夠接管接口類的方法,還能夠接管普通類的方法。)
JDK動態代理和CGLIB字節碼生成的區別:
* JDK動態代理只能對實現了接口的類生成代理,而不能針對類.
* CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
由於是繼承,因此該類或方法最好不要聲明成final。
JDK代理是不須要以來第三方的庫,只要JDK環境就能夠進行代理,它有幾個要求
* 實現InvocationHandler
* 使用Proxy.newProxyInstance產生代理對象
* 被代理的對象必需要實現接口
CGLib 必須依賴於CGLib的類庫,可是它須要類來實現任何接口代理的是指定的類生成一個子類,覆蓋其中的方法,是一種繼承
AOP的應用:
作權限的檢查:設計完備的權限管理組件,完成以往須要大費周折才能完成的權限斷定功能。
可是目前尚未一個完善的實現,一方面是由於權限檢查過於複雜多變,不一樣的業務邏輯中的權限斷定邏輯可能多種多樣;另外一方面,就目前的AOP應用的粒度而言,「權限管理」做爲一個切面顯得過於龐大,須要進一步設計,設計複雜,實現難度大。
,作日誌,作審計,作性能,作事務的處理。項目裏面主要用在了聲明式的事務處理上。
一、JDK方式:PersonService爲接口,PersonServiceBean爲實現類,
public class JDKProxyFactory implements InvocationHandler {
private
Object targetObject;
public Object createProxyIntance(Object
targetObject)
{
this.targetObject=targetObject;
return
Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
this.targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable {
PersonServiceBean
person=(PersonServiceBean)this.targetObject;
Object result=null;
if(person.getUser()!=null)
{
result =
method.invoke(targetObject, args);
}
return result;
}
}
二、使用CGlib包實現:PersonServiceBean爲實現類, 而沒有PersonService接口,
public class CGlibProxyFactory implements MethodInterceptor{
private
Object targetObject;
public Object createProxyInstance(Object
targetObject)
{
this.targetObject=targetObject;
Enhancer
enhancer=new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());//設置目標類的子類,該子類會覆蓋全部父類中的非final方法
enhancer.setCallback(this);//設置回調
return enhancer.create();
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { PersonServiceBean person=(PersonServiceBean)this.targetObject; Object result=null; if(person.getUser()!=null) { result = methodProxy.invoke(targetObject, args); } return null; } }