深入淺出講解Spring框架中AOP及動態(tài)代理的應用
一. Spring AOP
面向切面編程(Aspect Oriented Programming,AOP)是軟件編程思想發(fā)展到一定階段的產物,是對面向對象編程(Object Oriented Programming,OOP)的有益補充, 目前已成為一種比較成熟的編程方式。AOP適用于具有橫向邏輯的場所,如訪問控制、事務管理、性能監(jiān)測等。
1. 傳統(tǒng)問題:
在傳統(tǒng)的業(yè)務處理代碼中,通常都會進行事務處理、日志記錄等操作。雖然OOP可以通過組合或者繼承的方式來達到代碼的重用,但是比如實現(xiàn)日志記錄時,代碼還是會分散到不同的方法中。這樣就會存在一個問題,如果想要關閉某個功能或者修改時,就必須要修改所有的相關方法。這不單單增加了開發(fā)人員的工作量,而且提高了代碼的出錯率。
2. 問題的解決策略:
為了解決這個問題,AOP思想隨之產生。AOP采取橫向抽取機制,將分散在各個方法中的重復代碼提取出來,然后在程序編譯或運行時,再將這些提取出來的代碼應用到需要執(zhí)行的地方。這種采用橫向抽取機制的方式,是傳統(tǒng)的OOP思想無法辦到的,因為OOP只能實現(xiàn)父子關系的縱向的重用。雖然AOP是一種新的編程思想,卻不是OOP的替代品,它只是OOP的延申和補充。
3. AOP優(yōu)點:
AOP的使用讓開發(fā)人員在編寫業(yè)務邏輯時可以專心于核心業(yè)務,而不用過多地關注于其他業(yè)務邏輯的實現(xiàn),這不但提高了開發(fā)效率,而且增強了代碼的可維護性。
在AOP思想中,類于切面的關系如下圖所示。我們可以看出,通過Aspect(切面)分別在Class1和Class2的方法中加入了事務、日志、權限和異常等功能。
二. 動態(tài)代理
通過學習我們知道了AOP中的代理就是由AOP框架動態(tài)生成的一個對象,該對象可以作為目標對象使用,對于面向切面編程,簡單地說,就是在不改變原程序的基礎上為代碼段增加新的功能,對代碼段進行增強處理。它的設計思想來源于代理設計模式,通常情況下調用對象的方法如下圖。
在代理模式中可以為該對象設置一個代理對象,代理對象為function()提供一個代理方法,當通過代理對象的function()方法調用原對象的function()方法時,就可以在代理方法中添加新的功能,即增強處理。增強的功能既可以插到原對象的function()前面,也可以插到其后面(如虛線)
1. JDK動態(tài)代理
JDK動態(tài)代理是通過java.lang.reflect.Proxy類來實現(xiàn)的,可以調用Proxy類的newProxyInstance()方法來創(chuàng)建代理對象。對于使用業(yè)務接口的類,Spring框架會默認使用JDK動態(tài)代理來實現(xiàn)AOP。通過一個案例來演示。
1. UserDao.java
package dao; public interface UserDao { public void addUserDao(); public void deleteUser(); }
2. UserDaoImpl.java
package dao; public class UserDaoImpl implements UserDao{ @Override public void addUserDao() { System.out.println("添加用戶"); } @Override public void deleteUser() { System.out.println("刪除用戶"); } }
3. MyAspect.java
package aspect; public class MyAspect { public void check_permission(){ System.out.println("----模擬檢查訪問----"); } public void log(){ System.out.println("----模擬記錄日記----"); } }
4. JdkProxy.java
package jdk; import aspect.MyAspect; import dao.UserDao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Jdk代理類 */ public class JdkProxy implements InvocationHandler { //聲明目標類接口 private UserDao userdao; // 創(chuàng)建代理方法 public Object createProxy(UserDao userdao){ this.userdao=userdao; //類加載器 ClassLoader classLoader=JdkProxy.class.getClassLoader(); //被代理對象實現(xiàn)的所有接口 Class[] clazz=userdao.getClass().getInterfaces(); //使用代理類進行增強,返回的是代理后的對象 return Proxy.newProxyInstance(classLoader,clazz,this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //聲明切面 MyAspect myAspect=new MyAspect(); //前增強 myAspect.check_permission(); //在目標上調用方法,并傳入?yún)?shù) Object obj=method.invoke(userdao,args); //后增強 myAspect.log(); return obj; } }
5. Test.java
@Test public void shouldAnswerWithTrue() { JdkProxy jdkProxy=new JdkProxy(); UserDao userDao=new UserDaoImpl(); UserDao userDao1=(UserDao) jdkProxy.createProxy(userDao); userDao1.addUserDao(); System.out.println("\n-----------------------------分割線------------------------------------\n"); userDao1.deleteUser(); }
結果:
2. CGLIB代理
JDK 動態(tài)代理的使用非常簡單,但它具有一定的局限性(使用動態(tài)代理的對象必須實現(xiàn)一個或多個接口)如果要對沒有實現(xiàn)接口的類進行代理,那么可以使用CGLIB代理。
CGLIB(Code Generation Library)是一個高性能開源的代碼生成包,它采用非常底層的字節(jié)碼技術,對指定的目標類生成一個子類,并對子類進行增強。在Spring框架的核心包中已經集成了CGLIB所需要的包,所以開發(fā)中不需要另外導入jar包。
1. BookDao.java
package dao; public class BookDao { public void addBook(){ System.out.println("添加書本"); } public void deleteBook(){ System.out.println("刪除書本"); } }
2. CglibProxy.java
package jdk; import aspect.MyAspect; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxy implements MethodInterceptor { //代理方法 public Object createProxy(Object target){ Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { MyAspect myAspect=new MyAspect(); myAspect.check_permission(); Object o1=methodProxy.invokeSuper(proxy,args); myAspect.log(); return o1; } }
結果:
到此這篇關于深入淺出講解Spring框架中AOP及動態(tài)代理的應用的文章就介紹到這了,更多相關Spring AOP及動態(tài)代理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于SpringBoot集成Lettuce連接Redis的方法和案例
這篇文章主要介紹了關于SpringBoot集成Lettuce連接Redis的方法和案例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04詳解Java中Checked Exception與Runtime Exception 的區(qū)別
這篇文章主要介紹了詳解Java中Checked Exception與Runtime Exception 的區(qū)別的相關資料,這里提供實例幫助大家學習理解這部分內容,需要的朋友可以參考下2017-08-08Spring注解驅動之BeanFactoryPostProcessor原理解析
這篇文章主要介紹了Spring注解驅動之BeanFactoryPostProcessor原理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09