免费建网站最新视频教程,2m带宽可以做音乐网站,黄冈网站建设的方案,网站建设及第三方支付目录 前言#xff1a;
正文
一.Spring AOP
1.JDK动态代理
2.Cglib动态代理
使用AOP主要的应用场景#xff1a;
SpringBoot通过自定义注解实现日志打印
一.Maven依赖
二.ControllerMethodLog.class自定义注解
三.Spring AOP切面方法的执行顺序
四.ControllerMethodL…目录 前言
正文
一.Spring AOP
1.JDK动态代理
2.Cglib动态代理
使用AOP主要的应用场景
SpringBoot通过自定义注解实现日志打印
一.Maven依赖
二.ControllerMethodLog.class自定义注解
三.Spring AOP切面方法的执行顺序
四.ControllerMethodLogAspect.class:用于打印日志的切面定义类 前言 在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时我们一般会打印出Request请求参数和Response响应结果但是如果这些打印日志的代码相对而言还是比较重复的那么我们可以通过什么样的方式来简化日志打印的代码呢
正文 一.Spring AOP Spring AOP 即面向切面是对OOP面向对象的一种延伸。AOP机制可以让开发者把业务流程中的通用功能抽取出来单独编写功能代码。在业务流程执行过程中Spring框架会根据业务流程要求自动把独立编写的功能代码切入到流程的合适位置。
Spring AOP的实现方式
1.JDK动态代理 类对象必须实现接口JDK动态代理背后是借助Java多态的特性因为JDK动态代理生成的class文件已经继承了Proxy而Java是单继承的不能继承目标对象只能实现目标对象涉及向上转型所以是基于JDK动态代理是基于接口的。 JDK动态代理主要涉及两个类 InvocationHandler是一个接口通过实现该接口定义横切逻辑并通过反射机制调用目标类的代码动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建 一个符合某一接口的实例生成目标类的代理对象。 2.Cglib动态代理 Cglib是一个强大的高性能高质量的代码生成类库 可以在运行期扩展 Java 类与实现 Java 接口CgLib 封装了asm可以再运行期动态生成新 的 class。 特别要注意的是 目标类实现接口的情况下使用JDK动态代理没有实现接口的情况下使用Cglib动态代理。可以使用ProxyTargetClass true,强制所有都使用Cglib动态代理。Cglib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少有研究表明大概要高10倍但是Cglib在创建对象的时候所花费的时间却比JDK动态代理要多很多有研究表明大概有8倍的差距对于singleton的代理对象或者具有实例池的代理因为无需频繁的创建代理对象所以比较适合采用Cglib动态代理反正则比较适用JDK动态代理。 使用AOP主要的应用场景 Authentication 权限检查Caching 缓存Context passing 内容传递Error handling 错误处理Lazy loading 延迟加载Debugging 调试logging, tracing, profiling and monitoring日志记录跟踪优化校准Performance optimization性能优化效率检查Persistence 持久化Resource pooling资源池Synchronization同步Transactions 事务管理 SpringBoot通过自定义注解实现日志打印 一.Maven依赖
!--lombok--
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.2/versionoptionaltrue/optional
/dependency!--Spring AOP--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency二.ControllerMethodLog.class自定义注解
Retention: 用来修饰注解是注解的注解称为元注解。 Target:用来说明对象的作用范围 Documented:用来做标记使用
/**
* 自定义注解用于打印Controller层方式日志
*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface ControllerMethodLog {
} 这里特别讲一下Retention按生命周期来划分可分为3类 RetentionPolicy.SOURCE注解只保留在源文件当Java文件编译成class文件的时候注解被遗弃运行时去动态获取注解信息RetentionPolicy.CLASS注解被保留到class文件但jvm加载class文件时候被遗弃这是默认的生命周期在编译时进行一些预处理操作RetentionPolicy.RUNTIME注解不仅被保存到class文件中jvm加载class文件之后仍然存在做一些检查性的操作 这3个生命周期分别对应于Java源文件(.java文件) — .class文件 — 内存中的字节码。
三.Spring AOP切面方法的执行顺序 这里简单介绍一下切面的执行方法和其执行顺序 Around 通知方法将目标方法封装起来Before 通知方法会在目标方法调用之前执行After 通知方法会在目标方法返回或者异常后执行AfterReturning 通知方法会在目标方法返回时执行Afterthrowing 通知方法会在目标方法抛出异常时执行 这里以一个返回正常的情况为例异常替换最后一步即可 四.ControllerMethodLogAspect.class:用于打印日志的切面定义类
注意要在启动类扫描这个class并且添加 EnableAspectJAutoProxy(proxyTargetClass true)
Slf4j
Component
Aspect
public class ControllerMethodLogAspect {Pointcut(annotation(com.xiyuan.demo.annotation.ControllerMethodLog))public void pointCut() {}/*** 在切点运行前执行该方法*/Before(pointCut())public void doBefore(JoinPoint joinPoint) {MethodSignature signature (MethodSignature) joinPoint.getSignature();Method method signature.getMethod();ControllerMethodLog annotation method.getAnnotation(ControllerMethodLog.class);if (Objects.isNull(annotation)) {return;}String methodName method.getDeclaringClass().getSimpleName() . method.getName();log.info(start {}入参{}, methodName, JSON.toJSONString(joinPoint.getArgs()));}/*** 在切点运行后,无异常时执行该方法** param joinPoint* param result*/AfterReturning(value pointCut(), returning result)public void afterReturn(JoinPoint joinPoint, Object result) {MethodSignature signature (MethodSignature) joinPoint.getSignature();Method method signature.getMethod();ControllerMethodLog annotation method.getAnnotation(ControllerMethodLog.class);if (Objects.isNull(annotation)) {return;}String methodName method.getDeclaringClass().getSimpleName() . method.getName();log.info(end {}响应{}, methodName, JSON.toJSONString(result));}}验证 getUserById根据id获取用户的信息
GetMapping(/getUserById)
ApiOperation(value 根据用户id获取用户)
ControllerMethodLog
public ResponseResult getUserById(RequestParam(name id, required true) String id) {UserInfoPojo userInfoPojo userService.getUserById(id);return ResponseResult.success(userInfoPojo, ConstantsUtil.QUERY_SUCCESS);
}Swagger接口信息如下 IDEA控制台打印信息如下