国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java實現AOP面向切面編程的實例教程

2019-11-26 14:24:57
字體:
來源:轉載
供稿:網友

介紹

眾所周知,AOP(面向切面編程)是Spring框架的特色功能之一。通過設置橫切關注點(cross cutting concerns),AOP提供了極高的擴展性。那AOP在Spring中是怎樣運作的呢?當你只能使用core java,卻需要AOP技術時,這個問題的解答變得極為關鍵。不僅如此,在高級技術崗位的面試中,此類問題也常作為考題出現。這不,我的朋友最近參加了一個面試,就被問到了這樣一個棘手的問題――如何在不使用Spring及相關庫,只用core Java的條件下實現AOP。因此,我將在本文中提供一份大綱,幫助大家了解如何只用core Java實現一個AOP(當然啦,這種AOP在功能上有一定的局限性)。注意,本文不是一篇有關Spring AOP與Java AOP的對比研究,而是有關在core Java中借助固有的設計模式實現AOP的教程。

想必讀者已經知道AOP是什么,也知道在Spring框架中如何使用它,因此本文只著眼于如何在不用Spring的前提下實現AOP。首先,我們得知道,Spring是借助了JDK proxy和CGlib兩種技術實現AOP的。JDK dynamic proxy提供了一種靈活的方式來hook一個方法并執行指定的操作,但執行操作時得有一個限制條件:必須先提供一個相關的接口以及該接口的實現類。實踐出真知,讓我們透過一個案例來理解這句吧!現在有一個計算器程序,用于完成一些數學運算。讓我們來考慮下除法功能,此時的問題是:如果core framework 已經具備了一份實現除法的代碼,我們能否在代碼執行時劫持(highjack)它并執行額外的校驗呢?答案是肯定的,我將用下面提供的代碼片段來證明這點。首先來看基礎接口的代碼:

public interface Calculator {  public int calculate( int a , int b);}

該接口實現類的代碼如下:

public class CalculatorImpl implements Calculator {  @Override  public int calculate(int a, int b) {    return a/b;  }}

假設我們既不能修該上面的代碼,也不能對核心庫進行任何改動,怎樣才能完美地實現校驗功能呢?不如試下JDK dynamic proxy的功能吧。

public class SomeHandler implements InvocationHandler { // Code omitted for simplicity…..   @Override  public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {// Your complex business validation and logic    Object result = method.invoke(targetObject ,params);    return result;  } }

讓我們通過測試類來看看由JDK dynamic proxy實現的校驗功能的效果如何。

public static void main(String[] args) {    CalculatorImpl calcImpl = new CalculatorImpl();    Calculator proxied = (Calculator)ProxyFactory.getProxy (Calculator.class, calcImpl,         new SomeHandler(calcImpl));    int result = proxied.calculate(20, 10);    System.out.println("FInal Result :::" + result);  }

從結果可以看出,簡單地實現功能強大的InvocationHandler接口,我們便能得到一個hooking implementation。按照JDK文檔的描述,InvocationHandler接口是借助一個代理實例(proxy instance)來處理一個方法調用的。

現在我們已經知道,InvocationHandler的invoke()方法能夠幫助我們解決問題。那么再來解決一個新問題――怎樣才能在方法執行的前后執行操作呢?說的更具體一些,我們能通過添加多個aop(before、after、around)來hook一個方法嗎(譯注:原文為add multiple aops,但我認為Handler是充當Aspect的角色)?答案同樣是肯定的。按照以下的步驟建立一個精簡的代碼模板便能滿足這樣的需求:

  • 創建一個抽象類,用于將aop應用于目標對象上。
  • 創建名為BeforeHandler 和 AfterHandler的兩個aop。前者在方法執行之前工作,而后者則在方法執行結束后工作。
  • 創建一個代理類,使所有的aop handler和目標對象只需作為參數傳入,就能創建一個hook。
  • 加入你自己的業務邏輯或者橫切關注點。
  • 最后,通過傳入相關的參數創建代理對象(proxy object)。

兩種實現AOP的方式: 

1,JDK提供的動態代理實現  
接口 

public interface UserBean {   void getUser();   void addUser();   void updateUser();   void deleteUser(); } 

原始實現類 

public class UserBeanImpl implements UserBean {   private String user = null;   public UserBeanImpl()   {       }     public UserBeanImpl(String user)   {     this.user = user;   }     public String getUserName()   {     return user;   }     public void getUser()   {     System.out.println("this is getUser() method!");   }    public void setUser(String user)   {     this.user = user;     System.out.println("this is setUser() method!");   }   public void addUser()   {     System.out.println("this is addUser() method!");   }      public void updateUser()   {     System.out.println("this is updateUser() method!");   }     public void deleteUser()   {     System.out.println("this is deleteUser() method!");    }     } 

代理類  

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.cignacmc.finance.bean.UserBeanImpl;  public class UserBeanProxy implements InvocationHandler {   private Object targetObject;      public UserBeanProxy(Object targetObject)   {     this.targetObject = targetObject;       }      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   {     UserBeanImpl userBean = (UserBeanImpl) targetObject;     String userName = userBean.getUserName();     Object result = null;          //權限判斷     if(userName != null && !"".equals(userName))     {       result = method.invoke(targetObject, args);     }          return result;   } } 

 
測試類  

import java.lang.reflect.Proxy;  import com.cignacmc.finance.bean.UserBean; import com.cignacmc.finance.bean.UserBeanImpl; import com.cignacmc.finance.proxy.UserBeanProxy;  public class ProxyExe {   public static void main(String[] args)   {     System.out.println("Proved.............");     UserBeanImpl targetObject = new UserBeanImpl("Bob Liang");        UserBeanProxy proxy = new UserBeanProxy(targetObject);     //生成代理對象         UserBean object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),          targetObject.getClass().getInterfaces(), proxy);     object.addUser();          System.out.println("NO Proved.............");     targetObject = new UserBeanImpl();        proxy = new UserBeanProxy(targetObject);     //生成代理對象         object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),          targetObject.getClass().getInterfaces(), proxy);     object.addUser();            } } 

 
輸出:  

Proved............. this is addUser() method! NO Proved............. 

 
從上面這個例子可以成功攔截了調用的方法addUser()并對其做了相應的處理  
 

2, 通過cglib創建代理類

好處是不要求我們的目標對象實現接口 
原始類 

public class ClientBean {   private String name = null;    public ClientBean()   {    }    public ClientBean(String name)   {     this.name = name;   }    public void addClient()   {     System.out.println("this is addClient() method!");   }    public void deleteClient()   {     System.out.println("this is deleteClient() method!");   }    public void getClient()   {     System.out.println("this is getClient() method!");   }    public void updateClient()   {     System.out.println("this is updateClient() method!");   }    public String getClientName()   {     return name;   }    public void setClientName(String name)   {     this.name = name;   } } 

代理類 

import java.lang.reflect.Method;  import com.cignacmc.finance.bean.ClientBean;  import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;  public class CGLibProxy implements MethodInterceptor {   private Object targetObject;      public Object createProxyObject(Object targetObject)   {     this.targetObject = targetObject;     Enhancer enhancer = new Enhancer();     enhancer.setSuperclass(this.targetObject.getClass());     enhancer.setCallback(this);     return enhancer.create();   }      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable   {     ClientBean clientBean = (ClientBean)targetObject;     String userName = clientBean.getClientName();     Object result = null;          if(userName != null && !"".equals(userName))     {       result = method.invoke(targetObject, args);     }     return result;   } } 

測試類  

import java.lang.reflect.Proxy;  import com.cignacmc.finance.bean.ClientBean; import com.cignacmc.finance.bean.UserBean; import com.cignacmc.finance.bean.UserBeanImpl; import com.cignacmc.finance.proxy.CGLibProxy; import com.cignacmc.finance.proxy.UserBeanProxy;  public class ProxyExe {   public static void main(String[] args)   {       System.out.println(".............CGLIB Proxy....................");     System.out.println("Proved....................");     CGLibProxy cproxy = new CGLibProxy();     ClientBean clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean("Bob Liang"));     clientBean.addClient();          System.out.println("NO Proved....................");     cproxy = new CGLibProxy();     clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean());     clientBean.addClient();            } } 

 
輸出: 

.............CGLIB Proxy.................... Proved.................... this is addClient() method! NO Proved.................... 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阜平县| 利川市| 赤壁市| 谢通门县| 永修县| 六安市| 定日县| 七台河市| 德钦县| 城市| 岳普湖县| 繁峙县| 西青区| 彩票| 中牟县| 汤阴县| 金湖县| 嵩明县| 虹口区| 澄城县| 舞阳县| 井研县| 深泽县| 苍梧县| 镇坪县| 吉林市| 五家渠市| 宣汉县| 仙游县| 武陟县| 九台市| 威信县| 新和县| 渝北区| 桂阳县| 青铜峡市| 滨海县| 盘山县| 永顺县| 敦化市| 望城县|