AOP核心概念
1、横切关注点

对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)-》(通知+切点)

类是对物体特征的抽象,切面就是对横切关注点的抽象。
通知+切点
意思就是所有要被应用到增强(advice)代码的地方。(包括方法的方位信息)
3、连接点(joinpoint)-》(被拦截的方法)

被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)-》(描述拦截那些方法的部分)

对连接点进行拦截的定义
5、通知(advice)-》(拦截后执行自己业务逻辑的那些部分)

所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
这玩意也叫 增强
在逻辑层次上包括了我们抽取的公共逻辑和方位信息。因为Spring只能方法级别的应用AOP,也就是我们常见的before,after,after-returning,after-throwing,around五种,意思就是在方法调用前后,异常时候执行我这段公共逻辑呗。
6、目标对象

代理的目标对象
7、织入(weave)

将切面应用到目标对象并导致代理对象创建的过程。
比如根据Advice中的方位信息在指定切点的方法前后,执行增强。这个过程Spring 替我们做好了。利用的是CGLIB动态代理技术。
8、引入(introduction)

在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
图解

上面那一堆看不懂对吗? 我也不太懂。
来看张图

好了,现在我们直接看代码,简单的使用如下:

引入pom

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version><!--$NO-MVN-MAN-VER$-->
</dependency> <!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency> </dependencies>

创建DTO对象

package com.szl.demo.common.dto;

import lombok.Data;

@Data
public class AccountDto {
private String accountNo;
private String accountName;
private Double balance;
}

创建service和service实现类

package com.szl.demo.service;

import com.szl.demo.common.dto.AccountDto;

public interface DemoService {

    public AccountDto getUserAccount();

}
package com.szl.demo.service.impl;

import org.springframework.stereotype.Service;
import com.szl.demo.common.dto.AccountDto;
import com.szl.demo.service.DemoService; @Service("demoService")
public class DemoServiceImpl implements DemoService { public AccountDto getUserAccount() {
AccountDto dto = new AccountDto();
dto.setAccountNo("22133232001");
dto.setAccountName("XXX");
dto.setBalance(3000D);
return dto;
}
}

创建controller

package com.szl.demo.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.szl.demo.common.dto.AccountDto;
import com.szl.demo.service.DemoService; @Controller
public class DemoController {
@Autowired
private DemoService demoService;

    /**
     * @param request
     * @param response
     * @param body          这个是请求body体
     * @param nickName      这个是post参数
     * @param birthday      这个是post参数
     * @return
     */
@ResponseBody
    @RequestMapping(value = "/testAopDemo", method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json;charset=UTF-8")
    public AccountDto testAopDemo(HttpServletRequest request, HttpServletResponse response,
            @RequestBody String body,
            @RequestParam("nickName") String nickName,
            @RequestParam("birthday") String birthday) {
        log.info("controller层 请求body内容: " + body);
        log.info("controller层 请求参数nickName内容: " + nickName);
        log.info("controller层 请求参数birthday内容: " + birthday);
        return demoService.getUserAccount();
    } }

以上工作全部做完后,现在我们创建AOP核心代码块

package com.szl.demo.common.aop;

import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import lombok.extern.slf4j.Slf4j; /**
* @author Jimmy Shan
* @desc 创建AOP 切面记录controller的日志记录
* @Slf4j 必须结合lombok一起使用,否则无效
*/
@Slf4j
@Aspect
@Component
public class WebLogAcpect {
// 用于记录每个controller执行的耗时时间,毫秒级
private ThreadLocal<Long> timeLocal = new ThreadLocal<>(); /**
* 定义切入点,切入点为com.example.aop下的所有函数
*/
@Pointcut("execution(public * com.szl.demo.controller.*.*(..))")
public void webLog(){} /**
* @param joinPoint
* @throws Throwable
* @desc 前置通知:在连接点之前执行的通知
*/    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        timeLocal.set(startTime);// 记录开始时间         // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        
        // 记录下请求内容
        log.info("URL : " + request.getRequestURL().toString());
        log.info("HTTP_METHOD : " + request.getMethod());
        log.info("IP : " + request.getRemoteAddr());
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        
        //获取请求参数信息 和 requestBody数据
        List<String> paramList = new ArrayList<>();
        Object[] objArr = joinPoint.getArgs();
        for (int i = 0; i < objArr.length; i++) {
             if (objArr[i] instanceof String) {
                 paramList.add(String.valueOf(objArr[i]));
             }
        }
        log.info("AOP获取参数内容为: " + String.join("###", paramList));
    } /**
* @param ret
* @throws Throwable
* @desc 处理完成请求,返回的信息
*/    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        log.info("返回的内容: " + ret);
        log.info("耗时: {} 毫秒", (System.currentTimeMillis() - timeLocal.get().longValue()));
        timeLocal.remove();
    } }

OK,到此我们的AOP就可以正常的工作了,我们来看一下效果,控制台日志信息输出如下:

00:33:37.167 [http-nio-8081-exec-1] INFO   - Initializing Spring DispatcherServlet 'dispatcherServlet'
00:33:37.167 [http-nio-8081-exec-1] INFO - Initializing Servlet 'dispatcherServlet'
00:33:37.171 [http-nio-8081-exec-1] INFO - Completed initialization in 2 ms
00:33:37.218 [http-nio-8081-exec-1] INFO - URL : http://127.0.0.1:8081/testAopDemo
00:33:37.218 [http-nio-8081-exec-1] INFO - HTTP_METHOD : POST
00:33:37.218 [http-nio-8081-exec-1] INFO - IP : 127.0.0.1
00:33:37.218 [http-nio-8081-exec-1] INFO - CLASS_METHOD : com.szl.demo.controller.DemoController.testAopDemo
00:33:37.218 [http-nio-8081-exec-1] INFO - ARGS : [org.apache.catalina.connector.RequestFacade@69bd93bb, org.apache.catalina.connector.ResponseFacade@5a33b12, {"info2":"haha", "name":"Jackson"}, 百里守约, 2019-06-05]
00:33:37.218 [http-nio-8081-exec-1] INFO - AOP获取参数内容为: {"info2":"haha", "name":"Jackson"}###百里守约###2019-06-05
00:33:37.234 [http-nio-8081-exec-1] INFO - controller层 请求body内容: {"info2":"haha", "name":"Jackson"}
00:33:37.234 [http-nio-8081-exec-1] INFO - controller层 请求参数nickName内容: 百里守约
00:33:37.234 [http-nio-8081-exec-1] INFO - controller层 请求参数birthday内容: 2019-06-05
00:33:37.234 [http-nio-8081-exec-1] INFO - 返回的内容: AccountDto(accountNo=22133232001, accountName=XXX, balance=3000.0)
00:33:37.234 [http-nio-8081-exec-1] INFO - 耗时: 16 毫秒

蓝色字体部分就是 AOP 和 controller 获取参数的值信息。

转自:https://www.cnblogs.com/lic309/p/4079194.html

https://blog.csdn.net/lmb55/article/details/82470388

最新文章

  1. jQuery checkbox的全选与反选
  2. Sprint第三阶段(第三天12.11)
  3. RESTful框架调研
  4. C++位操作符总结
  5. 001. 启动Visual Studio 2010报错
  6. MSP430F149学习之路——时钟2
  7. WebMagic的设计参考了业界最优秀的爬虫Scrapy
  8. 基于最简单的FFmpeg的AVDevice抽样(屏幕录制)
  9. 2017寒假零基础学习Python系列之函数之 定义默认参数
  10. CSS实现父元素半透明,子元素不透明
  11. poj 2503 查字典
  12. 简谈高通Trustzone的实现
  13. JS自定义表单提交处理方案
  14. 【CF833E】Caramel Clouds(线段树)
  15. Nginx报502错误,PHP最大执行时间设置
  16. Nginx 负载均衡的Cache缓存批量清理的操作记录
  17. js regex variable &amp; Set, Map
  18. WebStrom配置
  19. DOS命令之at命令详解
  20. 【洛谷】【线段树】P1886 滑动窗口

热门文章

  1. Program不是内部命令也不是外部命令
  2. URLDoBase64
  3. Windows系统因“CredSSP加密Oracle修正”无法远程连接
  4. 自定义电脑IP地址
  5. Influx Sql系列教程一:database 数据库
  6. linux命令行模式与图形界面切换
  7. Django框架4——form表单
  8. Django项目常见面试问题
  9. AX2009取销售订单的税额
  10. INNODB 统计信息采集