日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring AOP知识点简介

發布時間:2023/12/3 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring AOP知识点简介 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 1、什么是AOP
    • 1.1、AOP術語
    • 1.2、AOP框架
  • 2、動態代理
    • 2.1、JDK動態代理
    • 2.2、CGLIB動態代理
  • 3、基于代理類的AOP實現
    • 3.1、Spring的通知類型
    • 3.2、ProxyFactoryBean
  • 4、AspectJ開發
    • 4.1、基于XML的聲明式AspectJ
    • 4.2、基于注解的聲明式AspectJ

1、什么是AOP

面向切面編程(Aspect Oriented Programming)提供了另一種角度來思考程序的結構,通過這種方式彌補面向對象編程(Object Oriented Programming)的不足。除了類以外,AOP提供了切面,切面對關注點進行模塊化,例如橫切多個類型和對象的事務管理(這些關注點術語通常稱作橫切(crosscutting)關注點)。Spring AOP是Spring的一個重要組件,但是Spring IOC并不依賴于Spring AOP,這意味著你可以自由選擇是否使用AOP,AOP提供了強大的中間件解決方案,這使得Spring IOC更加完善。我們可以通過AOP來實現日志監聽,事務管理,權限控制等等。

1.1、AOP術語

  • 切面(Aspect):一個關注點的模塊化,這個關注點可能會橫切多個對象。事務管理是Java應用程序中一個關于橫切關注點的很好的例子。在Spring AOP中,切面可以使用通過類(基于模式(XML)的風格)或者在普通類中以@Aspect注解(AspectJ風格)來實現。
  • 連接點(Join point):程序執行過程中某個特定的點,比如某方法調用的時候或者處理異常的時候。在Spring AOP中一個連接點總是代表一個方法的執行。個人理解:AOP攔截到的方法就是一個連接點。通過聲明一個org.aspectj.lang.JoinPoint類型參數我們可以在通知(Advice)中獲得連接點的信息。這個在稍后會給出案例。
  • 通知(Advice):在切面(Aspect)的某個特定連接點上(Join point)執行的動作。通知的類型包括"around",“before”,"after"等等。通知的類型將在后面進行討論。許多AOP框架,包括Spring 都是以攔截器作為通知的模型,并維護一個以連接點為中心的攔截器鏈。總之就是AOP對連接點的處理通過通知來執行。個人理解:Advice指當一個方法被AOP攔截到的時候要執行的代碼。
  • 切入點(Pointcut):匹配連接點(Join point)的斷言。通知(Advice)跟切入點表達式關聯,并在與切入點匹配的任何連接點上面運行。切入點表達式如何跟連接點匹配是AOP的核心,Spring默認使用AspectJ作為切入點語法。個人理解:通過切入點的表達式來確定哪些方法要被AOP攔截,之后這些被攔截的方法會執行相對應的Advice代碼。
  • 引入(Introduction):聲明額外的方法或字段。Spring AOP允許你向任何被通知(Advice)對象引入一個新的接口(及其實現類)。個人理解:AOP允許在運行時動態的向代理對象實現新的接口來完成一些額外的功能并且不影響現有對象的功能。
  • 目標對象(Target object):被一個或多個切面(Aspect)所通知(Advice)的對象,也稱作被通知對象。由于Spring AOP是通過運行時代理實現的,所以這個對象永遠是被代理對象。個人理解:所有的對象在AOP中都會生成一個代理類,AOP整個過程都是針對代理類在進行處理。
  • AOP代理(AOP proxy):AOP框架創建的對象,用來實現切面契約(aspect contract)(包括通知方法執行等功能),在Spring中AOP可以是JDK動態代理或者是CGLIB代理。
  • 織入(Weaving):把切面(aspect)連接到其他的應用程序類型或者對象上,并創建一個被通知對象。這些可以在編譯時(例如使用AspectJ編譯器),類加載時和運行時完成。Spring和其他純AOP框架一樣,在運行時完成織入。個人理解:把切面跟對象關聯并創建該對象的代理對象的過程。

1.2、AOP框架

  • Spring AOP:Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期間通過代理方式向目標類織入增強的代碼。
  • AspectJ:AspectJ是一個基于Java的AOP框架,從Spring2.0開始,SpringAOP引入了對AspectJ的支持,AspectJ擴展了Java語言,提供了一個專門的編輯器,在編譯時提供橫向代碼的織入。

2、動態代理

Spring中的AOP代理,可以是JDK動態代理,也可以是CGLIB代理。

2.1、JDK動態代理

JDK動態代理是通過java.lang.reflect.Proxy類來實現的,我們可以調用Proxy類的newProxyInstance()方法來創建代理對象。對于使用業務接口的類,Spring默認會使用JDK動態代理來實現AOP。

接下來通過一個案例演示Spring中的JDK動態代理

1.創建Java工程,導入Spring框架需要的JAR包并發布到類路徑下,如下圖所示:

2.創建接口,并編寫添加和刪除方法

package com.nynu.qdy.jdk;public interface UserDao {public void addUser();public void deleteUser(); }

3.創建接口實現類,實現接口中的方法,并在方法中輸出一條語句

package com.nynu.qdy.jdk;//目標類 public class UserDaoImpl implements UserDao {public void addUser() {System.out.println("添加用戶");}public void deleteUser() {System.out.println("刪除用戶");} }

4.創建切面類MyAspect,并在該類中定義模擬權限檢查和日志記錄的方法。這兩個方法表示切面中的通知

package com.nynu.qdy.aspect;//切面類:可以存在多個通知Advice(即增強的方法) public class MyAspect {public void check_Permissions() {System.out.println("模擬檢查權限.....");}public void log() {System.out.println("模擬記錄日志....");} }

5.創建代理類,該類需要實現InvocationHandller接口,并編寫代理方法。在代理方法中,需要通過Proxy類實現動態代理

package com.nynu.qdy.jdk;import com.nynu.qdy.aspect.MyAspect;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;/*** JDK代理類*/ public class JdkProxy implements InvocationHandler {// 聲明目標接口private UserDao userDao;// 創建代理方法@SuppressWarnings("rawtypes")public Object createProxy(UserDao userDao) {this.userDao = userDao;// 1.類加載器ClassLoader classLoader = JdkProxy.class.getClassLoader();// 2.被代理對象實現的所有接口Class[] clazz = userDao.getClass().getInterfaces();// 3.使用代理類,進行增強,返回的是代理后的對象return Proxy.newProxyInstance(classLoader, clazz, this);}/*** 所有動態類的方法調用,都會交有invoke()方法來處理 * proxy : 被代理后的對象 * method : 將要被執行的方法信息(反射)* args : 執行方法時需要的參數*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 聲明切面MyAspect myAspect = new MyAspect();// 前增強myAspect.check_Permissions();// 在目標類上調用方法,并傳入參數Object obj = method.invoke(userDao, args);// 后增強myAspect.log();return obj;} }

jdkProxy類實現了InvocationHandler接口,并實現了接口中的invoke方法, 所有動態代理類所調用的方法都會交由該方法處理。在創建的代理方法createProxy()中,使用了Proxy類的newProxyInstance()方法來創建代理對象。newProxyInstance()方法中包含3個參數,其中第一個參數是當前類的類加載器,第2個參數表示的是被代理對象實現的所有接口,第3個參數this代表的就是代理類jdkProxy本身。在invoke()方法中,目標類方法執行的前后分別執行切面類中的check_Permissions()方法和log()方法。

6.測試類

  • 創建代理對象和目標對象
  • 從代理對象中獲得對目標對象userDao增強后的對象
  • 最后調用該對象中的添加和刪除方法
  • package com.nynu.qdy.jdk;public class jdkTest {public static void main(String[] args) {// 創建代理對象JdkProxy jdkProxy = new JdkProxy();// 創建目標對象UserDao userDao = new UserDaoImpl();// 從代理對象中獲取增強后的目標對象UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);// 執行方法userDao1.addUser();userDao1.deleteUser();} }

    7.結果

    模擬檢查權限..... 添加用戶 模擬記錄日志.... 模擬檢查權限..... 刪除用戶 模擬記錄日志....

    從結果可以看出,userDao實例中的添加用戶和刪除用戶的方法已被成功調用,并且在調用前后分別增加了權限檢查和記錄日志的功能。這種實現了接口的動態代理方式,就是Spring中的JDK動態代理。

    2.2、CGLIB動態代理

    JDK動態代理的使用非常簡單,但它還有一定的局限性一使 用動態代理的對象必須實現一個或多個接口。如果要對沒有實現接只的類進行代理,那么可以使用CGLIB代理。

    CGLIB ( Code Generation Library )是一個高性能開源的代碼生成包,它采用非常底層的字 節碼技術,對指定的目標類生成一個子類, 并對子類進行增強。在Spring的核心包中已經集成了CGLIB所需要的包,所以開發中不需要另外導入JAR包。

    下面通過一個案例來演示CGLIB動態代理的實現過程

    1.創建目標類,目標類不需要實現任何接口,只需定義所需要的方法

    package com.nynu.qdy.cglib;//目標類 public class UserDao {public void addUser() {System.out.println("添加用戶");}public void deleteUser() {System.out.println("刪除用戶");}}

    2.創建代理類,該代理類需要實現MethodInterceptor接口,并實現接口中的intercept()方法

    package com.nynu.qdy.cglib;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import com.nynu.qdy.aspect.MyAspect;//代理類 public class CglibProxy implements MethodInterceptor {// 代理方法public Object createProxy(Object target) {// 創建一個動態對象Enhancer enhancer = new Enhancer();// 確定需要增強的父類,設置其父類enhancer.setSuperclass(target.getClass());// 添加回調函數enhancer.setCallback(this);// 返回創建的代理類return enhancer.create();}/*** proxy CGlib根據指定父類生成代理對象 method 攔截的方法 args 攔截的參數數組 methodProxy* 方法的代理對象,用于執行父類的方法*/public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {// 創建切面類對象MyAspect myAspect = new MyAspect();// 前增強myAspect.check_Permissions();// 目標方法執行Object obj = methodProxy.invokeSuper(proxy, args);// 后增強myAspect.log();return obj;}}

    在該代理方法中,首先創建了一個動態類對象Enhancer,它是CGLIB的核心類;然后調用了Enhancer類的setSuperclass()方法來確定目標對象;加下例調用了setCalllback()方法添加回調函數,其中的this代表的就是代理類CglibProxy本身;最后通過return語句將創建的代理類對象返回。intercept()方法會在程序執行目標方法時被調用,方法運行時將會執行切面類中的增強方法。

    3.測試
    創建測試類CglibTest,在該類的main方法中首先創建代理對象和目標對象,然后從代理對象中獲得增強后的目標對象,最后調用對象中的添加和刪除方法。

    package com.nynu.qdy.cglib;public class CglibTest {public static void main(String[] args) {// 創建代理對象CglibProxy cglibProxy = new CglibProxy();// 創建目標對象UserDao userDao = new UserDao();// 獲取增強后的對象UserDao userDao1 = (UserDao) cglibProxy.createProxy(userDao);// 執行方法userDao1.addUser();userDao1.deleteUser();} }

    4.結果

    模擬檢查權限..... 添加用戶 模擬記錄日志.... 模擬檢查權限..... 刪除用戶 模擬記錄日志....

    從結果可以看出,目標類UserDao中的方法被成功調用并增強了。這種沒有實現接口的代理方式,就是CGLIB代理。

    3、基于代理類的AOP實現

    Spring中的AOP代理默認就是使用JDK動態代理的方式實現的。在Spring中,使用ProxyFactoryBean是創建AOP代理的最基本方式。

    3.1、Spring的通知類型

    Spring中的通知按在目標類方法的連接點位置,可以分為以下5種類型:

    • org.allane.intercept.Methodinterceptor (環繞通知)
      在目標方法執行前后實施增強,可以應用于日志、事務管理等功能。
    • org.springframework.aop.MethodBeforeAdvice (前置通知)
      在目標方法執行前實施增強,可以應用于權限管理等功能。
    • org.springframework aop .AfterReturningAdvice (后置通知)
      在目標方法執行后實施增強,可以應用于關閉流、上傳文件、刪除臨時文件等功能。
    • org.springframework.aop.ThrowsAdvice (異常通知)
      在方法拋出異常后實施增強,可以應用于處理異常記錄日志等功能。
    • org.springtramework.aop.IntroductionInterceptor (引介通知)
      在目標類中添加一些新的方法和屬性,可以應用于修改老版本程序(增強類)。

    3.2、ProxyFactoryBean

    ProxyFactoryBean是FactoryBean接口的實現類,FactoryBean負責實例化一個Bean,而ProxyFactoryBean負責為其他Bean創建代理實例。ProxyFactoryBean類中的常用配置屬性如下邊所示:

    屬性名稱描述
    target代理的目標對象
    proxyInterfaces代理要實現的接口,如果是多個接口,可以使用以下格式賦值
    proxyTargetClass是否對類代理而不是接口,設置為true時,使用CGLIB代理
    interceptornames需要織入目標的Advice
    singleton返回的代理是否為單實例,默認為true(即返回單實例)
    optimize當設置為trues時,強制使用CGLIB

    對ProxyFactoryBean類有了初步的了解后,接下來通過一個典型的環繞通知案例,來演示Spring使用ProxyFactroyBean創建AOP代理

    1.創建Java工程,導入Spring框架需要的JAR包并發布到類路徑下,如下圖所示:

    2.創建切面類,實現MethodInterceptor接口,并實現接口中的invoke()方法,來執行目標方法

    package com.nynu.qdy.factorybean;import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;//切面類 public class MyAspect implements MethodInterceptor {public Object invoke(MethodInvocation mi) throws Throwable {check_Permissions();// 執行目標方法Object obj = mi.proceed();log();return obj;}public void check_Permissions() {System.out.println("模擬檢查權限...");}public void log() {System.out.println("模擬記錄日志...");}}

    為了演示效果,在目標方法前后分別執行了檢查權限和記錄日志的方法,這兩個方法也就是增強的方法,也就是通知
    3.創建配置文件,并指定代理對象

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsd"><!-- 1 目標類 --><bean id="userDao" class="com.nynu.qdy.jdk.UserDaoImpl" /><!-- 2 切面類 --><bean id="myAspect" class="com.nynu.qdy.factorybean.MyAspect" /><!-- 3 使用Spring代理工廠定義一個名稱為userDaoProxy的代理對象 --><bean id="userDaoProxy"class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 3.1 指代理實現的接口 --><property name="proxyInterfaces"value="com.nynu.qdy.jdk.UserDao" /><!-- 3.2 指定目標對象 --><property name="target" ref="userDao" /><!-- 3.3 指定切面,植入環繞通知 --><property name="interceptorNames" value="myAspect" /><!-- 3.4 指定代理方式,true:使用cglib,false(默認):使用jdk動態代理 --><property name="proxyTargetClass" value="true" /></bean> </beans>

    通過< bean >元素定義了目標類和切面,然后使用ProxyFactoryBean類定義了代理對象。在定義的代理對象中,分別通過< property >子元素指定了代理實現的接口、代理的目標對象、需要織入目標類的通知以及代理方式。

    4.創建測試類

    package com.nynu.qdy.factorybean;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.nynu.qdy.jdk.UserDao;public class ProxyFactoryBeanTest { //測試類@SuppressWarnings("resource")public static void main(String[] args) {/** String xmlPath = "com/nynu/qdy/factorybean/applicationContext.xml";* * @SuppressWarnings("resource") ApplicationContext applicationContext = new* ClassPathXmlApplicationContext(xmlPath);*/ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 從spring容器中獲得內容UserDao userDao = (UserDao) applicationContext.getBean("userDaoProxy");// 執行方法userDao.addUser();userDao.deleteUser();} }

    5.結果

    模擬檢查權限... 添加用戶 模擬記錄日志... 模擬檢查權限... 刪除用戶 模擬記錄日志...

    4、AspectJ開發

    AspectJ是一個基于Java語言的AOP框架,它提供了強大的AOP功能。

    使用AspectJ實現AOP的方式:

    • 基于XML的聲明式AspectJ
    • 基于注解的聲明式AspectJ

    4.1、基于XML的聲明式AspectJ

    基于XML的聲明式AspectJ是指通過XML文件來定義切面、切入點以及通知,所有的切面、切入點和通知都必須定義在< aop:config >元素內。

    1. 配置切面

    在Spring的配置文件中,配置切面使用的是<aop:aspect >元素,該元素會將一個已定 義好的Spring Bean轉換成切面Bean,所以要在配置文件中先定義一個普通的Spring Bean (如上述代碼中定義的myAspect)。 定義完成后,通過<aop:aspect >元素的ref 屬性即可引用該Bean。

    配置<aop:aspect >元素時,通常會指定id和ref兩個屬性,如下表所示。

    屬性名稱描述
    id用于定義該切面的唯一標識名稱
    ref用于引用普通的Spring Bean

    2.配置切入點

    在Spring的配置文件中,切入點是通過<aop:pointcut >元素來定義的。當<aop:pointcut >元素作為<aop:config >元素的子元素定義時,表示該切入點是全局切入點,它可被多個切面所共享;當<aop:pointcut >元素作為<aop:aspect >元素的子元素時,表示該切入點只對當前切面有效

    在定義<aop:pointcut >元素時,通常會指定id和expression兩個屬性,如下表所示。

    屬性名稱描述
    id用于指定切入點的唯一標識名稱
    expression用于指定切入點關聯的切入點表達式

    在上述配置代碼片段中,execution(* com.itheima.jdk.. (…))就是定義的切入點表達式,該切入點表達式的意思是匹配com.itheima.jdk包中任意類的任意方法的執行。其中execution()是 表達式的主體,第1個**表示的是返回類型,使用代表所有類型; com.itheima.jdk 表示的是需要攔截的包名,后面第2個表示的是類名,使用代表所有的類;第3個表示的是方法名,使用表示所有方法;后面(…)表示方法的參數,其中的“”表示任意參數。需要注意的是,**第1個與包名之間有-個空格。**

    上面示例中定義的切入點表達式只是開發中常用的配置方式,而Spring AOP中切入點表達式的基本格式如下:

    execution (modi fiers-pattern? ret-type-pattern declaring-type-pattern?
    name -pattern (param-pattern) throws-pattern?)

    上述格式中,各部分說明如下。

    • modifiers- pattern:表示定義的目標方法的訪問修飾符,如public、 private 等。
    • ret-type- pattern:表示定義的目標方法的返回值類型,如void、String 等。
    • delaring-type- pattern: 表示定義的目標方法的類路徑,如com.itheima.jdk.UserDaolmpl. ,
    • name- -pattern: 表示具體需要被代理的目標方法,如add()方法。
    • param- pattern:表示需要被代理的目標方法包含的參數,本章示例中目標方法參數都為空。
    • throws- pattern:表示需要被代理的目標方法拋出的異常類型。

    其中帶有問號(? ) 的部分,如mdifers- patterm、 declaring-type- pattern和throws -pattern表示可配置項;而其他部分屬于必須配置項。

    3.配置通知

    在配置代碼中,分別使用<aop:aspeq >的子元素配置了5種常用通知,這5個子元素不支持使用子元素,但在使用時可以指定一些屬性,如下表所示。

    屬性名稱描述
    pointcut該屬性用于指定-一個切入點表達式, Spring 將在匹配該表達式的連接點時織入該通知
    pointcut-ref該屬性指定一個已經存在的切入點名稱,如配置代碼中的myPointCut。通常pointut和pointcut-ref兩個屬性只需要使用其中之一
    method該屬性指定一個方法名,指定將切面Bean中的該方法轉換為增強處理
    throwing該屬性只對< after-throwing >元素有效, 它用于指定一個形參名,異常通知方法可以通過該形參訪問目標方法所拋出的異常
    returning該屬性只對< after-returning >元素有效, 它用于指定一個形參名,異常通知方法可以通過該形參訪問目標方法的返回值

    了解了如何在XML文件中配置切面、切入點和通知后,接下來通過一個案例來演示如何在Spring中基于XML的聲明式Aspect J

    1.創建切面類,并在類中分別定義不同類型的通知

    package com.nynu.qdy.aspectj.xml;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;public class MyAspect {// 前置通知public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知:模擬執行權限檢查:");System.out.println("目標類是:" + joinPoint.getTarget());System.out.println(",被植入增強的目標方法為: "+ joinPoint.getSignature().getName());}// 后置通知public void myAfterReturning(JoinPoint joinPoint) {System.out.println("后置通知:模擬記錄日志:");System.out.println("被植入增強處理的目標方法為: "+ joinPoint.getSignature().getName());}/*** 環繞通知 ProceedingJoinPoint 是JoinPoint子接口。表示可以執行目標方法 1.必須是Object類型的返回值 2.* 必須接受一個參數,類型為ProceedingJoinPoint 3. 必須throws Throwable* * @throws Throwable*/public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {// 開始System.out.println("環繞開始:執行目標方法之前,模擬開啟事物。。。。");// 執行當前目標方法Object obj = proceedingJoinPoint.proceed();// 結束System.out.println("環繞結束:執行目標方法之后。關閉模擬事物。。。");return obj;}// 異常通知public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("異常通知" + "出錯了" + e.getMessage());}// 最終通知public void myAfter() {System.out.println("最終通知:模擬方法結束后的釋放資源");} }

    在切面類中,分別定義了5種不同類型的通知,在通知中使用了JoinPoint 接口及其子接口ProceedingJoinPoint作為參數來獲得目標對象的類名、目標方法名和目標方法參數等。

    需要注意的是,環繞通知必須接收一個類型為ProceedingJoinPoint的參數,返回值也必須是Object類型,且必須拋出異常。異常通知中可以傳入Throwable類型的參數來輸出異常信息。

    2.創建配置文件,并編寫相關配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 1 目標類 --><bean id="userDao" class="com.nynu.qdy.jdk.UserDaoImpl" /><!-- 2 切面 --><bean id="myAspect" class="com.nynu.qdy.aspectj.xml.MyAspect" /><!-- 3 aop編程 --><aop:config><!-- 切面配置 --><aop:aspect ref="myAspect"><!-- 3.1 配置切入點,通知最后增強哪些方法 --><aop:pointcut expression="execution(* com.nynu.qdy.jdk.*.*(..))"id="myPointCut" /><!-- 3.2 關聯通知Advice和切入點pointCut --><!-- 3.2.1 前置通知 --><aop:before method="myBefore" pointcut-ref="myPointCut" /><aop:after-returning method="myAfterReturning"pointcut-ref="myPointCut" returning="returnVal" /><!-- 3.2.3 環繞通知 --><aop:around method="myAround" pointcut-ref="myPointCut" /><aop:after-throwing method="myAfterThrowing"pointcut-ref="myPointCut" throwing="e" /><aop:after method="myAfter" pointcut-ref="myPointCut" /></aop:aspect></aop:config> </beans>

    3.創建測試類,并在類中對方法進行增強

    package com.nynu.qdy.aspectj.xml;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.nynu.qdy.jdk.UserDao;public class TestXmlAspectj {@SuppressWarnings("resource")public static void main(String[] args) {String xmlPath = "com/nynu/qdy/aspectj/xml/applicationContext.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserDao userDao = (UserDao) applicationContext.getBean("userDao");userDao.addUser();} }

    4.結果

    前置通知:模擬執行權限檢查: 目標類是:com.nynu.qdy.jdk.UserDaoImpl@184cf7cf ,被植入增強的目標方法為: addUser 環繞開始:執行目標方法之前,模擬開啟事物。。。。 添加用戶 最終通知:模擬方法結束后的釋放資源 環繞結束:執行目標方法之后。關閉模擬事物。。。 后置通知:模擬記錄日志: 被植入增強處理的目標方法為: addUser

    4.2、基于注解的聲明式AspectJ

    與基于代理類的AOP實現相比,基于XML的聲明式ApectJ要便捷得多,但是它也存在著一些 缺點,那就是要在Spring文件中配置大量的代碼信息。為了解決這個問題,AspectJ 框架為AOP的實現提供了一套注解,用以取代Spring配置文件中為實現AOP功能所配置的臃腫代碼。

    關于AspectJ注解的介紹,如下表所示:

    注解名稱描述
    @Aspect用于定義一個切面
    @Pointcut用于定義切入點表達式。在使用時還需定義一個包含名字和任意參數的方法簽名來表示切入點 名稱。實際上,這個方法簽名就是一一個返回值為 void,且方法體為空的普通的方法
    @Before用于定義前置通知,相當于BeforeAdvice。在使用時,通常需要指定一一個value屬性值,該屬性值用于指定一個切入點表達式 (可以是已有的切入點,也可以直接定義切入點表達式)
    @AfterReturning用于定義后置通知,相當于AfterReturningAdvice。 在使用時可以指定pointcut/value 和 returning屬性,其中pointcut/value 這兩個屬性的作用一樣,都用于指定切入點表達式。returning屬性值用于表示Advice方法中可定義與此同名的形參,該形參可用于訪問目標方法的返回值
    @Around用于定義環繞通知,相當于MethodInterceptor.在使用時需要指定一個value屬性,該屬性用于指定該通知被植入的切入點
    @After Throwing用于定義異常通知來處理程序中未處理的異常,相當于ThrowAdvice 。在使用時可指定pointcut/value和throwing屬性。其中pointcutvalue用于指定切入點表達式,而throwing屬性值用于指定一個形參名來表示Advice方法中可定義與此同名的形參,該形參可用于訪問目標方法拋出的異常
    @After用于定義最終final通知,不管是否異常,該通知都會執行。使用時需要指定一個 value屬性,該屬性用于指定該通知被植入的切入點
    @DeclareParents用于定義引介通知,相當于IntroductionInterceptor (不要求掌握)

    為了使讀者可以快速地掌握這些注解,接下來重新使用注解的形式來實現上一小節的案例,具體步驟如下

    1.復制上一節切面類,并做相應修改

    package com.nynu.qdy.aspectj.annotation;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;@Aspect @Component public class MyAspect {// 切入點表達式@Pointcut("execution(* com.nynu.qdy.jdk.*.*(..))")// 使用一個返回值為void ,方法體為空的方法來命名切入點private void myPointCut() {}// 前置通知@Before("myPointCut()")public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知:模擬執行權限檢查:");System.out.println("目標類是:" + joinPoint.getTarget());System.out.println(",被植入增強的目標方法為: " + joinPoint.getSignature().getName());}// 后置通知@AfterReturning("myPointCut()")public void myAfterReturning(JoinPoint joinPoint) {System.out.println("后置通知:模擬記錄日志:");System.out.println("被植入增強處理的目標方法為: " + joinPoint.getSignature().getName());}/*** 環繞通知 ProceedingJoinPoint 是JoinPoint子接口。表示可以執行目標方法 1.必須是Object類型的返回值 2.* 必須接受一個參數,類型為ProceedingJoinPoint 3. 必須throws Throwable* * @throws Throwable*/@Around("myPointCut()")public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {// 開始System.out.println("環繞開始:執行目標方法之前,模擬開啟事物。。。。");// 執行當前目標方法Object obj = proceedingJoinPoint.proceed();// 結束System.out.println("環繞結束:執行目標方法之后。關閉模擬事物。。。");return obj;}// 異常通知@AfterThrowing(value = "myPointCut()", throwing = "e")public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("異常通知" + "出錯了" + e.getMessage());}// 最終通知@After("myPointCut()")public void myAfter() {System.out.println("最終通知:模擬方法結束后的釋放資源");} }

    在切面類中,首先使用@Aspect注解定義了切面類,由于該類在Spring中是作為組件使用的,所以還需要添加@Component注解才能生效。然后使用了@Poincut注解來配置切入點表達式,并通過定義方法來表示切入點名稱。接下來在每個通知相應的方法上添加了相應的注解,并將切入點名稱“myPointCut"作為參數傳遞給需要執行增強的通知方法。如果需要其他參數(如異常通知的異常參數),可以根據代碼提示傳遞相應的屬性值。

    2.目標類com.itheima.jdk.UserDaolmpl中,添加注解@Repository(“userDao”)

    package com.nynu.qdy.jdk;import org.springframework.stereotype.Repository;@Repository("userDao") public class UserDaoImpl implements UserDao {public void addUser() {System.out.println("添加用戶");}public void deleteUser() {System.out.println("刪除用戶");}}

    3.創建配置文件applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "><!-- 指定需要掃描的包,使注解生效 --><context:component-scanbase-package="com.nynu.qdy" /><!-- 啟動基于注解的聲明式AspectJ支持 --><aop:aspectj-autoproxy/></beans>

    4.創建測試類

    package com.nynu.qdy.aspectj.annotation;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.nynu.qdy.jdk.UserDao;public class TestAnnotation {@SuppressWarnings("resource")public static void main(String[] args) {String xmlPath = "com/nynu/qdy/aspectj/annotation/applicationContext.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);// 1 從容器中獲得內容UserDao userDao = (UserDao) applicationContext.getBean("userDao");// 2 執行方法userDao.addUser();userDao.deleteUser();} }

    5.結果

    環繞開始:執行目標方法之前,模擬開啟事物。。。。 前置通知:模擬執行權限檢查: 目標類是:com.nynu.qdy.jdk.UserDaoImpl@71809907 ,被植入增強的目標方法為: addUser 添加用戶 環繞結束:執行目標方法之后。關閉模擬事物。。。 最終通知:模擬方法結束后的釋放資源 后置通知:模擬記錄日志: 被植入增強處理的目標方法為: addUser 環繞開始:執行目標方法之前,模擬開啟事物。。。。 前置通知:模擬執行權限檢查: 目標類是:com.nynu.qdy.jdk.UserDaoImpl@71809907 ,被植入增強的目標方法為: deleteUser 刪除用戶 環繞結束:執行目標方法之后。關閉模擬事物。。。 最終通知:模擬方法結束后的釋放資源 后置通知:模擬記錄日志: 被植入增強處理的目標方法為: deleteUser

    如果同一個連接點有多個通知需要執行,那么在同一切面中,目標方法之前的前置通知和環繞通知的執行順序是未知的,目標方法之后的后置通知和環繞通知的執行順序也是位置的。

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Spring AOP知识点简介的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。