一、什麼是AOP AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程,通過預編譯方式和運行期間動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以 ...
一、什麼是AOP
AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程,通過預編譯方式和運行期間動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
二、AOP的一些概念
1.Aspect(切麵):切麵是通知和切入點的結合。
2.Join point(連接點):與切入點匹配的執行點,例如執行方法或處理異常。在SpringAOP 中,連接點始終表示方法執行。
3.Advice(通知):在切麵中需要完成的工作。
4.Pointcut(切入點):切入通知執行的位置。
5.Target(目標):被通知的對象。
6. proxy(代理):向目標對象應用通知之後創建的對象。
7.Introduction(引入):向現有類添加新的方法或屬性。
8.Weaving(織入):將各個方面與其他應用程式類型或對象鏈接起來,以創建通知的對象。
三、AOP的三種實現方法
首先我們需要導入依賴:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.9.1</version> </dependency>
1.通過SpringAPI介面進行實現
SpringAOP有五種通知方式,也有對應的介面:
Before:前置通知,在目標方法調用前通知,對應介面:MethodBeforeAdvice;
After:後置通知,在目標方法返回或異常後通知,對應介面:AfterReturningAdvice;
AfterReturning:後置返回通知,在目標方法返回後通知,對應介面:AfterReturningAdvice;
AfterThrowing:異常通知,在目標方法拋出異常後通知,對應介面:ThrowsAdvice;
Around:環繞通知:通知方法會將目標方法包裹起來,對應介面:MethodInterceptor;
我們下麵以具體的例子來展示:
(1)定義一個介面
package com.jms.service; public interface UserService { void create(); void read(); void update(); void delete(); }
(2)介面的實現類
package com.jms.service; public class UserServiceImpl implements UserService{ @Override public void create() { System.out.println("建立了一個用戶信息"); } @Override public void read() { System.out.println("讀取了一個用戶信息"); } @Override public void update() { System.out.println("更新了一個用戶信息"); } @Override public void delete() { System.out.println("刪除了了一個用戶信息"); } }
(3)建立兩個類分別繼承前置通知和後置返回通知的介面
package com.jms.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class beforeLog implements MethodBeforeAdvice { @Override //method:要執行目標對象的方法 //args:參數 //target:目標對象 public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("[Debug]" + target.getClass().getName() + "的" + method.getName() + "執行..."); } }
package com.jms.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class afterLog implements AfterReturningAdvice{ //returnValue:返回值 @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("[Debug]" + target.getClass().getName() + "的" + method.getName() + "執行完成,返回了" + returnValue); } }
(4)xml配置文件
註冊bean,並且配置aop
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.jms.service.UserServiceImpl"/> <bean id="beforeLog" class="com.jms.log.beforeLog"/> <bean id="afterLog" class="com.jms.log.afterLog"/> <!--方法一:使用SpringAPI介面--> <!--aop配置--> <aop:config> <!--pointcut:切入點 expression:表達式 --> <aop:pointcut id="pointcut" expression="execution(* com.jms.service.UserServiceImpl.*(..))"/> <!--執行環繞增加--> <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans>
(5)測試
@Test public void test1() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); /* UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class)這樣執行會報錯 因為動態代理代理的是介面,所以必須獲取介面 */ UserService userService = applicationContext.getBean("userService", UserService.class); userService.create(); }
測試結果如下:
2.自定義類、自定義切麵實現
介面以及實現類都與上面相同
(1)自定義切麵類
package com.jms.diy; public class diyAspect { public void before() { System.out.println("[Debug]方法執行..."); } public void after() { System.out.println("[Debug]方法執行完成"); } }
切麵類中自定義通知方法
(2)xml配置文件
註入切麵類的Bean,配置AOP
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.jms.service.UserServiceImpl"/> <!--方法二:自定義類,自定義切麵--> <bean id="diyAspect" class="com.jms.diy.diyAspect"/> <aop:config> <!--自定義切麵--> <aop:aspect ref="diyAspect"> <!--切入點--> <aop:pointcut id="pointcut1" expression="execution(* com.jms.service.UserServiceImpl.*(..))"/> <aop:after method="after" pointcut-ref="pointcut1"/> <aop:before method="before" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> </beans>
(3)測試如下
3.通過註解實現
這種實現其實是第二種的註解方式
(1)自定義切麵類
package com.jms.diy; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class annotationAspect { @Before("execution(* com.jms.service.UserServiceImpl.*(..))") public void before() { System.out.println("[Debug]方法前置增強"); } @After("execution(* com.jms.service.UserServiceImpl.*(..))") public void after() { System.out.println("[Debug]方法後置增強"); } }
(2)此處還是採用xml配置,也可以採用java類配置
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="userService" class="com.jms.service.UserServiceImpl"/> <!--方法三:註解--> <!--增加註解支持--> <context:annotation-config/> <context:component-scan base-package="com.jms"/> <aop:aspectj-autoproxy/> </beans>
(3)測試
(本文僅作個人學習記錄用,如有紕漏敬請指正)