Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >读后感 | 美团技术《如何优雅地记录操作日志》

读后感 | 美团技术《如何优雅地记录操作日志》

作者头像
程序猿杜小头
发布于 2022-12-01 13:41:33
发布于 2022-12-01 13:41:33
2.4K00
代码可运行
举报
文章被收录于专栏:程序猿杜小头程序猿杜小头
运行总次数:0
代码可运行

如何优雅地记录操作日志》是美团技术团队2021年最受欢迎的一篇技术文章,文章很有深度,强烈建议大家去品读一番。

操作日志指的是某一时间什么做了什么事情,操作日志一般限定于创建、更新和删除操作,而查询并不是什么敏感操作,所以无需记录操作日志。比如:管理员于2020-10-10 11:12:13新增一个用户,用户名为crimson_typhoon;买家青鸟于2020-10-10 11:12:13更新了联系邮箱,更新前:111111@qq.com,更新后:222222@qq.com等。其实要完整地呈现这一连串信息并不简单,如果大家有一个像我们团队这么好说话的产品经理,咱们也可以简单粗暴些(偷笑),如下所示:

虽然原文已经写的很深入了,但可能受限于篇幅,对方法注解所涉及到的Spring AOP相关知识并没有详细阐述,所以本文将着重叙述这一块内容。笔者参照原文中的思路,初步实现了一个记录操作日志的组件,后续会不断完善;该组件已经发布到maven中央仓库,大家可以体验一下哈,只需要将OperationLog注解标注于业务逻辑层中的相关敏感操作方法之上即可。GAV信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
     <groupId>io.github.dk900912</groupId>
     <artifactId>oplog-spring-boot-starter</artifactId>
     <version>1.0.1</version>
</dependency>

老实说,基于方法注解来实现操作日志是极其优雅的方案,它可以有效收敛横切关注逻辑,避免操作日志的记录逻辑散落在各个业务类中,极大提高了代码的可读性和可维护性。有些老司机可能会觉得直接使用Aspectj就好了,就像下面贴出来的代码那样。的确可以这么做,但后期不易复用,原文还提到了兼容性的问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
@Aspect
public class OperationLogAdvice {
    @Around(value = "@annotation(io.github.oplog.annotation.OperationLog)")
    public Object doOperationLog(ProceedingJoinPoint joinPoint) {
        // STEP 1:执行目标方法
        Object result = null;
        Throwable exceptionOnTraget = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            exceptionOnTraget = e;
        }
        // STEP 2:记录操作日志
        // STEP 3:如果目标方法执行失败,那么需要重新抛出异常
        return result;
    }
}

基于方法注解实现操作日志这一方案需要依赖于Spring AOP,核心思想就是借助Spring AOP去自动探测由OperationLog注解接口标记的业务逻辑类,从而为这些业务类动态创建代理对象。

1 代理对象如何生成

既然Spring AOP是基于代理对象来拓展目标对象的,那就很容易想到:Spring IoC容器内贮存的一定是代理对象而非目标对象,那究竟是如何替换的呢?众所周知,Spring暴露了若干IoC容器拓展点(IoC Container Extensiion Points),BeanPostProcessor接口就是其中之一;有了BeanPostProcessor,任何人都可以在Bean初始化前后对其进行个性化改造,甚至将其替换。

让我们来看一下BeanPostProcessor接口中的内容,它只有两个方法,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface BeanPostProcessor {
    default Object postProcessBeforeInitialization(Object bean, String beanName) 
            throws BeansException {
        return bean;
    }
    default Object postProcessAfterInitialization(Object bean, String beanName) 
            throws BeansException {
        return bean;
    }
}

没错,Spring AOP就是通过BeanPostProcessor将目标对象替换为代理对象的!在Spring AOP中,这个BeanPostProcessor就是AbstractAutoProxyCreator抽象类,其主要用于创建代理对象。AbstractAutoProxyCreator的父子关系如下图所示:

从上图可以看出,Spring AOP为AbstractAutoProxyCreator定义了两个直系子类,分别是:BeanNameAutoProxyCreatorAbstractAdvisorAutoProxyCreator;前者根据Bean的名称来判断是否需要为当前Bean创建代理对象,后者根据Advisor探测结果来判断是否需要为该Bean创建代理对象;何为Advisor?Advisor是Spring AOP中独有的术语,在AspectJ中并没有等效的术语与其匹配,但其与切面还是有一定相似之处的,或者大家干脆将其视为一个特殊的切面,该切面只能包含一个Advice (通知) 和一个Pointcut (切入点) 而已;此外,Advisor有两个分支,分别是PointcutAdvisorIntroductionAdvisor

相较于BeanNameAutoProxyCreator,AbstractAdvisorAutoProxyCreator更为重要,AbstractAdvisorAutoProxyCreator有三个子类,分别是AspectJAwareAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreatorInfrastructureAdvisorAutoProxyCreator。一般,在Spring IoC中只会有一个名称为org.springframework.aop.config.internalAutoProxyCreator、类型为AbstractAdvisorAutoProxyCreator的Bean,如果classpath下没有Spring AOP依赖或者没有aspectjweaver依赖,那么Spring Boot会自动选用InfrastructureAdvisorAutoProxyCreator;否则将会选用AnnotationAwareAspectJAutoProxyCreator。大家可以通过下面这种方式来验证三者的优先级,AnnotationAwareAspectJAutoProxyCreator是优先级最高、最通用的一个。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AutoProxyCreatorPriorityApplication {
    public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
            "org.springframework.aop.config.internalAutoProxyCreator";
    public static void main(String[] args) {
        // STEP 1:构造 BeanDefinitionRegistry
        // STEP 2 3 4 依次向 BeanDefinitionRegistry 中注册三种 AbstractAdvisorAutoProxyCreator BeanDefinition 实例,
        // 但 name 完全一致,即 AUTO_PROXY_CREATOR_BEAN_NAME
        BeanDefinitionRegistry beanDefinitionRegistry = new SimpleBeanDefinitionRegistry();

        // STEP 2:注册 InfrastructureAdvisorAutoProxyCreator BeanDefinition
        AopConfigUtils.registerAutoProxyCreatorIfNecessary(beanDefinitionRegistry);
        BeanDefinition infrastructureAdvisorCreatorBeanDefinition = beanDefinitionRegistry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        System.out.println(infrastructureAdvisorCreatorBeanDefinition.getBeanClassName());

        // STEP 3:注册 AspectJAwareAdvisorAutoProxyCreator BeanDefinition
        AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(beanDefinitionRegistry);
        BeanDefinition aspectJAwareAdvisorCreatorBeanDefinition = beanDefinitionRegistry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        System.out.println(aspectJAwareAdvisorCreatorBeanDefinition.getBeanClassName());

        // STEP 4:注册 AnnotationAwareAspectJAutoProxyCreator BeanDefinition
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(beanDefinitionRegistry);
        BeanDefinition annotationAwareAspectJCreatorBeanDefinition = beanDefinitionRegistry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        System.out.println(annotationAwareAspectJCreatorBeanDefinition.getBeanClassName());
    }
}

InfrastructureAdvisorAutoProxyCreator是如何判断是否需要为当前Bean创建代理对象的呢?

  1. 首先,它会从Spring IoC容器中一次性获取所有Advisor;
  2. 然后,逐一遍历每个Advisor,若当前Advisor所对应的BeanDefinition的Role等于BeanDefinition.ROLE_INFRASTRUCTURE,那么该Advisor就具备候选资质;
  3. 最后,从具备候选资质的Advisor列表中选取与当前Bean匹配的Advisor,如果最终存在相匹配的Advisor,那么就为当前Bean创建代理对象;那么是如何裁定是否匹配的呢?若该Advisor是PointcutAdvisor类型,那么就根据ClassFilter与MethodMatcher去匹配当前Bean;若该Advisor是IntroductionAdvisor类型,那么就根据ClassFilter去匹配当前Bean。

AnnotationAwareAspectJAutoProxyCreator又是如何判断是否需要为当前Bean创建代理对象的呢?这部分逻辑比较复杂,如果想了解详细逻辑,参见笔者之前写的一篇文章《Spring AOP,从入门到进阶》。

  1. 首先,它会从Spring IoC容器中一次性获取所有Advisor (一般,这些Advisor是用户或者开源组件中自定义的),默认这些Advisor具备候选资质,压根不用像InfrastructureAdvisorAutoProxyCreator那样还要具体判断是否具备候选资质,这也从侧面说明:为什么AnnotationAwareAspectJAutoProxyCreator比InfrastructureAdvisorAutoProxyCreator优先级更高;
  2. 然后,它再从Spring IoC容器中获取所有由@Aspect标注的Bean,将这些切面Bean中由@Before、@After和@Around等标注的方法封装成一个PointcutAdvisor列表,至此将步骤一和步骤二中的Advisor组合为一个候选Advisor列表;
  3. 最后,从具备候选资质的Advisor列表中选取与当前Bean匹配的Advisor,如果最终存在相匹配的Advisor,那么就为当前Bean创建代理对象;那么是如何裁定是否匹配的呢?若该Advisor是PointcutAdvisor类型,那么就根据ClassFilter与MethodMatcher去匹配当前Bean;若该Advisor是IntroductionAdvisor类型,那么就根据ClassFilter去匹配当前Bean。

Spring AOP之所以能支持以Aspectj注解风格去定义切面,靠的就是AnnotationAwareAspectJAutoProxyCreator!

代理对象的创建规则已经清晰了,接下来就要搞清楚究竟是如何创建代理对象的。Spring AOP依托JDK动态代理CGLIB代理技术来创建代理对象,关于这方面的知识参见笔者之前写的一篇文章《Java动态代理》,这里就不再赘述了。

理论知识基本介绍完毕,下面进入实战环节。摆在大家面前的第一道坎应该是选取合适的Advisor,究竟是PointcutAdvisor还是IntroductionAdvisor呢?PointcutAdvisor持有一个Advice和一个Pointcut,Spring AOP 将Advice建模为org.aopalliance.intercept.MethodInterctptor拦截器,Pointcut用于声明应该在哪些Joinpoint (连接点) 处应用切面逻辑,而Joinpoint在SpringAOP 中专指方法的执行,因此,PointcutAdvisor中的Advice是方法级的拦截器;IntroductionAdvisor仅持有一个Advice和一个ClassFilter,显然,IntroductionAdvisor中的Advice是类级的拦截器。如果选用IntroductionAdvisor,可我们无法知道哪些类需要拦截啊,相反,如果选用PointcutAdvisor,那就可以借助MethodMatcher中的matches()方法准确拦截持有@OperationLog注解的目标方法。既然认准了PointcutAdvisor,那既可以直接实现PointcutAdvisor接口,也可以继承AbstractPointcutAdvisor,还可以继承AbstractBeanFactoryPointcutAdvisor,怎么搞都行,只要能包住Advice和Pointcut就行。如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class OperationLogPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    private Pointcut pointcut;

    public OperationLogPointcutAdvisor() {
    }

    /**
     * @param pointcut
     * @param advice
     */
    public OperationLogPointcutAdvisor(Pointcut pointcut, Advice advice) {
        this.pointcut = pointcut;
        setAdvice(advice);
    }

    public void setPointcut(Pointcut pointcut) {
        this.pointcut = pointcut;
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}

那么,对于Pointcut又该如何取舍呢?我们期待它的ClassFiler能够匹配所有类,而它的MethodMatcher只需要静态匹配就好了,即MethodMatcher中的isRuntime()方法返回false,这么一合计,StaticMethodMatcherPointcut简直完美契合。如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class OperationLogPointcut extends StaticMethodMatcherPointcut {
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        Annotation operationLogAnnotation = AnnotationUtils.findAnnotation(method, OperationLog.class);
        return Objects.nonNull(operationLogAnnotation);
    }
}

对于Advice呢,直接使用强大的org.aopalliance.intercept.MethodInterceptor接口即可,它可以模拟实现MethodBeforeAdviceAfterReturningAdviceThrowsAdvice等。如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class OperationLogAdvice implements MethodInterceptor {

    private OperatorService operatorService;

    private LogRecordPersistenceService logRecordPersistenceService;

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object result = null;
        Throwable throwable = null;
        try {
            result = invocation.proceed();
        } catch (Throwable e) {
            throwable = e;
        }

        Method method = invocation.getMethod();
        Annotation operationLogAnnotation = AnnotationUtils.findAnnotation(method, OperationLog.class);
        Map<String, Object> operationLogAnnotationAttrMap = AnnotationUtils.getAnnotationAttributes(operationLogAnnotation);
        Operator operator = getOperator();
        BizCategory bizCategory =  (BizCategory) operationLogAnnotationAttrMap.get("bizCategory");
        String bizTarget =  (String) operationLogAnnotationAttrMap.get("bizTarget");
        String operation = String.format("%s %s %s", operator.getOperatorName(), bizCategory.getName(), bizTarget);
        LogRecord logRecord = encapsulateLogRecord(operator, bizTarget, operation, throwable);
        logRecordPersistenceService.doLogRecordPersistence(logRecord);

        if (Objects.nonNull(throwable)) {
            throw throwable;
        }
        return result;
    }
}

万事俱备,将OperationLogPointcutAdvisor声明为一个Bean吧,但千万别遗漏了这么一行:@Role(BeanDefinition.ROLE_INFRASTRUCTURE)。为什么强烈建议加这一行代码呢?当作思考题吧!

2 如何使用oplog-spring-boot-starter

2.1 在启动类中开启记录操作日志开关
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
@EnableOperationLog
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
2.2 实现OperatorService接口

OperatorService是预留接口,主要用于获取当前操作用户。一般,过滤器会提前将用户信息保存在ThreadLocal中,在同一个请求上下文中直接从ThreadLocal中获取即可。

2.3 实现LogRecordPersistenceService接口

LogRecordPersistenceService接口用于设定操作日志的持久化方式,如果大家自行实现LogRecordPersistenceService接口并将其声明为Bean,那么就会采用大家自定义日志持久化方案,否则采用默认的日志持久化方案 (即将操作日志打印到日志文件中) 。之所以这么灵活,是因为组件在声明LogRecordPersistenceService这一默认Bean时,使用了@ConditionalOnMissingBean,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class OperationLogAutoConfigurationImportSelector {
    @Bean
    @ConditionalOnMissingBean(LogRecordPersistenceService.class)
    public LogRecordPersistenceService logRecordPersistenceService() {
        return new DefaultLogRecordPersistenceServiceImpl();
    }
}
2.4 在业务类中的相关方法上追加@OperationLog注解

OperationLog注解接口源码如下,由于这俩属性都没default修饰符,因此它们都是必须显式设定的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface OperationLog {
    /**
     * 操作种类:新增、更新和删除
     */
    BizCategory bizCategory();

    /**
     * 业务对象,如:订单、用户、商品等
     */
    String bizTarget();
}

3 总结

感兴趣的读者可以到github阅读源码。

4 参考文档

  1. https://github.com/dk900912/oplog-spring-boot
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿杜小头 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【小家Spring】Sping AOP中使用到的那些工具类盘点:AopUtils、AopConfigUtils、AspectJAopUtils 、AopProxyUtils、AopContext
Spring AOP框架的代码结构组织得不可为不好,良好的面向对象的编程思想,其中很有一部分得益于它对代码的结构的把控。良好的封装、分层、隔离。而在其中起到重要作用的,便是本文要盘点的一些工具类。
YourBatman
2019/09/03
2.5K0
Spring AOP,从入门到进阶
我们常常在核心业务逻辑中看到诸如事务管理、日志记录或性能统计等行为,这些行为的代码量一般也就几行,但是却分散在多个类中的多个方法内;这些四处分散的重复代码不仅不利于后期的维护工作,同时也显得核心业务逻辑混乱无章。为了解决这一问题,面向切面编程(Aspect-Oriented Programming)应运而生。不同于面向对象编程(Object-oriented Programming),AOP不再以类(Class)为模块化单元,而是以切面(Aspect)作为模块化单元,也就是通过切面来封装那些四处分散的事务管理、日志记录和性能统计等行为。可能有的人会疑惑,可以将这些行为单独封装起来,并不见得一定要使用AOP啊!别杠,单独封装依然无法保持核心业务逻辑的清清爽爽啊,还是会夹杂在一起,不是吗?顺便提一句,横切关注点(Crosscutting Concern),指的就是事务管理、日志记录和性能统计等行为。
程序猿杜小头
2022/12/01
4000
Spring AOP,从入门到进阶
Spring AOP 注解方式源码解析
在上篇文章 Spring AOP 功能使用详解 中,知道了 Sprig AOP 的一个详细用法,现在的看看Spring 中是如何实现的。
Java技术编程
2020/05/20
5310
【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】
Spring AOP作为整个Spring体系最最重要的分支之一,若干技术都是基于它的(比如事务、异步、缓存等)
YourBatman
2019/09/03
3.8K0
【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】
Spring的AOP底层解析
            基于两种动态代理技术,在Spring中进行了封装,封装出来的类叫做ProxyFactory,表示是创建代理对象的一个工厂,使用起来会更加方便。
忧愁的chafry
2022/10/30
5220
Spring的AOP底层解析
SpringAOP学习–SpringAOP简介及原理
前文对AOP做了介绍,实际项目中,一般不会直接上手手动实现aop,而是使用一些高级封装的aop实现,如SpringAOP。 Spring是一个广泛应用的框架,SpringAOP则是Spring提供的一个标准易用的aop框架,依托Spring的IOC容器,提供了极强的AOP扩展增强能力,对项目开发提供了极大地便利。 前文提到AOP的实现有AspectJ、JDK动态代理、CGLIB动态代理,SpringAOP不是一种新的AOP实现,其底层采用的是JDK/CGLIB动态代理。
全栈程序员站长
2022/09/22
3220
SpringAOP学习–SpringAOP简介及原理
Spring AOP 源码分析 - 筛选合适的通知器
从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析。本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出合适的通知器(Advisor)。在上一篇AOP 源码分析导读一文中,我简单介绍了 AOP 中的一些术语及其对应的源码,部分术语和源码将会在本篇文章中出现。如果大家不熟悉这些术语和源码,不妨去看看。 关于 Spring AOP,我个人在日常开发中用过一些,也参照过 tiny-spring 过写过一个玩具版的 AOP 框架,并写成了文章。正因为前面做了一些准备工作,最近再看 Spring AOP 源码时,觉得也没那么难了。所以如果大家打算看 AOP 源码的话,这里建议大家多做一些准备工作。比如熟悉 AOP 的中的术语,亦或是实现一个简单的 IOC 和 AOP,并将两者整合在一起。经过如此准备,相信大家会对 AOP 会有更多的认识。
田小波
2018/08/01
2K0
Spring AOP 源码分析 - 筛选合适的通知器
spring-aop 之 aop:config
文章目录 开头 aop:config 解析 proxy-target-class & expose-proxy aop:pointcut aop:advisor aop:aspect aop:d
MickyInvQ
2021/10/13
1.3K0
【Spring源码】- 10 Spring AOP核心API
Spring的两大核心:IoC和AOP,IoC作为Spring的根基,通过大量的扩展点让系统轻而易举的就可以实现良好的扩展性,而AOP和IoC结合在一起,类似于发生强大化学反应一样,将Spring的功能性又提高了一个层次。Spring中也有大量使用AOP场景,比如@Configuration、数据库事务、mybatis mapper接口注入等等。
Reactor2020
2023/03/22
2820
【Spring源码】- 10  Spring AOP核心API
Spring读源码系列之AOP--05---aop常用工具类学习
Spring AOP框架的代码结构组织得不可为不好,良好的面向对象的编程思想,其中很有一部分得益于它对代码的结构的把控。良好的封装、分层、隔离。而在其中起到重要作用的,便是本文要盘点的一些工具类。
大忽悠爱学习
2022/05/10
1.1K0
Spring读源码系列之AOP--05---aop常用工具类学习
Spring事务是怎么通过AOP实现的
阅读此文章需要掌握一定的AOP源码基础知识,可以更好的去理解事务,我在另外一篇文章有提过。
@派大星
2023/07/15
3250
Spring事务是怎么通过AOP实现的
@Aspect注解背后的奥秘--下
上一篇文章我们减少了aop原始时代中通过ProxyFactory和AspectJProxyFactory手动创建代理对象的过程,本文我们来探究一下新生代中aop自动化是如何实现的。
大忽悠爱学习
2023/02/26
1.2K0
@Aspect注解背后的奥秘--下
SpringAop源码分析(基于注解)二:筛选通知器
我们已经知道BeanPostProcessors是在Bean实例化前后起作用的,如果看过前面的文章Spring Ioc源码分析 之 Bean的加载(八):初始化,应该知道Spring是在AbstractAutowireCapableBeanFactory#doCreateBean() 方法中有一个初始化Bean的方法:
周同学
2019/10/24
1K0
【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理
上篇文章: 【小家Spring】Spring-jdbc的使用以及Spring事务管理的8种方式介绍(声明式事务+编程式事务) 介绍了Spring事务的众多使用方式,其中讲到全注解@Transactional方式的时候一笔带过了,那么本文就以当下最流行的Spring事务的使用方式:全注解的@Transactional使用方式为切入点,扒开Spring事务管理的神秘面纱~
YourBatman
2019/09/03
1.5K0
一文搞懂Spring-AOP原理
文章目录 1. 简介 2. 添加依赖 3. 通知 4. 连接点 5. 切点 6. 切面 7. 实现 8. 注解的实现 9. 切入点表达式 10. 切面执行顺序(Order) 10.1. 注意点 11. Aspect实例化模型 12. 获取参数(args) 13. PointCut 14. PointCuts 15. ClassFilter 16. ClassFilters 17. MethodMatcher 18. MethodMatchers 19. Advice 20. Advisor 20.1.
爱撒谎的男孩
2019/12/31
1.1K0
Spring Transaction,从入门到上瘾
Spring Transaction 针对JDBC API中关于事务管理这一部分进行了高级抽象,它支持两种方式的事务管理,分别是:声明式事务管理 (Declarative Transaction Management) 与 编程式事务管理 (Programmatic Transaction Management) 。声明式事务管理由@Transactional注解来承载,而编程式事务管理则由TransactionManager或TransactionTemplate来实现 (推荐使用后者) 。基于注解的声明式事务管理方式既简洁又优雅,可以有效收敛横切关注逻辑,但极尽简洁的背后却也暗藏陷阱,比如:大事务、事务未正常回滚等。相较于声明式事务管理,编程式事务管理方式对事务粒度的把控更为灵活,这往往很有必要!
程序猿杜小头
2022/12/01
6400
Spring Transaction,从入门到上瘾
(六)Spring源码解析:Spring AOP源码解析
当我们对某些类有横切性的逻辑时,为了不破坏目标类,我们则可以使用AOP的方式将增强逻辑注入到目标类上。为了更清晰的了解AOP的用法,下面我们通过一个使用案例,实现一下面向切面编程。
爪哇缪斯
2023/09/06
8180
(六)Spring源码解析:Spring AOP源码解析
Spring 事务初始化源码分析
在上篇文章 Spring 事务使用详解 中详细介绍了 Spring 事务的使用过程,今天就来看下 Spring 事务是如何来实现,比如 Spring 事务在初始化的时候做了什么,Spring 事务是如何进行事务的提交和回滚的;为了避免篇幅太长,所以分开两篇文章进行分析,这篇文章先来分析下 Spring 事务是如何初始化的,在初始化的时候做了什么。
Java技术编程
2020/05/20
4850
Spring AOP 原理源码深度剖析
概述 AOP(Aspect-Oriented Programming) 面向切面编程。Spring Aop 在 Spring框架中的地位举足轻重,主要用于实现事务、缓存、安全等功能。本篇主要是对源码进行深度分析。
方志朋
2019/06/21
1.1K0
Spring事务AOP实现原理
此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理。
用户4283147
2022/10/08
5230
Spring事务AOP实现原理
推荐阅读
相关推荐
【小家Spring】Sping AOP中使用到的那些工具类盘点:AopUtils、AopConfigUtils、AspectJAopUtils 、AopProxyUtils、AopContext
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验