Spring Aop 底层责任链思路实现

责任链模式实现方式以及在业务中的运用 我们在平常业务开发或者深入了解一些框架实现时,经常会看到责任链模式的运用。责任链模式,通俗来讲,是若干个处理器组成一条链,当收到请求时,依次经过每个处理器,每个处理器只负责单独的一块逻辑。实现责任链模式有很多种方式,我们由浅入深,共同来探讨如何来实现责任链模式。 考虑一个场景,当我们接受一个用户请求,需要先做登录验证、权限验证、业务验证等许多验证,然后再做业务处理。我们首先想到的是将登录、权限、业务这些验证抽象成一个个过滤器,类似于这样: public interface Filter { void 阅读详情

动手AOP责任链实现

简单了解 AOP

Spring 的两个重要特性之一 AOP 面向切面编程

image-20230204155405588

它的作用简单来说就是解耦 可以通过代理类的方式实现在不改变类本身的代码的情况下做到功能上的增强 , 了解它能做些什么我们就可以去思考怎么去实现它 , 这里涉及到责任链模式 (后续在细说) 。

想要去实现简单的aop 我们至少要做到 :

  • 拥有目标类
  • 动态代理目标类
  • 自定义通知方法

在实现aop 之前呢 我们需要简单复习一些前置知识 在复习之前 确认使用的依赖和版本 避免demo出现意外的bug

Java版本 : 1.8

Maven 版本 : 3.6.x

依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>

动态代理(代理目标类)

了解代理,我们需要复习一下代理的知识。

目前来看 代理分为两种 ,用文字就可以很简单的讲述静态代理和动态代理。

  • 静态代理可以实现代理 但是受限制于抽象类,无法去代理抽象类之外的对象
  • 动态代理依赖反射机制 可以实现对任何类的代理

创建目标类

我们就用Userservice 来作为我们的代理目标类

public class UserService {
    
    public Object insert  ()
    {
        System.out.println("==插入用户成功==");
        return "user insert ok";
    }
    
}

创建代理工厂

这里我们使用cglib 来作为动态代理的方式, 其实通过实现动态代理的支持类我们就可以实现简单的 aop 增强 ,

代码案例

public class ProxyFactory implements MethodInterceptor {
    private Object target;

    public UserService getProxy(Object target){
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //执行目标方法
        Object result = null;

        try {
            //前置通知
            System.out.println("前置通知");
             result = method.invoke(target, objects);

            //    返回通知
            System.out.println("返回通知");
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常通知");
            throw new RuntimeException(e);
        } finally {
        //    后置通知
            System.out.println("后置通知");
        }

        return result;
    }
}

测试
public class Run {
    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.insert();
        UserService userService1 = new ProxyFactory().getProxy(userService);
        userService1.insert();

    }
}

image-20230204163324899

只要我们在 标有注释的地方添加代码 是不是简单的切面增强就成了 ,这个时候就会有一个需要思考的问题, 想想我们在Spring 中使用的AOP,在标注切面和增强注解的情况下,Spring才帮我们去实现切面增强 。

所以到这里才是刚刚开始 ,我们使用AOP 的本意是什么 解耦 如果想上面案例这样写的话 岂不是掩耳盗铃, 本类解耦了 代理工厂耦合又高了起来 完全没有达到效果 所以接下来 我们要去解决这个问题

  • 提供灵活性
  • 解耦合
  • 是不是可以使用设计模式来解决问题呢

责任链模式

我们希望使用设计模式来增加我们自己demoAOP 的 灵活性,这里简单的介绍一下责任链模式

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

PS: 递归

image-20230204164417938

那我们实现责任链模式的结构是什么呢?

image-20230204164549365

这里我们实现前置增强来演示 责任链模式的上手思路

责任链

我们用递归的方式来做通知的不断调用

public class Chian {

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    public Chian(List<BaseAdvice> adviceList) {
        this.adviceList = adviceList;
    }

    public Object proeccd() throws Throwable{
        if(index == adviceList.size()-1){
            System.out.println("==执行目标方法==");
            return null;
        }
        return  adviceList.get(++index).execute(this);
    }
}

增强通知基类

public abstract class BaseAdvice {

    public abstract Object execute(Chian chian) throws Throwable;

}

前置增强类

public class BeforeAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知");
        //调用链通知
        return   chian.proeccd();
    }
}

测试

public static void main(String[] args) throws Throwable {
     List<BaseAdvice> adviceList = new ArrayList<>();
    adviceList.add(new BeforeAdvice());
    Chian chian = new Chian(adviceList);
    chian.proeccd();
}

image-20230204170548913

可以看出来结果是与之前的代理方法结果是一致的,通过链式调用+递归来完成目标解耦并且增加灵活性

实现AOP

增强实现

四种增强 这里没有实现环绕增强,因为环绕相当于是其他增强的组合

基类

public abstract class BaseAdvice {

    public abstract Object execute(Chian chian) throws Throwable;

}

四种增强类

前置增强

public class BeforeAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知(责任链)");
        //调用链通知
        return   chian.proeccd();
    }
}

后置增强

public class AfterAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {

        try {
            return chian.proeccd();
        } finally {
            System.out.println("后置增强");
        }
    }
}

异常处理增强

public  class ThrowAdvice extends  BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        try {
            return chian.proeccd();
        } catch (Throwable e) {
            System.out.println("异常通知");
            throw new RuntimeException(e);
        }

    }
}

返回处理增强通知

public class ReturnAdvice extends BaseAdvice{
    @Override
    public Object execute(Chian chian) throws Throwable {
        //如果没有异常就走返回通知
        Object value = chian.proeccd();
        System.out.println("返回通知");
            return value;
    }
}

责任链实现

用链表+递归实现责任链,用链表数据结构的特点 来节点调节点执行增强

public class Chian {

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    //目标方法
    private Method method;

    //方法参数
    private  Object[] args;
    //目标对象
    private  Object target;

    public Chian(List<BaseAdvice> adviceList) {
        this.adviceList = adviceList;
    }

    public Chian(List<BaseAdvice> adviceList, Method method, Object[] args, Object target) {
        this.adviceList = adviceList;
        this.method = method;
        this.args = args;
        this.target = target;
    }

    public Object proeccd() throws Throwable{
        if(index == adviceList.size()-1){
            return method.invoke(args,target);
        }
        return  adviceList.get(++index).execute(this);
    }
}

代理类实现

public class ProxyFactoryAddChian implements MethodInterceptor {
    private Object target;
    private List<BaseAdvice> adviceList;

    public ProxyFactoryAddChian() {
        adviceList = new ArrayList<>();
        adviceList.add(new BeforeAdvice());
        adviceList.add(new ReturnAdvice());
        adviceList.add(new AfterAdvice());
        adviceList.add(new ThrowAdvice());
    }

    public UserService getProxy(Object target){
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //在生产代理的时候就把链设置好
        Chian chian = new Chian(adviceList,method,objects,target);
        return chian.proeccd();
    }
}

测试

public class Run {
    public static void main(String[] args) throws Throwable {
        UserService userService = new UserService();
        //userService.insert();
        UserService userService1 = new ProxyFactoryAddChian().getProxy(userService);
        userService1.insert("编程导航小冷Demo");
    }
}

image-20230204195338199

总结

实现增强功能其实我们就是将输出语句的位置都换成想要实现的代码就可以了,可能看起来有些疑问 ,这和spring的AOP并不是完全像,那是因为 AOP 有部分是有ioc的参与的 但是很巧,我们之前实现过ioc

如果这个系列更新的还好的话 之后可以尝试做个小型的Spring。 和小冷一起读spring源码在去根据自己想想怎么用自己的思路去实现。

那么这次的责任链动手实践 我们都学到了什么呢 ?

  • 责任链模式的应用
  • 递归的运用
  • 学习到类优秀框架源码的思路
  • 获得一个半成品的aopdemo

希望大伙可以继续观看小冷的技术文章 一起进步 你们的观看可以给予小冷莫大的鼓励

谢谢观看 请期待下一篇

Spring事务与AOP原理深度解析:从注解到动态代理的实现机制 在Java企业级开发中,面向切面编程(AOP)是一种重要的设计范式,其核心思想是将横切关注点(如事务管理、日志记录)从核心业务逻辑中分离,实现代码的解耦与复用。AOP通过动态代理技术,在不修改源代码的情况下,为方法调用添加额外行为,这一机制正是Spring框架实现声明式事务管理的基石。Spring事务的本质是利用AOP拦截目标方法,在方法执行前后自动处理事务的开启、提交与回滚,从而将开发者从繁琐的模板代码中解放出来。这种设计不仅提升了代码的整洁度,还确保了事务的一致性与可靠性。在实际应用中,Spring事务 阅读详情

相关推荐

Spring AOP环绕通知:原理、核心应用与深度避坑指南

面向切面编程(AOP)是Spring框架中用于处理横切关注点的核心技术,它通过将通用逻辑(如日志、事务)与业务逻辑分离,提升了代码的模块化和可维护性。其核心原理是基于动态代理或字节码增强,在运行时将通知织入到目标方法的连接点。这项技术的核心价值在于实现了关注点分离,让开发者能够集中处理系统级的通用功能。在实际工程中,AOP被广泛应用于性能监控、声明式事务管理、安全控制和缓存等场景。环绕通知(@Around)作为Spring AOP中最强大的通知类型,它本质上是一个可编程的方法拦截器,能够完全控制目标方法的执

weixin_30954265的博客 317

spring aop学习9:Aop的链式调用(责任链模式)

一.责任链模式 1.基本的责任链模式 ◆主体父类:abstract class Subject.javapackage com.tiglle.responsibility.chain.model; //主体 public abstract class Subject { private Subject successor; protected abstract void handle

Tiglle的博客 4873

SpringAOP之探秘(动态代理、责任链模式、注解使用)

SpringAOP之探秘(动态代理、责任链模式、注解使用)- 详情:https://blog.youkuaiyun.com/Dream_Weave/article/details/85008674

Spring AOP中的责任链设计模式

前面简单的写了下Spring AOP中是怎么实现动态代理的,简单的来说是通过bean对象的后置管理器对实例化的bean对象做判断后使用不同的动态代理方式,下面来看一下生成的动态代理是怎么执行的。

李永志的博客 1620

人大金仓集群部署(主备)

4.2 上传安装包镜像和授权文件到install目录下并授权。1、复制系统脚本到/opt/kingbase目录下(主节点)4.2 修改cluster_install.sh。回车进行下一步,直到出现以下界面,回复Y键回车。三、安装kingbase客户端段(都要安装)install目录作为安装包具体存放目录。4.1 修改install.conf文件。2、复制授权文件到安装目录下(主节点)3、修改ssh参数(节点都要配置)5、安装kingbase客户端。二、基本环境配置(都要配置)6、数据库集群安装(主节点)

edutech_wang的博客 1996

YOLOv11 网络结构详解:一文看懂 Backbone、Head、C3k2、SPPF 和 Detect 检测头

在使用 YOLOv11 进行目标检测时,我们经常会接触到或这样的模型配置文件。backbone和head分别是什么意思?ConvC3k2SPPFC2PSA这些模块分别起什么作用?P3/8、P4/16、P5/32 代表什么?为什么最后 Detect 要同时接收 3 个不同尺度的特征图?YOLOv11n、YOLOv11s、YOLOv11m、YOLOv11l、YOLOv11x 的区别在哪里?

learnerYC的博客 1815

SpringAOP中责任链模式的原理浅析(自己动手实现一个简易的责任链与SpringAOP源码学习)

2021.4.18 本文参考博客: 点击查看原文 根据其原文用代码实现,并作图理解。 目录责任链模式自己简单实现一个责任链模式分析代码 责任链模式 一个对象被多个拦截器拦截处理时,我们称这样的设计模式为责任链模式。 重点是其中在多个拦截器中,对象都是同一个,这样做能让处理始终围绕一开始的对象。 责任链模式在Filter过滤器和Spring的Interceptor里面都常常用到。 自己简单实现一个责任链模式 先画出UML的类图,大致的关系如下: 可以看出上面有三个接口,三个实现类。 接口代码分别是: 连接点

安洁莉娅丶的博客 1053

ArcGIS基础:CAD数据转换为GIS数据(符号化显示、数据转换、线转面、空间连接)

1、符号化显示: CAD数据加载进来有很多列表,包含了点【point】、线【polyline】、面【polygon】、标注数据【Annotation】等数据,本次实验我们需要用到的是面数据,也就是.dwgPolygong格式的数据。如下图所示: 把数据加载进来,然后在2处打开属性表,查看CAD数据的属性表,打开后可以发现【layer】图层表示就是地块的用地性质,它就是符号化显示的依据。 我们在数据上右键【属性】,打开图层属性,找到【符号系统】,选择类别中的【唯一值】,然后在【值字段】下拉选择【layer】,

yuanYW7556的博客 2万+

Spring AOP相关知识详解

AOP知识大全(不全)

乾坤未定,你我皆是黑马 1228

无刷电机FOC控制入门:磁场、洛伦兹力与坐标转换详解

本文深入解析无刷电机FOC(磁场定向控制)的核心原理,从电磁学基础的磁场与洛伦兹力出发,详细阐述了如何通过Clarke变换、Park变换等坐标转换技术,将三相交流解耦为直流量进行控制,最终利用SVPWM技术实现平滑、高效的电机驱动。文章旨在帮助开发者理解FOC的物理本质与数学框架,为机器人、无人机等高性能应用奠定基础。

weixin_29306011的博客 267

【开关电源篇】整流及其滤波电路的工作原理和设计指南-超简单解读

半波整流是一种利用二极管的单向导通特性,将交流电转换为直流电的基础电路。它通过“切除”交流电的半个周期,仅保留另外半个周期来实现整流。1 开关电源超快学习思路点击跳转1.1开关电源的原理、结构和实物入门篇-超简单解读点击跳转1.2开关电源的EMI输入电路-超简单解读点击跳转倍压整流适用于需要高电压、小电流的特殊场合,通过电容充放电实现电压倍增。

2301_81299416的博客 2927

互联网架构-Spring5.0源码深度解析-024:SpringBean的Aop通知调用链源码分析

024:SpringBean的Aop通知调用链源码分析1 SpringAop底层调用链源码分析演示2 SpringAop底层源码流程回顾3 循环遍历与递归算法实现的区别4 纯手写SpringAop调用链思路分析5 纯手写SpringAop调用链代码016 纯手写SpringAop调用链代码027 纯手写SpringAop调用链代码03 1 SpringAop底层调用链源码分析演示 课程内容: 1.SpringAop源码分析之通知调用链关系 2.递归算法与循环算法区别 3.基于递归算法+责任链模式实现Spri

枫火的博客 322

从零开始学DAG:用dagitty软件快速构建因果图的5个步骤

本文为初学者提供了使用dagitty软件快速构建因果图的5个实用步骤。通过一个公共卫生研究实例,详细演示了如何从定义核心变量开始,逐步引入混杂、中介和碰撞变量,最终利用dagitty的自动分析功能识别最小充分调整集,从而科学指导研究设计与统计分析,有效提升因果推断的严谨性。

ii567的博客 800

spring-aop

aop概念 AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装...

sinat_34814635的博客 570

12、每日卫星任务规划问题的不同公式

本文探讨了卫星任务规划问题的多种数学公式表示方法,包括传统的整数线性规划(ILP)模型、改进的基于路径的公式、基于集合覆盖的公式以及动态规划公式。通过案例研究比较了不同公式的求解效率和适用场景,并提供了使用Python进行实际求解的操作步骤。最后讨论了进一步优化策略及未来研究方向,旨在为解决卫星任务规划问题提供全面的理论支持和实践指导。

assembly8low的博客 204

银河麒麟桌面系统批量交付:封装自动化ISO镜像,百台装机效率提升10倍

麒麟桌面系统自动化ISO镜像定制摘要 本文详细介绍麒麟桌面版ISO安装镜像的定制方法,通过修改系统文件实现自动化安装部署。主要内容包括:1) 挂载原版ISO并提取文件;2) 使用unsquashfs解压系统文件进行定制化修改,包括添加系统标记配置;3) 配置ky-installer.cfg自动应答文件,设置安装参数如用户名、密码、分区方案等;4) 修改grub引导配置启用自动安装模式。该流程支持磁盘加密、自定义分区、自动登录等功能,生成的定制镜像可满足批量部署需求,显著提升系统安装效率。

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 1508

深入解析Spring AOP底层原理:从代理模式到性能调优实战

面向切面编程(AOP)是一种通过预编译或运行时动态代理,在不修改源代码的情况下为程序统一添加功能的编程范式。其核心原理基于代理模式,通过在方法调用前后插入增强逻辑,实现对横切关注点的模块化管理。这项技术的核心价值在于解耦业务逻辑与通用功能(如日志、事务、权限),提升代码的可维护性和复用性。在Java企业级开发中,Spring AOP作为其主流实现,广泛应用于事务管理、安全控制、性能监控和日志记录等场景。本文将聚焦Spring AOP的底层机制,特别是其默认使用的**JDK动态代理**与可选的**CGLIB代

450

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Spring干货---AOP

springAOP

zhzhxian的博客 204

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

spring aop应用场景_02.面试指南Spring(上)

SpringFramework文章导读IOC/Bean的生命周期AOP事务面试套路对于面试官问的各个问题,我们首先要知道面试官问我们这个问题的目的是什么,他想从我这里得到什么答案,比如很多面试官喜欢问spring源码,其实并不是想要我们去背源码,是想我们遇到spring相关的问题时候可以快速的解决。套路分下面三点:我学习源码的过程是什么样的?通过学习源码,我解决过项目中的哪些问题源码的代...

weixin_39926749的博客 168

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring之AOP(切面思想)

Spring之AOP(切面思想)

小汤圆 157

Java 23 种设计模式:从踩坑到精通 | 代理模式 —— 你的 AOP 就是用代理实现的

摘要:本文深入剖析了 Java 代理模式(Proxy Pattern)的三种实现形态(静态代理、JDK 动态代理、CGLIB 动态代理),并结合 Spring AOP 源码详细解读了代理机制的选择逻辑与自调用失效陷阱。文章从报表查询的性能优化场景切入,不仅涵盖了 MyBatis Mapper、RPC 框架等经典应用,还对比了装饰器模式,梳理了高频面试题,是 Java 开发者掌握“面向切面编程”基石的实战指南。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 1071

【AOP】AOP-面向切面编程 (系统性知识体系全解)

本文从基础认知、核心概念、底层原理、主流实现、工程应用、进阶特性、避坑实践、范式对比8大维度,构建AOP完整的知识体系,覆盖从入门到精通的全链路内容。

小江的记录本 618

spring

在应用开发中用的非常多, @Component注解是一个通用注解,可以用在于任何类上。包括普通java类,业务逻辑组件,持久化对象等等。通过@Component注解spring自动创建该类的实例注入SpringIOC容器中。@Bean是用于配置类中声明一个Bean的,它通常是用于配置类的方法上面,表示把这个方法的返回对象注册到Spring IOC容器中。通过@Bean自定义Bean的创建和初始化过程,包括指定Bean的名称、作用域、依赖关系等。1.用途不同@Component用于标识普通的类。

黑冰[̲̅V̲̅I̲̅P̅] 818

子类重写方法aop切不到_Spring5.0源码深度解析:SpringBean的Aop通知调用链源码分析,小白都能看懂...

点击上方“Java分享吧”,选择“设为星标”优选有价值的技术文献,从我做起源码分析篇章SpringAOP原理探究思考:springAOP底层运用了什么设计模式?生成代理类:代理设计模式、底层五个通知形成调用链采用:责任链设计模式下面我们回顾下SpringAop实现流程:1、配置@EnableAspectJAutoProxy:开启AOP权限2、@Import(AspectJAutoProx...

weixin_39619478的博客 176

Spring深度学习:动态代理源码解析

本文小豪将带大家深度学习Spring动态代理相关知识,包括JDK和Cglib两种动态代理的底层实现原理,以及代理对象回调时拦截链执行过程的源码分析,深入研究动态代理的内部机制,进一步理解面向切面编程的思想,提升我们的架构能力

Code豪客 1252

对线面试官day2-Spring基础,东软医疗java面试题目

2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

2401_83977689的博客 756
上一篇: 图解设计模式: 有趣的工厂模式
下一篇: 重走前端路JS进阶篇:This 指向与箭头函数
冷环渊
博客等级 码龄7年 1130粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷环渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值