把文章在简书同步了之后,有几篇文章被收入专题,还有一篇文章被收入首页,尽管不是什么了不起的事,但是这样也让自己挺开心的,慕课网约我录了一次视频课程,没有通过,让修改下录第二次,想想还是算了,目前的自己水平还是有限,另一方面时间也比较有限,在博客这方面能够持续下去就已经是件很难的事情,其他的以后再说看缘分吧。接下来继续技术的分析。
前两篇主要记录了AOP所用的核心设计模式-代理模式,包含动态代理和静态代理,以及JDK和CGLIB的两种实现方式,接下来开始重点分析Spring-AOP源码相关操作,当然开始也是从概念理解。这个不太好明白,但是第一遍阅读也主要是为了对于框架有个大局观,不需要过度的拘泥于细节。AOP这段计划在9月中之前结束,而下半月主要是SpringMVC相关的源码研究,可能也会结合一点事务和mybatis源码的研究。
参考了很多程序员DD的东西
Spring-Aop相关概念如下:
我把这个图片放在网络上了,欢迎大家前往下载,建议大家先从地址一下载,地址二要耗流量
下载地址
备用地址
相关的概念描述在脑图中有详细解释,当然方便理解,这里我也会记录下来。
我们先在springboot中将aop整合进来
在pom.xml引入pom依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
starter中默认添加了@EnableAspectJAutoProxy
设计一个简单的controller入门
@RestController public class HomeController { private Logger logger = Logger.getLogger(getClass()); @GetMapping("/index") public String index(@RequestParam String name){ logger.info("-----------{name}:{}"+name); return "【welcome to aop】:" +name; } }
使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
代码如下:
@Aspect @Component public class WebLogAspect { private Logger logger = Logger.getLogger(getClass()); @Pointcut("execution(public * com.sunliangliang.springsource.controller..*(..))") public void webLog(){} @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录下请求内容 logger.info("URL : " + request.getRequestURL().toString()); logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 logger.info("RESPONSE : " + ret); } }
通过@Pointcut定义切入点为 com.sunliangliang.springsource.controller.
包下面的所有函数,然后通过 @Before
实现,对请求内容的日志记录(本文只是说明过程,可以根据需要调整内容),最后通过 @AfterReturning
记录请求返回的对象。
输出如下日志:
2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : URL : http://localhost:8888/index 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : HTTP_METHOD : GET 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : IP : 0:0:0:0:0:0:0:1 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : CLASS_METHOD : com.sunliangliang.springsource.controller.HomeController.index 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : ARGS : [liangliang] 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.s.controller.HomeController : -----------{name}:{}liangliang 2017-09-01 18:20:34.953 INFO 14696 --- [nio-8888-exec-3] c.s.springsource.aop.WebLogAspect : RESPONSE : 【welcome to aop】:liangliang
由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对Web层做多个切面,校验用户,校验头信息等等,这个时候经常会碰到切面的处理顺序问题。
所以要定义每个切面的优先级,我们需要@Order(i)注解来标识切面的优先级。i值越小,优先级越高。假设我们还有一个切面是CheckNameAspect用来校验name必须为didi,我们为其设置@Order(10),而上文中WebLogAspect设置为@Order(5),所以WebLogAspect有更高的优先级,这个时候执行顺序是这样的:
在@After和@AfterReturning中优先执行@Order(10)的内容,再执行@Order(5)的内容
所以我们可以这样子总结:
在切入点前的操作,按order的值由小到大执行