Spring Boot : 全局异常处理与自定义切面
工程地址: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基础(IOC)
下一篇: Spring 入门
推荐阅读
-
spring boot 2 全局统一返回RESTful风格数据、统一异常处理
-
只需一步,在Spring Boot中统一Restful API返回值格式与统一处理异常
-
Spring Boot : 全局异常处理与自定义切面
-
Spring Boot全局统一异常处理器
-
spring boot2.x 后端参数校验+统一异常处理+后端自定义全局统一接口返回响应数据格式
-
spring boot 2 全局统一返回RESTful风格数据、统一异常处理
-
Spring Boot处理全局统一异常的两种方法与区别
-
Spring Boot 全局异常处理
-
Spring Boot 2.X REST 风格全局异常处理
-
Spring Boot 全局异常处理