如何动态修改 spring aop 切面信息?让自动日志输出框架更好用

news2024/11/23 17:19:19

业务背景

很久以前开源了一款 auto-log 自动日志打印框架。

其中对于 spring 项目,默认实现了基于 aop 切面的日志输出。

但是发现一个问题,如果切面定义为全切范围过大,于是 v0.2 版本就是基于注解 @AutoLog 实现的。

只有指定注解的类或者方法才会生效,但是这样使用起来很不方便。

如何才能动态指定 pointcut,让用户使用时可以自定义切面范围呢?

在这里插入图片描述

自定义注解切面原理

常规 aop 方式

@Aspect
@Component
@EnableAspectJAutoProxy
@Deprecated
public class AutoLogAop {

    @Pointcut("@within(com.github.houbb.auto.log.annotation.AutoLog)" +
            "|| @annotation(com.github.houbb.auto.log.annotation.AutoLog)")
    public void autoLogPointcut() {
    }

    /**
     * 执行核心方法
     *
     * 相当于 MethodInterceptor
     *
     * @param point 切点
     * @return 结果
     * @throws Throwable 异常信息
     * @since 0.0.3
     */
    @Around("autoLogPointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 日志增强逻辑
    }

}

发现这里的 @Pointcut 注解属性是一个常量,无法方便地动态修改。

于是去查资料,找到了另一种更加灵活的方式。

可以指定 pointcut 的方式

我们通过 @Value 获取属性配置的切面值,给定默认值。这样用户就可以很方便的自定义。

/**
 * 动态配置的切面
 * 自动日志输出 aop
 * @author binbin.hou
 * @since 0.3.0
 */
@Configuration
@Aspect
//@EnableAspectJAutoProxy
public class AutoLogDynamicPointcut {

    /**
     * 切面设置,直接和 spring 的配置对应 ${},可以从 properties 或者配置中心读取。更加灵活
     */
    @Value("${auto.log.pointcut:@within(com.github.houbb.auto.log.annotation.AutoLog)||@annotation(com.github.houbb.auto.log.annotation.AutoLog)}")
    private String pointcut;

    @Bean("autoLogPointcutAdvisor")
    public AspectJExpressionPointcutAdvisor autoLogPointcutAdvisor() {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(pointcut);
        advisor.setAdvice(new AutoLogAdvice());
        return advisor;
    }

}

当然,这里的 Advice 和以前的 aop 不同,需要重新进行实现。

AutoLogAdvice

只需要实现 MethodInterceptor 接口即可。

/**
 * 切面拦截器
 *
 * @author binbin.hou
 * @since 0.3.0
 */
public class AutoLogAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 增强逻辑
    }

}

介绍完了原理,我们一起来看下改进后的日志打印组件的效果。

spring 整合使用

完整示例参考 SpringServiceTest

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>auto-log-spring</artifactId>
    <version>0.3.0</version>
</dependency>

注解声明

使用 @EnableAutoLog 启用自动日志输出

@Configurable
@ComponentScan(basePackages = "com.github.houbb.auto.log.test.service")
@EnableAutoLog
public class SpringConfig {
}

测试代码

@ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void queryLogTest() {
        userService.queryLog("1");
    }

}
  • 输出结果
信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) param is [1]
五月 30, 2020 12:17:51 下午 com.github.houbb.auto.log.core.support.interceptor.AutoLogMethodInterceptor info
信息: public java.lang.String com.github.houbb.auto.log.test.service.impl.UserServiceImpl.queryLog(java.lang.String) result is result-1
五月 30, 2020 12:17:51 下午 org.springframework.context.support.GenericApplicationContext doClose

切面自定义

原理解释

spring aop 的切面读取自 @Value("${auto.log.pointcut}"),默认为值 @within(com.github.houbb.auto.log.annotation.AutoLog)||@annotation(com.github.houbb.auto.log.annotation.AutoLog)

也就是默认是读取被 @AutoLog 指定的方法或者类。

当然,这并不够方便,我们希望可以想平时写 aop 注解一样,指定 spring aop 的扫描范围,直接在 spring 中指定一下 auto.log.pointcut 的属性值即可。

测试例子

完整测试代码

我们在配置文件 autoLogConfig.properties 中自定义下包扫描的范围:

auto.log.pointcut=execution(* com.github.houbb.auto.log.test.dynamic.service.MyAddressService.*(..))

自定义测试 service

package com.github.houbb.auto.log.test.dynamic.service;

import org.springframework.stereotype.Service;

@Service
public class MyAddressService {

    public String queryAddress(String id) {
        return "address-" + id;
    }

}

自定义 spring 配置,指定我们定义的配置文件。springboot 啥的,可以直接放在 application.properties 中指定,此处仅作为演示。

@Configurable
@ComponentScan(basePackages = "com.github.houbb.auto.log.test.dynamic.service")
@EnableAutoLog
@PropertySource("classpath:autoLogConfig.properties")
public class SpringDynamicConfig {
}

测试

@ContextConfiguration(classes = SpringDynamicConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringDynamicServiceTest {

    @Autowired
    private MyAddressService myAddressService;

    @Autowired
    private MyUserService myUserService;

    @Test
    public void queryUserTest() {
        // 不会被日志拦截
        myUserService.queryUser("1");
    }

    @Test
    public void queryAddressTest() {
        // 会被日志拦截
        myAddressService.queryAddress("1");
    }

}

开源地址

为了便于大家学习,项目已开源。

Github: https://github.com/houbb/auto-log

Gitee: https://gitee.com/houbinbin/auto-log

小结

这个项目很长一段时间拘泥于注解的方式,我个人用起来也不是很方便。

最近才想到了改进的方法,人还是要不断学习进步。

关于日志最近还学到了 aspect 的编译时增强,和基于 agent 的运行时增强,这 2 种方式都很有趣,有机会会做学习记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/781570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytest常用执行参数详解

1. 查看pytest所有可用参数 我们可以通过pytest -h来查看所有可用参数。 从图中可以看出&#xff0c;pytest的参数有很多&#xff0c;下面是归纳一些常用的参数&#xff1a; -s&#xff1a;输出调试信息&#xff0c;包括print打印的信息。-v&#xff1a;显示更详细的信息。…

GAN在图像超分辨领域的应用

本篇博客介绍了对抗生成网络GAN在图像超分辨领域的应用&#xff0c;包括(SRGAN, ESRGAN, BSRGAN, Real-ESRGAN),详细介绍了论文内容&#xff0c;方法&#xff0c;网络结构并对其做了相关总结。相关GAN原理的介绍大家可以查看我之前的几篇博客&#xff0c;链接如下&#xff1a;生…

从用户的角度谈GPT时代技术突破的两大关键逻辑

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

API接口:如何通过使用手机归属地查询

随着手机普及率的不断增加&#xff0c;手机号码的信息查询也成为了一个非常实用的功能。本文将介绍如何通过使用手机归属地查询API接口实现查询手机号码所在地的功能。 首先&#xff0c;我们需要一个可以查询手机号码所在地的API接口。目前市面上有很多免费或付费的API接口可供…

MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点6:MySQL Enterprise Monitor之Query Analyzer

文章目录 MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点6&#xff1a;MySQL Enterprise Monitor之Query AnalyzerMySQL Enterprise Monitor之Query AnalyzerQuery Response Time index (QRTi)例题例题1: Query Analyzer答案与解析1 参考 【免责声明】文章仅供学习交流&#x…

RT1052的GPIO

文章目录 GPIO资源GPIO资料GPIO复用器IOMUXGPIO的控制块 GPIO配置宏定义的使用 GPIO函数使用GPIO_PinRead 函数GPIO_WritePinOutput函数 GPIO资源 图中 P2、P3 和 P6 为 MCU 主 IO 引出口&#xff0c;这三组排针共引出了 97 个 IO 口&#xff0c;另外&#xff0c;通过&#xff…

深度理解BeanFactory和ApplicationContext的区别

BeanFactory和ApplicationContext 接口及其子类图 这是Spring一部分的关系类图,从这个类图我们可以大致看出BeanFactory的和ApplicationContext的关系,BeanFactory是ApplicationContext的基类,BeanFactory所拥有的功能,ApplicationContext都拥有, 不仅如此,ApplicationContext还…

【Docker 的数据管理和网络通信】

目录 一、Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器 二、容器互联&#xff08;使用centos镜像&#xff09;三、Docker 镜像的创建1&#xff0e;基于现有镜像创建&#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改&#xff08;2&#x…

C# Yolo+Onnx 号牌识别

参考 https://github.com/missxingwu/net_yolov5_plate https://github.com/ivilson/Yolov7net https://github.com/we0091234/Chinese_license_plate_detection_recognition 效果 项目 VS2022.net 4.8OpenCvSharp4Microsoft.ML.OnnxRuntime 部分代码 using System; using …

xDS解决的是什么样子的痛点

xDS基本概念 Istio发现模型 xDS是什么 xDS是一类发现服务的总称&#xff0c;包含LDS&#xff0c; RDS&#xff0c; CDS&#xff0c; EDS以及SDS。 Envoy通过xDS API可以动态获取Listener&#xff08;监听器&#xff09;&#xff0c;Route&#xff08;路由&#xff09;&#x…

Python 集合 union()函数使用详解,Python合并集合

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 union函数使用详解 1、合并多个集合2、合并其他类型2.1、合并字符串2.2、合并列表…

性能测试Ⅲ

JMeter里面使用后端监听器&#xff0c;结合influxdb的时序数据库以及grafana可以打造性能测试的平台 后端监听器&#xff1a;把JMeter执行过程中的数据写到influxDB的时序数据库 influxD&#xff1a;时序数据库&#xff0c;用来存储JMeter发送请求的数据 Grafana &#xff1a;从…

k8s容器入门

一、k8s入门 1.什么是容器 降低虚拟机造成的物理主机资源浪费&#xff0c;提高物理主机的利用率&#xff0c;并能提供像虚拟机一样狼好的应用程序隔离运行环境&#xff0c;人们把这种轻量型的虚拟机&#xff0c;称为容器。 2. 容器的管理工具 主要用于容器的创建、启动、关…

优化transformer

使用transformer而导致的时间长&#xff0c;可能会由于self-attention计算Query和key的值才导致的时间长&#xff0c;也可能会因为feed forward中的计算导致时间长。这里我们只针对第一种情况下进行优化。 第一种情况&#xff1a;有些问题&#xff0c;我们可能不需要看整个句子…

Linux安装JDK、Redis、MySQL、RabbitMQ、Minio、Nginx.......

文章目录 一、环境准备二、安装JDK三、安装MySQL四、安装Redis三、安装RabbitMQ四、安装Minio五、安装Nginx特殊情况处理Centos7挂载磁盘服务器时间同步MySQL数据库时间同步安装解压软件修改数据库SQL模式 一、环境准备 下载镜像源 中科大镜像源下载至/opt目录下修改yum源为中…

蓝桥杯专题-真题版含答案-【贪吃蛇长度】【油漆面积】【绘制圆】【高次方数的尾数】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

微服务初始

今天准备开始学习微服务&#xff0c;使用微服务肯定是因为他有好处。 首先了解到的三种架构&#xff0c;传统单体&#xff0c;集群架构&#xff0c;微服务架构 单体架构 有单点问题&#xff0c;如果宕机所有的服务都不可用所有业务的功能模块都聚集在一起&#xff0c;如果代…

POSTGRESQL PERPARE 事务提交方式,到底用还是不用

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

单Bank OTA升级:STM32G071 APP (二)

接上一篇文章&#xff1a;单Bank OTA升级&#xff1a;STM32G071 BootLoader (一)&#xff1a;跳转链接 什么是单Bank升级&#xff1a;将Flash划分为以下3个区域。 BootLoader区&#xff1a;程序进行升级的引导程序&#xff0c;根据Upade_Flag来判断跳转Bank区运行程序或是接收…

spring复习:(52)注解方式下,ConfigurationClassPostProcessor是怎么被添加到容器的?

进入AnnotationConfigApplicationContext的构造方法&#xff1a; 进入AnnotatedBeanDefinitionReader的构造方法&#xff1a; 进入this(registry, getOrCreateEnvironment(registry));代码如下&#xff1a; 进入AnnotationConfigUtils.registerAnnotationConfigProcessors方…