1. 程式人生 > >Java實現AOP面向切面程式設計的例項教程

Java實現AOP面向切面程式設計的例項教程

介紹

眾所周知,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.................... 

相關推薦

Java實現AOP面向切面程式設計例項教程

介紹 眾所周知,AOP(面向切面程式設計)是Spring框架的特色功能之一。通過設定橫切關注點(cross cutting concerns),AOP提供了極高的擴充套件性。那AOP在Spring中是怎樣運作的呢?當你只能使用core java,卻需要AOP技術時,這個問題的解答變得極為關鍵。不僅如此,

Spring之註解實現aop(面向切面程式設計)

1:Aop(aspect object programming)面向切面程式設計,名詞解釋:     1.1:功能:讓關注點程式碼與業務邏輯程式碼分離     1.2:關注點       

Java框架之Spring AOP 面向切面程式設計 有哪幾種實現方式?如何選擇適合的AOP實現方式?

文章目錄 1. 實現方式 2. JDK動態代理如何實現? 2.1 主要的實現過程 3. 如何選擇? 1. 實現方式 JDK 動態代理實現和 cglib 實現 2. JDK

結合Java例項程式碼來理解 AOP--面向切面程式設計 中的各個術語

因為這個AOP--面向切面程式設計是基於動態代理模式的,所以,要想搞清楚這個AOP,就必須得先了解下,什麼是代理模式,什麼又是動態代理模式。動態代理模式的2種實現方式。現在假設,你已經可以看得懂動態代

Java面試之面向切面程式設計AOP的原理,

            最近在面試,所以複習了一些Java概念方面的內容,AOP--有段話我感覺說的很清楚了:這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式

AspectJ教程--AOP面向切面程式設計框架(Android)

AOP的概念很久前就接觸過了,不過沒有真正寫過專案,甚至Demo都沒有,今天把這點缺陷補上。 推薦兩篇文章(本文部分圖片引自這兩篇文章): 1. 【翻譯】Android中的AOP程式設計 2. 【深入理解Android之AOP】

基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖

![](https://img2020.cnblogs.com/other/1815316/202007/1815316-20200708094430273-1467040799.png) **基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖** **基於SpringBoot AOP面

3.AOP面向切面程式設計

1. 首先我要控制事務,要想控制事務就得使用一個connection 所以只能提取出來connection 所以注重物件的注入 這個重點就是怎麼注入的問題? 重點:加強聯絡 IOC 2. 1.怎麼踢掉重複程式碼? 2.動態代理!AOP 作用就是在

Spring Boot實戰系列(3)AOP面向切面程式設計

AOP是一種與語言無關的程式思想、程式設計正規化。專案業務邏輯中,將通用的模組以水平切割的方式進行分離統一處理,常用於日誌、許可權控制、異常處理等業務中。 快速導航 引入AOP依賴 AOP常用註解解析 實現日誌分割功能 @Pointcut 新增切入點 @Be

第二天 : AOP 面向切面程式設計 、 JdbcTemplete 工具類使用

AOP 面向切面程式設計 、 JdbcTemplete 工具類使用 目錄 一、 什麼是 AOP ***** 二、 AOP 的底層實現 1、 JDK動態代理 2、 使用CGlib 完成動態代理 三、 Spring AOP 1、 傳統Spring AOP 提供

Spring(2)之 (AOP 面向切面程式設計)(AOP目錄)

Spring Core: Spring的核心功能即IOC容器,解決物件的建立及物件之間的依賴關係 Spring WEB: Spring對WEB模組的支援 Spring AOP: 面向切面程式設計 AOP的概述 AOP的底層實現 Spring AOP開發

從原始碼入手,一文帶你讀懂Spring AOP面向切面程式設計

基於這兩者的實現上,這次來探索下Spring的AOP原理。雖然AOP是基於Spring容器和動態代理,但不瞭解這兩者原理也絲毫不影響理解AOP的原理實現,因為大家起碼都會用。 AOP,Aspect Oriented Programming,面向切面程式設計。在很多

瞭解AOP(面向切面程式設計)與OOP(面向物件程式設計

AOP,他是一種思想,是OOP的延展。 1, 說OOP就來說下之前的OPP,最早開始的程式,一個函式(方法)或者說是功能做一個事情,這種思想劃分的是一個功能一個功能的來組合解決問題。 後來人們發現,功能解決問題是解決了,但是功能太多了,人腦實在是有限,

spring aop(面向切面程式設計)

aop分為兩種,一種是靜態代理(不常用),另一種是動態代理  。 靜態代理的優點,及缺點: 優點:代理是客戶端不需要知道實現類是什麼,怎麼做的,客戶只需要知道代理就可以了。缺點:代理類和委託類都實現了相同的介面,代理類通過委託類實現了相同的方法,這樣就出現了大量的程式碼重

Spring AOP面向切面程式設計:理解篇(一看就明白)

一、到底什麼是AOP(面向切面程式設計)? 無論在學習或者面試的時候,大家都會張口說spring的特性AOP和IOC(控制反轉咱們下一篇講),有些大神理解的很到位,但是對於大多數初中級工程師來講還是模糊階段,但是為什麼會有AOP這種技術呢?傻瓜都知道:為了開發者的方便!

Spring詳解篇之 AOP面向切面程式設計

Aop(aspect oriented programming面向切面程式設計),是spring框架的另一個特徵。AOP包括切面、連線點、通知(advice)、切入點(pointCut) 。 1.aop幾個概念: 橫切關注點: 對哪些方面進行攔截,攔截後怎麼處理。 切面

AOP面向切面程式設計的應用

前兩年看書的時候,瞭解到了面向切面程式設計方法(AOP)。對這個技術印象最深刻的特點就是可以實現業務邏輯和許可權、異常處理等的分離。正好在做專案的時候,有些場景可以借鑑這個思想,於是在專案中借用開源的.net環境的KingAOP實現了選單按鈕許可權控制、上下游

Spring Boot之AOP面向切面程式設計-實戰篇

目錄 前言 程式設計正規化主要有以下幾類 引入pom依賴 aop註解 實現日誌分割功能 前言 AOP是一種與語言無關的程式思想、程式設計正規化。專案業務邏輯中,將通用的模組以水平切割的方式進行分離統一處理,常用於日誌、許可權控制、異常處理等業務中。 程式設計正規化主

Spring AOP面向切面程式設計之日誌記錄

實際專案中我們往往需要將一些重要的操作,以日誌的形式進行儲存,當機器宕機的時候,可以通過查詢日誌,定位出錯位置,方便恢復。 1:首先匯入spring支援的AOP架包 2:編寫將要進行切面工作的類 /** * */ package com.zhiyou100.aspect; i

Spring AOP面向切面程式設計詳解(基於XML方式 註解方式 注入Aspectj方式)

前言 AOP即面向切面程式設計,是一種程式設計思想,OOP的延續。在程式開發中主要用來解決一些系統層面上的問題,比如日誌,事務,許可權等等。在閱讀本文前希望您已經對Spring有一定的瞭解 注:在能對程式碼進行添加註解方式實現AOP的話,並不推薦使用XML方