aop
aop通知类型,有如下几类。通过测试验证以下结论:
- 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常);当通知出现异常,连接点之后不会执行。
- 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回;当通知出现异常,不影响连接点执行,影响连接点的返回。
- 异常通知(After throwing advice):在方法抛出异常退出时执行的通知;当通知出现异常,不影响连接点执行,影响连接点的返回。
- 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出),当通知出现异常,不影响连接点执行,影响连接点的返回。
- 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
下面是一个自定义注解
package com.example.mybatisplus.mybatisplusdamo.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* {@link MyTestInterfaceBefore}
*
* @author clc
* @date 2022/5/23 17:35
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyTestInterfaceBefore
{
}
package com.example.mybatisplus.mybatisplusdamo.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* {@link MyTestInterfaceAfter}
*
* @author clc
* @date 2022/5/23 17:35
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyTestInterfaceAfter
{
}
package com.example.mybatisplus.mybatisplusdamo.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* {@link MyTestInterfaceAfterRetrun}
*
* @author clc
* @date 2022/5/23 17:35
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyTestInterfaceAfterRetrun
{
}
package com.example.mybatisplus.mybatisplusdamo.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* {@link MyTestInterfaceAfterThrow}
*
* @author clc
* @date 2022/5/23 17:35
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyTestInterfaceAfterThrow
{
}
package com.example.mybatisplus.mybatisplusdamo.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* {@link MyTestInterface}
*
* @author clc
* @date 2022/5/23 17:35
*/
@Target(METHOD)
@Retention(RUNTIME)
public @interface MyTestInterface
{
}
下面是一个切面类
package com.example.mybatisplus.mybatisplusdamo.aop;
import com.example.mybatisplus.mybatisplusdamo.sql.p3.SqlMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* <p>切面类</p>
* 通知类型
* 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常);当通知出现异常,连接点之后不会执行。
* 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回;当通知出现异常,不影响连接点执行,影响连接点的返回。
* 异常通知(After throwing advice):在方法抛出异常退出时执行的通知;当通知出现异常,不影响连接点执行,影响连接点的返回。
* 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出),当通知出现异常,不影响连接点执行,影响连接点的返回。
* 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
*/
@Component
@Aspect
public class MyTestInterfaceAspect
{
private static Logger logger = LoggerFactory.getLogger(MyTestInterfaceAspect.class);
@Autowired
private SqlMapper sqlMapper;
@Pointcut("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterface01)")
public void pointCut()
{
}
@Before("pointCut()")
public void before()
{
logger.info("pointCut()" + "-->" + "before");
}
@Before("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterfaceBefore)")
public Object handleLogResult(JoinPoint pjp)
throws Throwable
{
logger.info("================================aop/MyTestInterfaceBefore,测试完成");
Signature sig = pjp.getSignature();
MethodSignature msig = (MethodSignature)sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(),
msig.getParameterTypes());
RequestMapping annotation = currentMethod.getAnnotation(RequestMapping.class);
if (annotation == null)
{
return pjp;
}
else
{
logger.error("annotation: {}", annotation);
if (new Random().nextBoolean())
{
//NPE
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.get("dd").toString();
}
Map<String, Object> user = new HashMap<>();
user.put("id", new Random().nextInt(100000) + 101);
user.put("name", "Before-chenlc");
user.put("age", 100);
sqlMapper.add(user);
}
return pjp;
}
@After("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterfaceAfter)")
public Object handleLogResult1(JoinPoint pjp)
throws Throwable
{
logger.info("================================aop/MyTestInterfaceAfter,测试完成");
Signature sig = pjp.getSignature();
MethodSignature msig = (MethodSignature)sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(),
msig.getParameterTypes());
RequestMapping annotation = currentMethod.getAnnotation(RequestMapping.class);
if (new Random().nextBoolean())
{
//NPE
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.get("dd").toString();
}
if (annotation == null)
{
return pjp;
}
else
{
logger.error("annotation: {}", annotation);
Map<String, Object> user = new HashMap<>();
user.put("id", new Random().nextInt(100000) + 101);
user.put("name", "After-chenlc");
user.put("age", 100);
sqlMapper.add(user);
}
return pjp;
}
@AfterReturning("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterfaceAfterRetrun)")
public Object handleLogResult2(JoinPoint pjp)
throws Throwable
{
logger.info("================================aop/MyTestInterfaceAfterReturning,测试完成");
Signature sig = pjp.getSignature();
MethodSignature msig = (MethodSignature)sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(),
msig.getParameterTypes());
RequestMapping annotation = currentMethod.getAnnotation(RequestMapping.class);
if (new Random().nextBoolean())
{
//NPE
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.get("dd").toString();
}
if (annotation == null)
{
return pjp;
}
else
{
logger.error("annotation: {}", annotation);
Map<String, Object> user = new HashMap<>();
user.put("id", new Random().nextInt(100000) + 101);
user.put("name", "AfterReturning-chenlc");
user.put("age", 100);
sqlMapper.add(user);
}
return pjp;
}
@AfterThrowing("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterfaceAfterThrow)")
public Object handleLogResult3(JoinPoint pjp)
throws Throwable
{
logger.info("================================aop/MyTestInterfaceAfterThrow,测试完成");
Signature sig = pjp.getSignature();
MethodSignature msig = (MethodSignature)sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(),
msig.getParameterTypes());
RequestMapping annotation = currentMethod.getAnnotation(RequestMapping.class);
if (new Random().nextBoolean())
{
//NPE
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.get("dd").toString();
}
if (annotation == null)
{
return pjp;
}
else
{
logger.error("annotation: {}", annotation);
Map<String, Object> user = new HashMap<>();
user.put("id", new Random().nextInt(100000) + 101);
user.put("name", "AfterThrowing-chenlc");
user.put("age", 100);
sqlMapper.add(user);
}
return pjp;
}
@Around("@annotation(com.example.mybatisplus.mybatisplusdamo.aop.MyTestInterface)")
public Object handleLogResult4(ProceedingJoinPoint pjp)
throws Throwable
{
logger.info("================================aop/MyTestInterfaceAround,测试完成");
Signature sig = pjp.getSignature();
MethodSignature msig = (MethodSignature)sig;
Object target = pjp.getTarget();
Method currentMethod = target.getClass().getMethod(msig.getName(),
msig.getParameterTypes());
RequestMapping annotation = currentMethod.getAnnotation(RequestMapping.class);
if (new Random().nextBoolean())
{
//NPE
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.get("dd").toString();
}
if (annotation == null)
{
return pjp.proceed();
}
else
{
logger.error("annotation: {}", annotation);
Map<String, Object> user = new HashMap<>();
user.put("id", new Random().nextInt(100000) + 101);
user.put("name", "Around-chenlc");
user.put("age", 100);
sqlMapper.add(user);
}
return pjp.proceed();
}
}
下面是测试接口,分别对几个aop通知模型做了测试
package com.example.mybatisplus.mybatisplusdamo.sql.p1;
import com.alibaba.fastjson.JSON;
import com.example.mybatisplus.mybatisplusdamo.aop.*;
import com.example.mybatisplus.mybatisplusdamo.sql.p2.SqlService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import java.util.*;
@Slf4j
@RestController
@ApiOperation(notes = "clc-测试controller", value = "测试-SqlController")
public class SqlController
{
@Autowired
private SqlService sqlService;
@MyTestInterfaceBefore
@RequestMapping(path = "/test/aop/MyTestInterfaceBefore", method = RequestMethod.GET)
public String testBefore()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceBefore,测试完成");
throw new Exception();
}
log.info("================================aop/MyTestInterfaceBefore,测试完成");
return "aop/MyTestInterfaceBefore,测试完成";
}
@MyTestInterfaceAfterRetrun
@RequestMapping(path = "/test/aop/MyTestInterfaceAfterRetrun", method = RequestMethod.GET)
public String testAfterRetrun()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceAfterRetrun,测试完成");
throw new Exception();
}
log.info("================================aop/MyTestInterfaceAfterRetrun,测试完成");
return "aop/MyTestInterfaceAfterRetrun,测试完成";
}
@MyTestInterfaceAfterThrow
@RequestMapping(path = "/test/aop/MyTestInterfaceAfterThrow", method = RequestMethod.GET)
public String testAfterThrow()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceAfterThrow,测试完成");
throw new Exception();
}
log.info("================================aop/MyTestInterfaceAfterThrow,测试完成");
return "aop/MyTestInterfaceAfterThrow,测试完成";
}
@MyTestInterfaceAfter
@RequestMapping(path = "/test/aop/MyTestInterfaceAfter", method = RequestMethod.GET)
public String testAfter()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceAfter,测试完成");
throw new Exception();
}
log.info("================================aop/MyTestInterfaceAfter,测试完成");
return "aop/MyTestInterfaceAfter,测试完成";
}
@MyTestInterface
@RequestMapping(path = "/test/aop/MyTestInterface", method = RequestMethod.GET)
public String testAround()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceAround,测试完成");
throw new Exception();
}
log.info("================================aop/interface,测试完成");
return "aop/interface,测试完成";
}
@MyTestInterface01
@RequestMapping(path = "/test/aop/MyTestInterface01", method = RequestMethod.GET)
public String testPointcut()
throws Exception
{
List<Map<String, Object>> maps = sqlService.allOrgs();
log.error("map:{}", maps);
if (new Random().nextBoolean())
{
log.info("===========出现异常=====================aop/MyTestInterfaceAround,测试完成");
throw new Exception();
}
log.info("================================aop/interface,测试完成");
return "aop/interface,测试完成";
}
}