欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot : 全局异常处理与自定义切面

程序员文章站 2022-07-12 13:02:50
...

工程地址:https://github.com/showsys20/spring-demo-cm.git

1.Spring提供了便利的异常捕获机制,采用注解@ExceptionHandler(具体Exception.class)就可以了。全局的异常可以通过定义专门的异常处理类加上注解@ControllerAdvice来实现。下面是个简单的例子。

@ControllerAdvice
@Slf4j
public class MyExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public String runtimeException(RuntimeException e) {
        log.info("全局的异常处理器");
        log.error("error:", e);
        return "RuntimeException:" + e.getMessage();
    }

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public String throwable(Throwable e) {
        log.info("全局的异常处理器");
        log.error("error:", e);
        return "Throwable: " + e.getMessage();
    }

2.控制反转IOC和面向切面编程AOP是Spring的很重要的特性,都是为了减少代码的耦合程度。传统的设计模式中,若A对象引用B对象,需要在A对象中new B对象的实例;而Spring 通过依赖注入(自动,构造方法注入,Set方法注入),A对象不再需要自己显示的new B对象的实例,将控制权交了出去。这即为控制反转。

AOP在Spring中是通过动态代理来实现的,对原业务代码无侵入的情况下,实现功能的增强。先看个例子:

package com.demo.cm.sample.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class LoggerAspectj {
    Logger logger = LoggerFactory.getLogger(LoggerAspectj.class);

    @Pointcut("execution(* com.demo.cm.sample.controller..*.*(..))")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Class clazz = AopUtils.getTargetClass(proceedingJoinPoint.getTarget());
//        Type[] types = AopUtils.getTargetClass(proceedingJoinPoint.getTarget()).getGenericInterfaces(); // 获取所有接口
//        Annotation nologgingAnno = ((Class)types[0]).getAnnotation(Nologging.class); // type是所有类型的父接口

        Method targetMethod = methodSignature.getMethod();
//        String methodName = targetMethod.getName();
        logger.info("============={}: start================", targetMethod);
        Object o = proceedingJoinPoint.proceed();
        long end = System.currentTimeMillis();
        logger.info("============={}: 执行时间{} end================", targetMethod, end - start);
        return o;
    }

}

分为2个步骤,首先定义一个Pointcut,@Pointcut("execution(* com.demo.cm.sample.controller..*.*(..))"),本次定义的切点意思是执行com.demo.cm.sample.controller包及子包下方法任意方法。根据业务需要,可以定义指定返回值,指定参数的切点。

简单来说就是触发的点。而后通过@Around, @Before,@After等注解设置触发时机。

运行程序,访问/hello接口,可以在控制台看到log。而这整个过程,在Controller的方法里面是完全察觉不到这个过程的。

9  INFO 3944 --- [nio-8080-exec-7] com.demo.cm.sample.aspect.LoggerAspectj  : =============public com.demo.cm.model.User com.demo.cm.sample.controller.UserController.getUser(java.lang.Integer): start================
2020-04-06 23:14:11.757  INFO 3944 --- [nio-8080-exec-7] com.demo.cm.sample.aspect.LoggerAspectj  : =============public com.demo.cm.model.User com.demo.cm.sample.controller.UserController.getUser(java.lang.Integer): 执行时间385097 end================

关于切面的机制,spring是采用动态代理在实现的,分为JDK的动态代理和CGLib的动态代理,在自己定义的方法中加断点,debug运行,访问接口后,可以看到调用过程,这个过程能够看出使用的具体是那种代理,也可以跟进去查看源码。

Spring Boot : 全局异常处理与自定义切面

 

相关标签: Spring AOP IOC

上一篇: spring基础(IOC)

下一篇: Spring 入门