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编程可以运用在日志、事务、权限控制等等一些地方,只要你想。