1. 程式人生 > >Spring之註解版AOP的使用

Spring之註解版AOP的使用

AOP:【動態代理】  *         指在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式;  *   * 1、匯入aop模組;Spring AOP:(spring-aspects包)  * 2、定義一個業務邏輯類(MathCalculator);在業務邏輯執行的時候將日誌進行列印(方法之前、方法執行結束、方法出現異常,xxx)  * 3、定義一個日誌切面類(LogAspects):切面類裡面的方法需要動態感知MathCalculator.div執行到哪裡然後執行;  *         通知方法:  *             前置通知(@Before):logStart:在目標方法(div)執行之前執行  *             後置通知(@After):logEnd:在目標方法(div)執行結束之後執行(無論方法正常結束還是異常結束)  *             返回通知(@AfterReturning):logReturn:在目標方法(div)正常返回之後執行  *             異常通知(@AfterThrowing):logException:在目標方法(div)出現異常以後執行  *             環繞通知(@Around):動態代理,手動推進目標方法執行(joinPoint.procced())  * 4、給切面類的目標方法標註何時何地執行(通知註解);  * 5、將切面類和業務邏輯類(目標方法所在類)都加入到容器中;  * 6、必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)  * [7]、給配置類中加 @EnableAspectJAutoProxy 【開啟基於註解的aop模式】  *         在Spring中很多的 @EnableXXX;  *  * 關鍵三步:

 *  1)、將業務邏輯元件和切面類都加入到容器中;告訴Spring哪個是切面類(@Aspect)  *  2)、在切面類上的每一個通知方法上標註通知註解,告訴Spring何時何地執行(切入點表示式)  *  3)、開啟基於註解的aop模式;@EnableAspectJAutoProxy

1、pom.xml中匯入Spring AOP的spring-aspects包

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>4.3.12.RELEASE</version>
		</dependency>

2、定義一個業務邏輯類(MathCalculator.java)

在業務邏輯執行的時候將日誌進行列印(方法之前、方法執行結束、方法出現異常,xxx)

package com.atguigu.aop;

public class MathCalculator {
	
	public int div(int i,int j){
		System.out.println("MathCalculator...div...");
		return i/j;	
	}

}

3、定義一個日誌切面類(LogAspects.java)

切面類裡面的方法需要動態感知MathCalculator.div執行到哪裡然後執行;  *         通知方法:  *             前置通知(@Before):logStart:在目標方法(div)執行之前執行  *             後置通知(@After):logEnd:在目標方法(div)執行結束之後執行(無論方法正常結束還是異常結束)  *             返回通知(@AfterReturning):logReturn:在目標方法(div)正常返回之後執行  *             異常通知(@AfterThrowing):logException:在目標方法(div)出現異常以後執行  *             環繞通知(@Around):動態代理,手動推進目標方法執行(joinPoint.procced())

給切面類上加一個註解:@Aspect,告訴Spring哪個類是切面類;

在切面方法中,根據引數,可以獲取目標方法的引數,方法名稱及丟擲的具體的異常資訊;

注意:切點表示式有很多種寫法,可參考spring的官方文件;

          JoinPoint一定要出現在引數表的第一位;

package com.atguigu.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 切面類
 * @author lfy
 * 
 * @Aspect: 告訴Spring當前類是一個切面類
 *
 */
@Aspect
public class LogAspects {
	
	//抽取公共的切入點表示式
	//1、本類引用
	//2、其他的切面引用
	@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
	public void pointCut(){};
	
	//@Before在目標方法之前切入;切入點表示式(指定在哪個方法切入)
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint){
		Object[] args = joinPoint.getArgs();
		System.out.println(""+joinPoint.getSignature().getName()+"執行。。。@Before:引數列表是:{"+Arrays.asList(args)+"}");
	}
	
	@After("com.atguigu.aop.LogAspects.pointCut()")
	public void logEnd(JoinPoint joinPoint){
		System.out.println(""+joinPoint.getSignature().getName()+"結束。。。@After");
	}
	
	//JoinPoint一定要出現在引數表的第一位
	@AfterReturning(value="pointCut()",returning="result")
	public void logReturn(JoinPoint joinPoint,Object result){
		System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:執行結果:{"+result+"}");
	}
	
	@AfterThrowing(value="pointCut()",throwing="exception")
	public void logException(JoinPoint joinPoint,Exception exception){
		System.out.println(""+joinPoint.getSignature().getName()+"異常。。。異常資訊:{"+exception+"}");
	}

}

4、定義配置類

將切面類和業務邏輯類(目標方法所在類)都加入到容器中;

給配置類中加 @EnableAspectJAutoProxy 【開啟基於註解的aop模式】

package com.atguigu.config;



import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.atguigu.aop.LogAspects;
import com.atguigu.aop.MathCalculator;


@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
	 
	//業務邏輯類加入容器中
	@Bean
	public MathCalculator calculator(){
		return new MathCalculator();
	}

	//切面類加入到容器中
	@Bean
	public LogAspects logAspects(){
		return new LogAspects();
	}
}

5、測試

注意:spring容器中的元件才能使用spring提供的aop功能;

package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.atguigu.aop.MathCalculator;
import com.atguigu.bean.Boss;
import com.atguigu.bean.Car;
import com.atguigu.bean.Color;
import com.atguigu.bean.Red;
import com.atguigu.config.MainConfigOfAOP;
import com.atguigu.config.MainConifgOfAutowired;
import com.atguigu.dao.BookDao;
import com.atguigu.service.BookService;

public class IOCTest_AOP {
	
	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
		
		//1、不要自己建立物件
//		MathCalculator mathCalculator = new MathCalculator();
//		mathCalculator.div(1, 1);
		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
		
		mathCalculator.div(1, 1);
		
		applicationContext.close();
	}

}

結果:

說明:已獲取到目標方法引數列表,方法名稱和執行結果;並在目標方法執行前、後進行了攔截;

如果丟擲異常,傳入1除以0,結果:

說明:已在目標方法執行結束後獲取到了異常資訊;