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方