三分钟看懂,Java开发如何使用SpringBoot中的AOP处理

三分钟看懂,Java开发如何使用SpringBoot中的AOP处理

可获得两大新人礼包

36份一线互联网Java面试电子书

84个Java稀缺面试题视频

1. 什么是AOP

AOP:Aspect Oriented Programming的缩写,意为:面向切面编程。面向切面编程的目标就是分离关注点。什么是关注点呢?就是你要做的事,就是关注点。假如你是个公子哥,没啥人生目标,天天就是衣来伸手,饭来张口,整天只知道玩一件事!那么,每天你一睁眼,就光想着吃完饭就去玩(你必须要做的事),但是在玩之前,你还需要穿衣服、穿鞋子、叠好被子、做饭等等等等事情,这些事情就是你的关注点,但是你只想吃饭然后玩,那么怎么办呢?这些事情通通交给别人去干。在你走到饭桌之前,有一个专门的仆人A帮你穿衣服,仆人B帮你穿鞋子,仆人C帮你叠好被子,仆人C帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之后,回来,然后一系列仆人又开始帮你干这个干那个,然后一天就结束了!

AOP的好处就是你只需要干你的正事,其它事情别人帮你干。也许有一天,你想裸奔,不想穿衣服,那么你把仆人A解雇就是了!也许有一天,出门之前你还想带点钱,那么你再雇一个仆人D专门帮你干取钱的活!这就是AOP。每个人各司其职,灵活组合,达到一种可配置的、可插拔的程序结构。

2. SpringBoot中的AOP处理

2.1 AOP依赖

使用AOP,首先需要引入AOP的依赖。

org.springframework.boot

spring-boot-starter-aop

2.2 实现AOP切面

SpringBoot中使用AOP非常简单,假如我们要在项目中打印一些log,在引入了上面的依赖之后,我们新建一个类LogAspectHandler,用来定义切面和处理方法。只要在类上加个@Aspect注解即可。

@Aspect

@Component

public class LogAspectHandler {

}

这里主要介绍几个常用的注解:

1.@Pointcut:定义一个切面,即上面所描述的关注的某件事入口。

2.@Before:在做某件事之前做的事。

3.@After:在做某件事之后做的事。

4.@AfterReturning:在做某件事之后,对其返回值做增强处理。

5.@AfterThrowing:在做某件事抛出异常时,处理。

具体看如下代码注释:

/**

* 使用AOP处理log

* @author shengwu ni

* @date 2018/05/04 20:24

*/

@Aspect

@Component

public class LogAspectHandler {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

/**

* 定义一个切面,拦截cn.nxcoder.blog.controller包下的所有方法

*/

@Pointcut("execution(* com.itcodai.demo7.controller.*.*(..))")

public void pointCut() {}

/**

* 在上面定义的切面方法之前执行该方法

* @param joinPoint jointPoint

*/

@Before("pointCut()")

public void doBefore(JoinPoint joinPoint) {

// 获取执行的方法和参数

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("即将执行方法: {}", classMethod);

}

/**

* 在上面定义的切面方法之后执行该方法

* @param joinPoint jointPoint

*/

@After("pointCut()")

public void doAfter(JoinPoint joinPoint) {

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("方法{}已经执行完", classMethod);

}

/**

* 在上面定义的切面方法返回后执行该方法,可以捕获返回对象或者对返回对象进行增强

* @param joinPoint jointPoint

* @param Object result

*/

@AfterReturning(pointcut = "pointCut()", returning = "result")

public void doAfterReturning(JoinPoint joinPoint, Object result) {

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("方法{}执行完毕,返回参数为:{}", classMethod, result);

logger.info("对返回参数进行业务上的增强:{}", result + "增强版");

}

/**

* 在上面定义的切面方法执行抛异常时,执行该方法

* @param joinPoint jointPoint

* @param ex ex

*/

@AfterThrowing(pointcut = "pointCut()", throwing = "ex")

public void afterThrowing(JoinPoint joinPoint, Throwable ex) {

Signature signature = joinPoint.getSignature();

String method = signature.getDeclaringTypeName() + "." + signature.getName();

// 处理异常的逻辑

logger.info("执行方法{}出错,异常为:{}", method, ex);

}

}

JointPoint对象很有用,它可以获取请求的方法名,包括参数(joinPoint.getArgs())等,在@Before中,我们还可以获取用户访问的ip等信息,比如:

// 获取请求的url和ip

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

String url = request.getRequestURL().toString();

String ip = request.getRemoteAddr();

在@AfterReturning中,属性returning的值必须要和参数保持一致,否则检测不到。对于返回值的增强,可以根据业务需要做相应的封装,上面只是做个demo。 下面写个Controller来测试一下:

@RestController

public class TestController {

@GetMapping("/test/{name}")

public String testAop(@PathVariable String name) {

return "Hello " + name;

}

}

启动程序,在浏览器中输入:localhost:8080/test/aop看下结果:

即将执行方法: com.itcodai.demo7.controller.TestController.testAop

方法com.itcodai.demo7.controller.TestController.testAop已经执行完

方法com.itcodai.demo7.controller.TestController.testAop执行完毕,返回参数为:Hello aop

对返回参数进行业务上的增强:Hello aop增强版

当然了,除了如上定义切面的方式外,还可以针对某个注解定义切面,比如我们对具有@GetMapping注解的方法做切面,可以如下定义切面:

@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

public void annotationCut() {}

然后在其他方法上使用该切面,就会切入注解是@GetMapping的方法。因为在实际项目中,可能对于不同的注解有不同的逻辑处理,比如@GetMapping、@PostMapping、@DeleteMapping等。所以这种按照注解的切入方式也很常用。


分享到:


相關文章: