您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Spring中的AOP編程怎么應用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Spring中的AOP編程怎么應用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
AOP 為 Aspect Oriented Programming 的縮寫,是面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP 是 OOP 的延續,是軟件開發中的一個熱點,也是 Spring 框架中的一個重要內容,是函數式編程的一種衍生范型
AOP 可以分離業務代碼和關注點代碼(重復代碼),在執行業務代碼時,動態的注入關注點代碼。切面就是關注點代碼形成的類。Spring AOP 中的動態代理主要有兩種方式,JDK 動態代理和 CGLIB 動態代理。JDK 動態代理通過反射來接收被代理的類,并且要求被代理的類必須實現一個接口
AOP 要達到的效果是,保證開發者不修改源代碼的前提下,去為系統中的業務組件添加某種通用功能,按照 AOP 框架修改源代碼的時機,可以將其分為兩類:
靜態 AOP 實現, AOP 框架在編譯階段對程序源代碼進行修改,生成了靜態的 AOP 代理類(生成的 *.class 文件已經被改掉了,需要使用特定的編譯器),比如 AspectJ。
動態 AOP 實現, AOP 框架在運行階段對動態生成代理對象(在內存中以 JDK 動態代理,或 CGlib 動態地生成 AOP 代理類),如 SpringAOP
連接點(JointPoint):與切入點匹配的執行點,在程序整個執行流程中,可以織入切面的位置,方法的執行前后,異常拋出的位置
切點(PointCut):在程序執行流程中,真正織入切面的方法。
切面(ASPECT):切點+通知就是切面
通知(Advice):切面必須要完成的工作,也叫增強。即,它是類中的一個方法,方法中編寫織入的代碼。
前置通知 后置通知
環繞通知 異常通知
最終通知
目標對象(Target):被織入通知的對象
代理對象(Proxy):目標對象被織入通知之后創建的新對象
通知的類型
Spring 方面可以使用下面提到的五種通知工作:
通知 | 描述 |
---|---|
前置通知 | 在一個方法執行之前,執行通知。 |
最終通知 | 在一個方法執行之后,不考慮其結果,執行通知。 |
后置通知 | 在一個方法執行之后,只有在方法成功完成時,才能執行通知。 |
異常通知 | 在一個方法執行之后,只有在方法退出拋出異常時,才能執行通知。 |
環繞通知 | 在一個方法調用之前和之后,執行通知。 |
基于 Aspectj 實現 AOP 操作,經歷了下面三個版本的變化,注解版是我們最常用的。
切入點表達式
作用:聲明對哪個類中的哪個方法進行增強
語法:
execution([訪問權限修飾符] 返回值 [ 類的全路徑名 ] 方法名 (參數列表)[異常])
訪問權限修飾符:
可選項,不寫就是四個權限都包含
寫public就表示只包括公開的方法
返回值類型
必填項 * 標識返回值任意
全限定類名
可選項,兩個點 … 表示當前包以及子包下的所有類,省略表示所有類
方法名
必填項 * 表示所有的方法 set*表示所有的set方法
形參列表
必填項
()表示沒有參數的方法
(…)參數類型和參數個數隨意的方法
(*)只有一個參數的方法
(*,String) 第一個參數類型隨意,第二個參數String類型
異常信息
可選項 省略時標識任何異常信息
使用 Spring AOP 接口方式實現 AOP, 可以通過自定義通知來供 Spring AOP 識別對應實現的接口是:
前置通知:MethodBeforeAdvice
返回通知:AfterReturningAdvice
異常通知:ThrowsAdvice
環繞通知:MethodInterceptor
實現步驟:
1、定義業務接口
/** * 使用接口方式實現AOP, 默認通過JDK的動態代理來實現. 非接口方式, 使用的是cglib實現動態代理 */ package cn.kgc.spring05.entity; public interface Teacher { String teachOnLine(String course); String teachOffLine(Integer course); }
2、定義實現類
package cn.kgc.spring05.entity; public class TeacherA implements Teacher{ @Override public String teachOnLine(String course) { System.out.println("TeacherA開始"+course+"課程線上教學"); if(course.equals("java")){ throw new RuntimeException("入門到放棄!"); } return course+"課程線上教學"; } @Override public String teachOffLine(Integer course) { System.out.println("TeacherA開始"+course+"課程線下教學"); return course+"課程線下教學"; } }
3、實現接口定義通知類
前置通知類
package cn.kgc.spring05.advice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; //前置通知 public class MyMethodBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("------------spring aop 前置通知------------"); } }
后置通知類
package cn.kgc.spring05.advice; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class MyAfterReturnAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("------------spring aop 后置通知------------"); } }
4、XML 配置方式
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--托管通知--> <bean id="after" class="cn.kgc.spring05.advice.MyAfterReturnAdvice"></bean> <bean id="before" class="cn.kgc.spring05.advice.MyMethodBeforeAdvice"></bean> <bean id="teacherA" class="cn.kgc.spring05.entity.TeacherA"></bean> <!--AOP的配置--> <aop:config> <!--切點表達式--> <aop:pointcut id="pt" expression="execution(* *(..))"/> <aop:advisor advice-ref="before" pointcut-ref="pt"></aop:advisor> <aop:advisor advice-ref="after" pointcut-ref="pt"></aop:advisor> </aop:config> </beans>
5、測試
package cn.kgc.spring05; import cn.kgc.spring05.entity.Teacher; import junit.framework.TestCase; import junit.framework.TestSuite; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Unit test for simple App. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-config.xml") public class AppTest { @Autowired Teacher teacher; @Test public void teachOnLine() { System.out.println(teacher.getClass()); String s = teacher.teachOnLine("java"); System.out.println("s = " + s); } }
6、運行結果
基于 xml(aop:config) 配置文件的方式,增加幾個通知,就會創建幾個通知類,那我們能否將這些通知類寫在一個類中呢?下面就讓我來帶你們找到解決之法!
配置 AspectJ 標簽解讀表
實現步驟:
1、定義業務接口
/** * 使用接口方式實現AOP, 默認通過JDK的動態代理來實現. 非接口方式, 使用的是cglib實現動態代理 */ package cn.kgc.spring05.entity; public interface Teacher { String teachOnLine(String course); String teachOffLine(Integer course); }
2、定義實現類
package cn.kgc.spring05.entity; public class TeacherA implements Teacher{ @Override public String teachOnLine(String course) { System.out.println("TeacherA開始"+course+"課程線上教學"); if(course.equals("java")){ throw new RuntimeException("入門到放棄!"); } return course+"課程線上教學"; } @Override public String teachOffLine(Integer course) { System.out.println("TeacherA開始"+course+"課程線下教學"); return course+"課程線下教學"; } }
3、實現接口定義通知類
package cn.kgc.spring05.advice; public class AllAdvice { public void before(){System.out.println("------------前置通知--------------");} public void afterReturning(){System.out.println("------------后置通知--------------");} public void afterThrowing(){System.out.println("------------異常通知--------------");} public void after(){System.out.println("------------最終通知--------------");} public void around(){System.out.println("------------環繞通知--------------");} }
4、XML 配置方式
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--托管通知--> <bean id="all" class="cn.kgc.spring05.advice.AllAdvice"></bean> <bean id="teacherA" class="cn.kgc.spring05.entity.TeacherA"></bean> <!--AOP的配置--> <aop:config> <!--切點表達式--> <aop:pointcut id="pt" expression="execution(* *(String))"/> <aop:aspect ref="all"> <aop:before method="before" pointcut-ref="pt"></aop:before> <aop:after-returning method="afterReturning" pointcut-ref="pt"></aop:after-returning> <aop:after-throwing method="afterThrowing" pointcut-ref="pt"></aop:after-throwing> <aop:after method="after" pointcut-ref="pt"></aop:after> <!-- <aop:around method="around" pointcut-ref="pt"></aop:around>--> </aop:aspect> </aop:config> </beans>
5、測試
package cn.kgc.spring05.advice; import cn.kgc.spring05.entity.Teacher; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-config2.xml") public class AllAdviceTest{ @Autowired Teacher teacher; @Test public void test01() { System.out.println(teacher.getClass()); String s = teacher.teachOnLine("java"); System.out.println("s = " + s); } }
6、運行結果
常用 “通知” 注解如下:
@Aspect 注解將此類定義為切面。
@Before 注解用于將目標方法配置為前置增強(前置通知)。
@AfterReturning 注解用于將目標方法配置為后置增強(后置通知)。
@Around 定義環繞增強(環繞通知)
@AfterThrowing 配置異常通知
@After 也是后置通知,與 @AfterReturning 很相似,區別在于 @AfterReturning 在方法執行完畢后進行返回,可以有返回值。@After 沒有返回值。
實現步驟:
1、定義業務接口
/** * 使用接口方式實現AOP, 默認通過JDK的動態代理來實現. 非接口方式, 使用的是cglib實現動態代理 */ package cn.kgc.spring05.entity; public interface Teacher { String teachOnLine(String course); String teachOffLine(Integer course); }
2、定義注解
package cn.kgc.spring05.advice; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnnoAdvice { }
3、定義實現類
package cn.kgc.spring05.entity; import cn.kgc.spring05.advice.AnnoAdvice; import org.springframework.stereotype.Component; @Component public class TeacherA implements Teacher{ @Override @AnnoAdvice public String teachOnLine(String course) { System.out.println("TeacherA開始"+course+"課程線上教學"); if(course.equals("java")){ throw new RuntimeException("入門到放棄!"); } return course+"課程線上教學"; } @Override @AnnoAdvice public String teachOffLine(Integer course) { System.out.println("TeacherA開始"+course+"課程線下教學"); return course+"課程線下教學"; } }
4、實現接口定義切面類
首先在類上面添加 @Aspect 注解,將該類轉化為切面類,再在類中的各個方法上面使用各自的 “通知” 注解即可實現。
package cn.kgc.spring05.advice; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class AllAdvice { @Pointcut("@annotation(AnnoAdvice)") public void point(){} @Before("point()") public void before(){System.out.println("------------前置通知--------------");} @AfterReturning("point()") public void afterReturning(){System.out.println("------------后置通知--------------");} @AfterThrowing("point()") public void afterThrowing(){System.out.println("------------異常通知--------------");} @After("point()") public void after(){System.out.println("------------最終通知--------------");} @Around("point()") public Object aroundAdvice(ProceedingJoinPoint joinPoint){ Object proceed = null; try { System.out.println("----------spring aop 環繞 前通知-----------"); proceed = joinPoint.proceed(); System.out.println("----------spring aop 環繞 后通知-----------"); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("----------spring aop 環繞 異常通知-----------"); }finally { System.out.println("----------spring aop 環繞 最終通知-----------"); } return proceed; } }
5、XML 配置方式
開啟包掃描和aspectj自動代理
<?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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--開啟包掃描--> <context:component-scan base-package="cn.kgc.spring05"></context:component-scan> <!--開啟aspectj自動代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
6、測試
package cn.kgc.spring05.advice; import cn.kgc.spring05.entity.Teacher; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-config3.xml") public class AllAdviceTest{ @Autowired Teacher teacher; @Test public void test01() { System.out.println(teacher.getClass()); String s = teacher.teachOnLine("html"); System.out.println("s = " + s); } }
7、運行效果
讀到這里,這篇“Spring中的AOP編程怎么應用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。