SPRing AOP技術(基于aspectJ)的Annotation開發
@(Spring)[aop, spring, xml, Spring, annotation, aspectJ]
Spring AOP技術基于AspectJ的Annotation開發Spring AOP的Annotation的開發Spring的基于AspectJ的AOP的Annotation開發第一步引入jar包第二步創建配置文件第三步創建需增強包和類第四步將類交給Spring管理第五步編寫測試第六步編寫切面類和通知第七步 配置切面類第八步開啟AOP的自動代理第九步通過注解實現AOP第九步執行測試通知類型前置通知配置切面和通知單元測試后置通知配置切面和通知單元測試環繞通知配置切面和通知單元測試異常拋出通知配置切面和通知單元測試最終通知配置切面和通知單元測試切入點的注解Spring AOP小項目
Spring AOP的Annotation的開發
Spring的基于AspectJ的AOP的Annotation開發
第一步引入jar包

第二步創建配置文件
引入AOP的約束<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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>第三步創建需增強包和類
創建接口package com.pc.aop.dao;/** * 客戶持久層接口 * * @author Switch * @data 2016年11月23日 * @version V1.0 */public interface CustomerDao { /** * 保存用戶 */ public void save();}創建實現類package com.pc.aop.dao.impl;import com.pc.aop.dao.CustomerDao;/** * 用戶持久層實現類 * * @author Switch * @data 2016年11月23日 * @version V1.0 */public class CustomerDaoImpl implements CustomerDao { @Override public void save() { System.out.println("保存用戶了。。。"); }}第四步將類交給Spring管理
<bean id="customerDao" class="com.pc.aop.dao.impl.CustomerDaoImpl" />第五步編寫測試
package com.pc.test;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.pc.aop.dao.CustomerDao;/** * 面向切面編程測試類 * * @author Switch * @data 2016年11月23日 * @version V1.0 */// 配置Spring單元測試環境@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試Spring單元測試集成 @Test public void testSpring() { customerDao.save(); }}輸出
保存用戶了。。。PS:這時候沒用使用AOP進行任何增強
第六步編寫切面類和通知
package com.pc.aop.advice;import org.aspectj.lang.ProceedingJoinPoint;/** * 切面類 * * @author Switch * @data 2016年11月23日 * @version V1.0 */public class MyAspect { // 通知:校驗權限 public void check() { System.out.println("校驗權限。。。。。。"); }}第七步 配置切面類
<!-- 配置切面類 --><bean id="myAspect" class="com.pc.aop.advice.MyAspect"/>第八步開啟AOP的自動代理
<!-- 開啟AOP注解自動代理 --><aop:aspectj-autoproxy/>第九步通過注解實現AOP
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 前置通知 @Before("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.save(..))") // 通知:校驗權限 public void check() { System.out.println("校驗權限。。。。。。"); }}第九步執行測試
package com.pc.test;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.pc.aop.dao.CustomerDao;/** * 面向切面編程測試類 * * @author Switch * @data 2016年11月23日 * @version V1.0 */// 配置Spring單元測試環境@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試Spring單元測試集成 @Test public void testSpring() { customerDao.save(); }}輸出
校驗權限。。。。。。保存用戶了。。。通知類型

PS:因為在XML中已經給出了各個通知的完整測試代碼,所以這里只給出通知代碼和測試代碼及其結果,如果想查看其他代碼,請查找《Spring AOP技術(基于AspectJ)的XML開發》
前置通知
前置通知:在目標方法執行之前完成的增強。獲得切入點信息。 注解:@Before
PS:接入點信息,其他類型的增強也可以通過這種方法使用。
配置切面和通知
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 前置通知 @Before("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.save(..))") // 通知:校驗權限 public void check(JoinPoint joinPoint) { System.out.println("校驗權限。。。。。。"); // 輸出接入點信息 System.out.println(joinPoint.toString()); }}單元測試
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試前置通知 @Test public void testBefore() { customerDao.save(); }}輸出
校驗權限。。。。。。execution(void com.pc.aop.dao.CustomerDao.save())保存用戶了。。。后置通知
后置通知:在目標方法執行之后完成的增強。獲得方法的返回值。 注解:@AfterReturning
配置切面和通知
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 后置通知 @AfterReturning(value = "execution(* com.pc.aop.dao.impl.CustomerDaoImpl.delete(..))", returning = "retVal") // 通知:打印日志 public void printLog(String retVal) { System.out.println("打印日志。。。。。"); System.out.println("返回值為:" + retVal); }}單元測試
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試后置通知 @Test public void testAfterRunning() { String delete = customerDao.delete(); System.out.println(delete); }}輸出
刪除用戶了。。。打印日志。。。。。返回值為:deletedelete環繞通知
環繞通知:在目標方法執行前和執行后完成的增強。阻止目標方法的執行,獲得方法參數。 注解:@Around
配置切面和通知
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 環繞通知 @Around("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.update(..))") // 通知:計算方法耗時 public void calTime(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("方法執行前。。。。。。"); // 打印參數 System.out.println("參數為:" + joinPoint.getArgs()[0]); // 執行目標方法 joinPoint.proceed(); System.out.println("方法執行后。。。。。。"); }}單元測試
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試環繞通知 @Test public void testAround() { customerDao.update(6166); }}輸出
方法執行前。。。。。。參數為:6166更新用戶了。。。方法執行后。。。。。。異常拋出通知
異常拋出通知:在目標方法執行出現異常的時候完成的增強。獲得異常的信息。 注解:@AfterThrowing
配置切面和通知
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 異常通知 @AfterThrowing(value = "execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))", throwing = "ex") // 通知:異常處理 public void throwHandler(Throwable ex) { System.out.println("異常處理。。。。。。" + ex.getMessage()); }}單元測試
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試異常通知 @Test public void testAfterThrowing() { customerDao.find(); }}輸出
查詢用戶了。。。異常處理。。。。。。/ by zero最終通知
最終通知:無論目標方法是否出現異常總是執行的增強。 注解:@After
PS:該案例和異常測試案例對同一個target進行增強。
配置切面和通知
// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 最終通知 @After("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))") // 通知:關閉資源 public void close() { System.out.println("關閉資源。。。。。。"); }}單元測試
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringAOPTest { // 注入依賴 @Resource(name = "customerDao") private CustomerDao customerDao; // 測試最終通知 @Test public void testFinally() { customerDao.find(); }}輸出
查詢用戶了。。。關閉資源。。。。。。異常處理。。。。。。/ by zero切入點的注解
在上面的案例中,都是在通知上面直接定義切入點。這樣有一個比較麻煩的問題,也就是如果我們需要修改多個通知相同的切入點,那么需要改大量的切入點代碼。
上面的問題,可以通過使用切入點注解@Pointcut
解決。
案例:
package com.pc.aop.advice;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;/** * 切面類 * * @author Switch * @data 2016年11月23日 * @version V1.0 */// 配置了自動AOP代理的,需要在類上配置該注解,不然無法被識別為切面@Aspectpublic class MyAspect { // 異常通知 @AfterThrowing(value = "com.pc.aop.advice.MyAspect.pointcut1()", throwing = "ex") // 通知:異常處理 public void throwHandler(Throwable ex) { System.out.println("異常處理。。。。。。" + ex.getMessage()); } // 最終通知 @After("com.pc.aop.advice.MyAspect.pointcut1()") // 通知:關閉資源 public void close() { System.out.println("關閉資源。。。。。。"); } // 配置切入點 @Pointcut("execution(* com.pc.aop.dao.impl.CustomerDaoImpl.find(..))") public void pointcut1() {}}PS:切入點的注解需要定義在方法上,切入點方法一般是無意義的。如果需要使用切入點方法,只需要在通知聲明中寫入包名.類型.方法名()
,如果通知和切入點在一個類中,那么也可以直接寫入方法名()
Spring AOP小項目
GitHub:Spring AOP小項目 GitHub:MyStore-netease