欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)AOP面向切面編程的實例教程

 更新時間:2016年04月27日 18:36:22   作者:elviskang  
這篇文章主要介紹了Java實現(xiàn)AOP面向切面編程的實例教程,通常Java中的AOP都是利用Spring框架中造好的輪子來開發(fā),而本文則關(guān)注于Java本身AOP的設(shè)計模式實現(xiàn),需要的朋友可以參考下

介紹

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

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

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

該接口實現(xiàn)類的代碼如下:

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

假設(shè)我們既不能修該上面的代碼,也不能對核心庫進行任何改動,怎樣才能完美地實現(xiàn)校驗功能呢?不如試下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實現(xiàn)的校驗功能的效果如何。

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);
  }

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

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

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

兩種實現(xiàn)AOP的方式: 

1,JDK提供的動態(tài)代理實現(xiàn)  
接口 

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

原始實現(xiàn)類 

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; 
     
    //權(quán)限判斷 
    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............. 

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

2, 通過cglib創(chuàng)建代理類

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

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.................... 

相關(guān)文章

  • Springboot手動連接庫并獲取指定表結(jié)構(gòu)的示例代碼

    Springboot手動連接庫并獲取指定表結(jié)構(gòu)的示例代碼

    這篇文章主要介紹了Springboot手動連接庫并獲取指定表結(jié)構(gòu)的示例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • java?Map.Entry的使用示例

    java?Map.Entry的使用示例

    Map.Entry是Java中Map接口的嵌套接口,它提供了獲取鍵和值的方法及遍歷和操作Map的鍵值對,本文就來詳細的介紹一下,感興趣的可以了解一下
    2024-11-11
  • Java中equals和==的區(qū)別詳解

    Java中equals和==的區(qū)別詳解

    這篇文章主要介紹了詳解 Java 中 equals 和 == 的區(qū)別的相關(guān)資料,equals 和 == 都是用來檢測兩個字符串是否相等,返回值也都是布爾型,但是兩者在內(nèi)部比較的處理中卻不盡相同需要的朋友可以參考下
    2021-09-09
  • Spring Cache和EhCache實現(xiàn)緩存管理方式

    Spring Cache和EhCache實現(xiàn)緩存管理方式

    這篇文章主要介紹了Spring Cache和EhCache實現(xiàn)緩存管理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • java使用smslib連接短信貓發(fā)送短信代碼分享

    java使用smslib連接短信貓發(fā)送短信代碼分享

    這篇文章主要介紹了java使用smslib連接短信貓發(fā)關(guān)短信代碼,需要的朋友可以參考下
    2014-02-02
  • Springboot打成war包并在tomcat中運行的部署方法

    Springboot打成war包并在tomcat中運行的部署方法

    這篇文章主要介紹了Springboot打成war包并在tomcat中運行,在文中還給大家介紹了SpringBoot war包tomcat運行啟動報錯(Cannot determine embedded database driver class for database type NONE)的解決方法,需要的朋友可以參考下
    2018-01-01
  • java線程間通信的通俗解釋及代碼示例

    java線程間通信的通俗解釋及代碼示例

    這篇文章主要介紹了java線程間通信的通俗解釋,介紹了線程通信中的幾個相關(guān)概念,然后分享了線程通信的實現(xiàn)方式及代碼示例,具有一定參考價值 ,需要的朋友可以了解下。
    2017-11-11
  • 解決mybatis plus報錯Invalid bound statement (not found):問題

    解決mybatis plus報錯Invalid bound statement 

    在使用MyBatis時遇到InvalidBoundStatement異常,常因多個MapperScan配置沖突或者包掃描路徑設(shè)置錯誤,解決方法包括保留一個MapperScan聲明、檢查jar包沖突、確保命名空間和掃描路徑正確,使用@TableId注解指定主鍵
    2024-11-11
  • MyBatis-Plus不使用數(shù)據(jù)庫默認值的問題及解決

    MyBatis-Plus不使用數(shù)據(jù)庫默認值的問題及解決

    這篇文章主要介紹了MyBatis-Plus不使用數(shù)據(jù)庫默認值的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Eclipse 使用Maven構(gòu)建SpringMVC項目

    Eclipse 使用Maven構(gòu)建SpringMVC項目

    本文主要介紹在Eclipse下創(chuàng)建Maven項目構(gòu)建SpringMVC框架的過程,講解的比較詳細,需要的朋友可以參考下。
    2016-06-06

最新評論