Spring官网阅读(十八)AOP的核心概念(3)

简介: Spring官网阅读(十八)AOP的核心概念(3)

AOP的应用


AOP的实际应用非常多,我这里就给出两个例子

1.全局异常处理器

2.利用AOP打印接口日志


全局异常处理器


需要用到两个注解:@RestControllerAdvice及@ExceptionHandler`,总共分为以下几步:

  1. 定义自己项目中用到的错误码及对应异常信息
  2. 封装自己的异常
  3. 申明全局异常处理器并针对业务中的异常做统一处理


定义错误码及对应异常信息

@AllArgsConstructor
@Getter
public enum ErrorCode {
    INTERNAL_SERVICE_ERROR(500100, "服务端异常"),
    PASSWORD_CAN_NOT_BE_NULL(500211, "登录密码不能为空"),
    PASSWORD_ERROR(500215, "密码错误");
    private int code;
    private String msg;
}
// 统一返回的参数
@Data
public class Result<T> {
    private int code;
    private String msg;
    private T data;
    public static <T> Result<T> success(T data){
        return new Result<T>(data);
    }
    public static <T> Result<T> error(ErrorCode cm){
        return new Result<T>(cm.getMsg);
    }
}

封装对应异常

public class GlobalException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    private int errorCode;
    public CreativeArtsShowException(int errorCode) {
        this.errorCode = errorCode;
    }
    public CreativeArtsShowException(ErrorCode errorCode) {
        super(errorCode.getMsg());
        this.errorCode =  errorCode.getCode();
    }
}

申明异常处理器

//该注解定义全局异常处理类
//@ControllerAdvice
//@ResponseBody
// 使用@RestControllerAdvice可以替代上面两个注解
@RestControllerAdvice
//@ControllerAdvice(basePackages ="com.example.demo.controller") 可指定包
public class GlobalExceptionHandler {
    @ExceptionHandler(value=GlobalException.class) //该注解声明异常处理方法
    public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
        e.printStackTrace();
        // 在这里针对异常做自己的处理
    }
}

其实SpringMVC中提供了一个异常处理的基类(org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler)。我们只需要将自定义的异常处理类继承这个ResponseEntityExceptionHandler然后复写对应的方法即可完成全局异常处理。这个类中的方法很简单,所以这里就不放代码了。


这个类中已经定义了很多的异常处理方法,如下:

@ExceptionHandler({
      HttpRequestMethodNotSupportedException.class,
      HttpMediaTypeNotSupportedException.class,
      HttpMediaTypeNotAcceptableException.class,
      MissingPathVariableException.class,
      MissingServletRequestParameterException.class,
      ServletRequestBindingException.class,
      ConversionNotSupportedException.class,
      TypeMismatchException.class,
      HttpMessageNotReadableException.class,
      HttpMessageNotWritableException.class,
      MethodArgumentNotValidException.class,
      MissingServletRequestPartException.class,
      BindException.class,
      NoHandlerFoundException.class,
      AsyncRequestTimeoutException.class
    })

所以我们只需要复写对应异常处理的方法即可完成自己在当前业务场景下异常的处理。但是需要注意的是,它只会对上面这些框架抛出的异常进行处理,对于我们自定义的异常还是会直接抛出,所以我们自定义的异常处理还是需要在其中进行定义。


接口日志


我们在开发中经常会打印日志,特别是接口的入参日志,如下:

@RestController
@RequestMapping("/test/simple")
@Validated
@Slf4j
public class ValidationController {
    @GetMapping("/valid")
    public String testValid(
            @Max(10) int age, @Valid @NotBlank String name) {
        log.info("接口入参:" + age + "      " + name);
        return "OK";
    }
}

如果每一个接口都需要添加这样一句代码的话就显得太LOW了,基于此我们可以使用AOP来简化代码,按照以下几步即可:

1.自定义一个注解

2.申明切面


定义一个注解

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Log {
}

申明切面

@Aspect
@Component
@Slf4j
public class LogAspect {
    @Pointcut("@annotation(com.spring.study.springfx.aop.annotation.Log)")
    private void pointcut() {
    }
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        Object[] args = joinPoint.getArgs();
        String methodName = method.getName();
        Class<?> declaringClass = method.getDeclaringClass();
        String simpleName = declaringClass.getSimpleName();
        StringBuilder sb = new StringBuilder();
        sb.append(simpleName).append(".").append(methodName).append(" [");
        for (int i = 0; i < parameters.length; i++) {
            String name = parameters[i].getName();
            sb.append(name);
            sb.append(":");
            sb.append(args[i]);
            sb.append(";");
        }
        sb.setLength(sb.length() - 1);
        sb.append("]");
        log.info(sb.toString());
    }
}

基于上面的例子测试:

@RestController
@RequestMapping("/test/simple")
@Validated
@Slf4j
public class ValidationController {
    @Log
    @GetMapping("/valid")
    public String testValid(
            @Max(10) int age, @Valid @NotBlank String name) {
        log.info("接口入参:" + age + "      " + name);
        return "OK";
    }
}
// 控制台输出日志:
// ValidationController.testValid [age:0;name:11]

总结


这篇文章到这里就结束啦,这也是《Spring官网阅读笔记》系列笔记的最后一篇。其实整个SpringFrameWork可以分为三部分


1.IOC

2.AOP

3.事务(整合JDBC,MyBatis)

而IOC跟AOP又是整个Spring的基石,这一系列的笔记有10篇以上是IOC相关的知识。AOP的只有这一篇,这是因为Spring简化了AOP的使用,如果要探究其原理以及整个AOP的体系的话必定要深入到源码中去,所以思来想去还是决定将其放到源码阅读系列笔记中去。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6天前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
29 6
|
1月前
|
监控 Java 开发者
Spring AOP动态代理
Spring AOP动态代理
43 1
|
30天前
|
设计模式 Java Maven
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
35 1
|
2天前
|
安全 Java 数据库连接
[AIGC] Spring框架的基本概念和优势
[AIGC] Spring框架的基本概念和优势
|
23天前
|
XML Java Maven
Spring之Aop的注解使用
Spring之Aop的注解使用
|
23天前
|
设计模式 监控 Java
深入浅出 Spring:核心概念和基本用法详解
深入浅出 Spring:核心概念和基本用法详解
16 1
|
29天前
|
Java Spring
Spring 如何实现 AOP
Spring 如何实现 AOP
17 0
|
1月前
|
Java 编译器 程序员
Spring AOP 和 AspectJ 的比较
Spring AOP 和 AspectJ 的比较
37 0
|
1月前
|
Java Spring
【spring(三)】AOP总结
【spring(三)】AOP总结
|
Java Spring 容器
SSM-Spring-01:Spring的概念+入门案例
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------     Spring   提起Spring,就会想到企业级框架这个词   企业级系统:     1.
1211 0