【JAVA】Spring AOP 介紹與簡單DEMO

Spring AOP 介紹與簡單DEMO

通知(Advice)

Spring中的切面一共提供5種通知的類型:
  前置通知(@Before)
  後置通知(@After)
  返回通知(@AfterReturning)
  異常通知(@AfterThrowing)
  環繞通知(@Around)
前面4個較爲容易理解,例如“前置通知”,我們通常在一個方法的第一句打印出傳入的方法參數,此時就可以使用前置通知在方法調用前打印出傳入的參數。對於“後置通知”實際是“返回通知”和“異常通知”的並集,返回通知表示程序正確運行返回後執行,異常通知表示程序不正常運行拋出異常時執行,而後置通知則不論程序是否正確運行,一旦離開方法就會執行。
環繞通知最爲強大,它包裹了被通知的方法,可同時定義前置通知和後置通知。

切點(Pointcut)

通知定義了何時工作以及工作內容,切點則定義了在何處工作,也就是在哪個方法應用通知。要表達出在哪個方法中運用通知,這需要用到切點表達式。Spring AOP藉助AspectJ(另一種AOP實現)的切點表達式來確定通知被應用的位置,雖然是藉助但並不支持所有AspectJ的所有切點指示器而僅僅是其一個子集,這其中最爲常用的就是execution切點指示器,表示執行。例如:

execution(* com.deo.springaop.Test.test(..))

DEMO

1. 引用依賴
1) 需要引用的AOP依賴:
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjrt</artifactId>
		<version>1.8.10</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>1.8.10</version>
	</dependency>
2) 需要引用的測試依賴:
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.3.7.RELEASE</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.7.RELEASE</version>
		</dependency>
2. Spring 配置自動掃描
3. 定義一個業務類DEMO:
package aop.service;

import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;

@Component
public class AuthService {

	public boolean delete(JSONObject s) {
		System.out.println("-- delete : " + s);
		return false;
	}
}
4. 針對此業務類定義一個切面:
@Aspect
@Component
public class AopUtil {

	@AfterReturning(returning = "res", pointcut = "execution(* aop.service.*.delete(..))")
	public void check(JoinPoint joinPoint, boolean res) {
		System.out.println("-- check -- param: " + joinPoint.getArgs() + " -- res: " + res);
		Object objArr[] = joinPoint.getArgs();
		for(Object obj : objArr) {
			System.out.println("-- param: " + obj.toString());
		}
	}
}

也可以寫成:

@Aspect
@Component
public class AopUtil {

	@Pointcut("execution(* aop.service.*.delete(..))")
	public void pointcut() {
		System.out.println("-- pointcut --");
	}
	
	@AfterReturning(value = "pointcut()", returning = "res")
	public void check(JoinPoint joinPoint, boolean res) {
		System.out.println("-- check -- param: " + joinPoint.getArgs() + " -- res: " + res);
  String className = joinPoint.getTarget().getClass().getName();
  String methodName = joinPoint.getSignature().getName();
  Object objArr[] = joinPoint.getArgs();
		for(Object obj : objArr) {
			System.out.println("-- param: " + obj.toString());
		}
	}
}

@AfterReturning:定義在方法返回時執行此切面。
@Pointcut:定義了一個切點,execution 標識在哪些方法會觸發此切點。
returning:可以獲取方法返回的參數.
JoinPoint joinPoint: 通過此對象可以獲取方法的信息以及入參參數。

5. 測試類:
package aop.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.SpringRunner;
import com.alibaba.fastjson.JSONObject
import aop.service.AuthService;

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext.xml"})
public class Test {

	@Autowired
	private AuthService auth;
	
	@org.junit.Test
	public void delete() {
		JSONObject json = new JSONObject();
		json.put("name", "張三");
		json.put("age", "17");
		auth.delete(json);
	}
}
6. 運行結果:
-- delete : {"age":"17","name":"張三"}
-- check -- param: [Ljava.lang.Object;@76b1e9b8 -- res: false
-- param: {"age":"17","name":"張三"}

結果表明在執行業務類的delete方法之後,執行了切面的check方法。

AOP編程可以運用在日誌、事務、權限控制等等一些地方,只要你想。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章