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

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

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