自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

Apple_Boy的博客

吃苹果的程序员

  • 博客(320)
  • 资源 (1)
  • 收藏
  • 关注

原创 值得你收藏的类加载、初始化、实例化、加载时机,初始化时机...

文章目录类加载机制类加载机制分类、类加载器、双亲委派机制类加载机制分类类加载器双亲委派机制加载.class文件的方式类生命周期类生命周期结束类加载过程JVM初始化步骤类加载时机类初始化时机类的初始化类的实例化平常总是对类的加载,初始化,实例化,类加载机制。。。等等概念容易搞混,这里记录一下!类加载机制虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型的过程就是虚拟机的 类加载机制。类加载机制分类、类加载器、双亲委派机制

2020-08-29 15:20:21 9420 4

原创 全网最全解析!Spring与非Spring环境下获取动态代理对象的原始目标对象

为什么这个userSerivce代理对象里面又是一个CGLIB$CALLBACK_0变量???为什么这个userMapper代理对象里面是一个h变量???关于这个问题的话,我在之前的文章中其实已经讲到了,这里面涉及到了两种动态代理的原理,可以看我之前文章深入探索JDK动态代理:从入门到原理的全面解析探索Cglib:解析动态代理的神奇之处今天我们不讨论这个问题,我们讨论另外一个问题,如何获取这两种动态代理对象里面的原始目标对象???

2024-04-01 20:59:31 1066

原创 深入探索JDK动态代理:从入门到原理的全面解析

为了调试目的,我们要查看或修改这些动态生成的代理类,正常我们还需要反编译工具(比如JD-GUI或JAD)来查看生成的类的源代码,但是我们不用那么麻烦,直接用IDEA打开即可。在标准的Java JDK实现中,生成的动态代理类(字节码)默认是在内存中动态生成并直接加载的,不会写入磁盘成为文件。现在,我们可以编写一个测试类来验证动态代理的使用,这个例子中,我们通过动态代理实现了一个代理对象,当调用代理对象的方法时,会先执行。添加了这个系统属性后,当创建动态代理实例的时候,JVM会将生成的代理类以。

2024-03-24 21:20:42 1077

原创 简单!实用!易懂!:Java如何批量导出微信收藏夹链接-->转换成Markdown/txt

如果手动一个个导的话非常麻烦,操作步骤如下:2、提取链接:使用鼠标右键点击链接,然后选择“复制地址”3、导出链接:将复制的链接地址粘贴到一个文本文件中,每个链接一行。4、为每个链接进行命名:从微信复制出来的链接,没有名字只有单纯的URL链接,你都不知道这个链接是什么,很不友好,所以还得打开链接,复制标题,类似这样的格式近日择机发射!!!

2024-03-17 18:50:18 895

原创 探索Cglib:解析动态代理的神奇之处

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供方法的interception(拦截)。

2024-03-09 19:18:37 791

原创 源码透析MapperScannerRegistrar和MapperScannerConfigurer的区别及作用

在使用Spring Boot和MyBatis整合的时候,我们经常会看到@MapperScan这个注解,它的作用是扫描指定包下的Mapper接口,并将它们注册到Spring容器中,这样我们就可以在Service层或者Controller层直接注入Mapper接口的实例,而不需要写DAO层的实现类。那么,@MapperScan这个注解是如何实现这个功能的呢?它背后涉及到了两个重要的类:MapperScannerRegistrar和MapperScannerConfigurer,它们之间有什么区别和联系呢?

2024-01-21 18:04:17 1114

原创 带你拿捏SpringBoot自动装配的核心技术?模块装配(@EnableXXX注解+@Import)+ 条件装配(@ConditionalXXX)

之前文章我们完整的学习了模块装配的核心使用方法,通过模块装配,咱可以通过一个注解,一次性导入指定场景中需要的组件和配置。使用的时候就只需要传入对应的.class即可,原来的是直接传入Condition接口的实现类,现在这个ConditionalOnBean注解相当于封装了一层。等重要对象信息,根据这些对象就可以获取和检查spring容器初始化时所包含的所有信息,再结合业务需求,就可以实现组件注册时的自定义条件判断。根据条件的不同,这个自动配置类可能会在Spring容器中自动配置一些与JPA相关的Bean。

2024-01-14 15:49:52 1060

原创 @EnableXXX注解+@Import轻松实现SpringBoot的模块装配

最早我们开始学习或接触过 SSH 或者 SSM 的框架整合,大家应该还记得那些配置文件有多烦吧,又多又不好记真的很让人头大。在处理配置文件的同时,大家是否有想过:如果能有一种方式,可以使用很少的配置,甚至不配置就可以完成一个功能的装载,那岂不是省了很多事?这个疑问在 SpringBoot 中得以解决,也就是我们常说的自动装配,而这个自动装配的核心技术就是模块装配 + 条件装配。今天我们这里主要讲解模块装配,条件装配我们后续再讲解!

2024-01-02 20:04:42 1734 1

原创 Mybatis分页插件之PageHelper生效and失效原理解析

PageHelper是一个优秀的Mybatis分页插件,它可以帮助我们自动完成分页查询的工作。它的使用非常简单,只需要在查询之前调用PageHelper.startPage方法,传入页码和每页大小,就可以实现分页效果。PageHelper还提供了很多其他的配置和功能,例如排序、合理化、分页参数映射等。那么,PageHelper是如何实现分页功能的呢?本文将从源码的角度,一步步分析PageHelper的实现原理,希望能够对大家有所帮助。对指定mapper查询支持分页,前面一定要有。

2023-12-30 23:25:54 1159

原创 构建自己的拦截器:深入理解MyBatis的拦截机制

Mybatis拦截器并不是每个对象里面的方法都可以被拦截的。Mybatis拦截器只能拦截Executor、StatementHandler、ParameterHandler、ResultSetHandler四个类里面的方法,这四个对象在创建的时候才会创建代理。Mybatis拦截器是Mybatis提供的一种插件功能,它允许你在已映射语句执行过程中的某一点进行拦截调用。

2023-12-24 23:36:21 1336

原创 Mybatis-Spring整合原理:MapperFactoryBean和MapperScannerConfigurer的区别及源码剖析

1.是一个包扫描的配置类,其中属性是必需的,多个包时可以使用逗号隔开。二选一即可。如果都选了那么根据引用的创建的SqlSession会被覆盖掉。如果两个都没配置,将会根据类型自动装配,这种方式适合应用程序中只有一个或者的bean存在。其它配置就不总结了。2. 具体实现扫描以及注册接口的功能被委托给类了。具体做法就是将Spring扫描接口后生成的修改成一个表示的,而是一个实现的特殊bean,相当于返回Mapper接口实例的工厂。具体返回接口实例的原理是MyBatis本身的接口绑定功能,底层其实是动态代理。

2023-12-16 23:18:00 1167

原创 Mybatis与Spring结合深探——MapperFactoryBean的奥秘

在没有Spring单独使用Mybatis的时候,我在之前的文章超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?讲解到了调用链路在SqlSessionFactoryBuilder().build方法 中最终调用Configuration对象的addMappper()方法(实际上是委托给MapperRegistry的addMapper)添加对应的MapperProxyFactory代理工厂类,最终通过这个工厂类生成对应的代理对象MapperProxy。

2023-12-10 23:57:07 1239

原创 超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?

提到MyBatis,很多人可能已经使用过,MyBatis中的mapper接口实际上并没有对应的实现类,它的功能通过一个对应的xml配置文件来实现。这意味着当我们调用一个mapper接口时,我们实际上是在执行xml文件中定义的SQL语句来操作数据。那么Mybatis的mapper为啥只有接口没有实现类,它却能工作?答案很简单,动态代理,但是要真正理解这个动态代理的整个过程,还是有点费劲的,没事,接下来我们一步步解析。Mybatis的动态代理工作原理概括步骤如下:Mapper接口与XML的关联。

2023-12-03 22:40:23 1683

原创 究竟FactoryBean是什么?深入理解Spring的工厂神器

在Spring框架中,bean的创建通常交由Spring IoC容器负责,它提供了丰富的方式来创建和管理bean的生命周期。在众多的功能中,以一种特别的方式出现,不仅让我们能够控制bean的创建过程,还使得更复杂的初始化逻辑变得简洁清晰。接下来,让我们 一步步地走进的世界,并通过案例解析来透彻理解它在Spring应用中的使用。是Spring提供的一种特殊的bean,使用它可以生成某些需要复杂初始化过程的bean对象。当配置某个bean实现了接口时,该bean返回的对象不是本身,而是。

2023-11-26 19:18:40 1230

原创 解析Spring Boot中的CommandLineRunner和ApplicationRunner:用法、区别和适用场景详解

在Spring Boot应用程序中,CommandLineRunner和ApplicationRunner是两个重要的接口,它们允许我们在应用程序启动后执行一些初始化任务。本文将介绍CommandLineRunner和ApplicationRunner的区别,并提供代码示例和使用场景,让我们更好地理解和使用这两个接口。

2023-11-19 13:50:10 2664

原创 异步编程工具Promise与Async/Await:解决前端开发中的嵌套回调地狱

如果数组中的所有Promise对象都变为fulfilled(已成功)状态,那么Promise.all返回的Promise对象也会变为fulfilled状态,其结果是一个数组,包含了数组中的所有Promise对象的结果。Promise.all是一个静态方法,它可以接收一个Promise对象的数组作为参数,返回一个新的Promise对象,该对象的状态和结果取决于数组中的所有Promise对象的状态和结果。使用Promise进行异步编程时,可以将多个Promise对象链接在一起,形成一个Promise链。

2023-11-12 18:42:42 389

原创 定时任务场景下的代码审查:continue和return的滥用可能引发潜在bug

在最近的代码审查中,有帮忙审查了组里一个刚毕业1年不到的应届生,发现他写的其中一段代码将for循环中的break、continue、return滥用,导致了一个潜在的bug风险,这个风险后文我们再来分析。continue关键字的作用是跳过当前的迭代,继续执行下一次的迭代。它可以用来跳过某些不需要执行的情况,或者优化循环的效率。break关键字的作用是结束当前的循环,跳出循环体。它可以用来提前终止循环,或者跳出嵌套的循环。return关键字的作用是结束当前的方法,并返回一个值(如果有的话)。

2023-11-04 17:22:17 237

原创 面试官:听说你很了解Java8特性,给我优化一下这段代码吧?

在之前的一次面试过程中,我被问到了一道代码优化题:对于下面的代码,你有什么优化的思路呢?

2023-10-24 21:12:19 180

原创 SpringBoot +JdbcTemplate+VUE 实现在线输入SQL语句返回数据库结果

想起来要做这个功能是因为我们公司的预生产环境和生产环境如果想要连接数据库都需要登录堡垒机,然后再通过堡垒机进行跳转到对应定制的Navicat 连接工具进行查询。每次这个过程十分繁琐,所以就想直接在我们的系统上直接做个口子,登录以后,可以直接输入SQL查询,跟直接连接Navitcat效果是一样的。

2023-10-22 18:59:25 588 1

原创 每天debug/run一键启动的Spring Boot控制台启动日志,你了解过吗?

每次打开Idea点击debug/run启动SpringBoot项目时,都在坐等启动成功的最后一行日志,然而对于启动过程中,控制台里面的每一行日志代表什么?你可能从来没去管他!是的,曾经我也是这样的,然而今天对此引起了我的好奇心。。。接下来,随着跟我一探究竟Spring Boot启动日志的真相!......启动日志可以分为两部分1、JDK执行Spring Boot应用的启动命令2、Spring Boot本身启动时的日志。

2023-10-15 16:57:34 349

原创 Nginx与Spring Boot的错误模拟实践:探索502和504错误的原因

刚工作那会,最常见的报错是,曾经也碰到过前端反馈或者,那时候傻傻的搞不懂,以为这种都是外部服务或者网络运维部那边的问题。当时那个服务里正好有个调用日志,平时会记录各种200,4xx状态码的信息。于是我跑到服务日志里去搜索了一下502这个数字,毫无发现。于是跟反映错误的前端说,“服务日志里并没有502的记录,你是不是搞错啦?现在想想,果然那时候还是个小白。。。在Nginx中,access.log和error.log是两个重要的日志文件,用于记录服务器的访问和错误信息。

2023-10-04 23:21:59 3651 1

原创 Spring事务this自调用的理解误区?真的会让事务失效吗?

我们经常谈到Spring事务失效会有多种场景导致:可参考我另外一篇文章一文清晰讲解@Transactional 注解失效场景@Transactional 应用在非 public 修饰的方法上@Transactional 注解属性 propagation 设置错误@Transactional 注解属性 rollbackFor 设置错误同一个类中方法调用,导致@Transactional失效异常被你的 catch“吃了”导致@Transactional失效数据库引擎不支持事务。

2023-09-27 00:25:38 1755

原创 从零开始的 MyBatis 拦截器之旅:实战经验分享

Configuration:初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中。SqlSessionFactory:SqlSession工厂。SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要的数据库增删改查功能。

2023-09-22 23:02:31 358

原创 深入探究Spring Boot自动配置原理及SPI机制:实现灵活的插件化开发

在传统的Spring应用程序中,我们需要手动配置各种组件、依赖和属性,以满足应用程序的需求。这通常涉及编写大量的XML配置文件或Java配置类,并进行复杂的依赖注入和组件装配。这种手动配置过程可能非常繁琐且容易出错。而Spring Boot的自动配置机制通过约定大于配置的原则,基于应用程序的依赖和配置信息,自动推断和配置应用程序所需的各种组件。它通过提供默认的配置和装配规则,减少了我们的工作量,使得我们可以更专注于业务逻辑的开发。接下来就讲解一下自动配置的原理实现。

2023-09-17 20:44:40 515

原创 Nginx入门指南:轻松掌握Web服务器技术

在入门之前先抛出几个问题进行思考,后面会进行解答Nginx是什么?正向代理和反向代理?为什么要使用负载均衡?Nginx的负载均衡模式有哪些?它的实现原理是什么?如果代理的服务器宕机了 Nginx 会如何处理?Nginx 的缓存功能是如何使用的?

2023-09-10 17:12:41 104

原创 解密Spring事务生效的内部机制

方法调用前的处理:事务拦截器在目标方法调用前执行一些预处理操作。这包括检查当前是否存在事务上下文(TransactionContext),如果不存在则创建新的事务上下文。事务上下文包含了事务的相关信息,如事务的传播行为、隔离级别、超时设置等。事务拦截器还会根据事务定义的属性决定是否开启新的事务或者加入已有的事务。方法调用:事务拦截器将目标方法调用传递给实际的目标对象,并执行目标方法。方法调用后的处理:在目标方法执行完成后,事务拦截器会根据方法的执行结果决定是提交事务还是回滚事务。

2023-09-02 18:36:41 243

原创 Spring为什么要专门定义BeanDefinition ,有Class不行吗?

借助 IDE ,打开的接口定义,从方法列表上看,Bean 的类信息 - 全限定类名 ( beanClassName )Bean 的属性 - 作用域 ( scope ) 、是否默认 Bean ( primary ) 、描述信息 ( description ) 等Bean 的行为特征 - 是否延迟加载 ( lazy ) 、是否自动注入 ( autowireCandidate ) 、初始化 / 销毁方法 ( initMethod / destroyMethod ) 等。

2023-08-26 17:23:01 164

原创 深入探索Spring后置处理器:解析作用与实际应用场景

BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor InstantiationAwareBeanPostProcessor BeanPostProcessor是spring生命周期中常见的4个后置处理器,但是对于其作用和执行顺序很多人还不是非常清楚,这里给大家讲解一下其作用以及执行顺序,并带上实操。

2023-08-19 15:05:15 1245

原创 如何在项目中正确使用异常?

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。用户输入了非法数据。要打开的文件不存在。网络通信时连接中断,或者JVM内存溢出。

2023-02-12 17:41:13 811 1

原创 必读开发规范之阿里巴巴开发手册(个人整理版)

【推荐】不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解,也不利于维护。正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下。

2022-10-24 21:37:54 18066

原创 单元测试入门扫盲

单元测试是一种白盒测试,测试者依据程序的内部结构来实现测试代码。单元测试英文单词: Unit Test。什么是 Unit (单元)?单元可以是一个方法、可以是一个类,也可以是一个包甚至是一个子系统。我们开发时编写的单元测试,通常是对一个类中的部分或者所有方法进行测试,用来验证它们功能的正确性。通常用来验证给定特定的输入,是否能够给出符合预期的输出。

2022-08-19 13:59:44 2441

原创 手把手带你入门链表的基本操作及其优化

文章目录一、概念头指针:头结点(虚拟头结点/哨兵节点/哑节点)首元节点三者关系图判断链表为空代码理解一、遍历二、查找三、插入1、链表头部插入2、链表尾部插入1)优化1:添加tail尾节点2)优化2:添加虚拟头结点3、给点节点后插入四、删除1、删除指定节点后面的节点2、删除指定节点虚拟头结点优化五、根据索引下标插入删除六、时间复杂度分析完整代码测试一、概念头指针:1)头指针是指链表中 ,指向第一个结点的指针(可以是头结点也可以是首元节点,看实现方式)2)头指针是必须存在的,链表为空也存在(head=n

2021-12-26 14:50:17 1053

原创 实战模拟带你入门Junit+Mockito+Assert

文章目录测试分类Junit+Mockito+Assert实战Mock场景实战模拟Mock测试解析正常调用成功调用外部依赖失败测试分类按不同分类可以有很多种,我这里简单说一下下面的几种,这里想要更深入了解的可以看这篇文章:https://zhuanlan.zhihu.com/p/81571007单元测试目的:用于验证编码单元的正确性,比如测试某个方法逻辑正确性,属于白盒测试,即被测对象内部逻辑对测试者来说是透明的,一般由开发编写。集成测试:用于验证详细设计,也叫组装测试、子系统测试,是在单元测试的基

2021-12-18 13:55:33 1351

原创 一文带你扫盲日志记录的基础知识

文章目录一、日志记录入门二、日志记录域三、日志记录安全使用场景四、 设计、实现和测试注意事项五、 要记录的事件六、事件属性七、使用 OWASP 进行安全日志记录监控应用程序基础结构的健康状况日志消息关联您在启动应用时是否记录足够多的信息?八、日志记录技术一、日志记录入门读者可能会想知道:为什么要介绍日志记录?我们多年来一直在进行日志记录。还有什么需要知道的吗?在忙着部署产品的过程中,日志记录几乎总是被忽视。这并不是因为日志记录不重要,而是因为它被认为是产品团队对其产品需求没有特别要求的非功能性使用场景

2021-12-15 14:49:21 4609

原创 Kotlin基础语法总结

基本语法函数函数返回无意义的值:Unit 返回类型可以省略:fun sum(a: Int, b: Int): Int { return a + b}fun sum(a: Int, b: Int) = a + b变量定义只读局部变量使用关键字 val 定义。只能为其赋值一次。val a: Int = 1 // 立即赋值val b = 2 // 自动推断出 `Int` 类型val c: Int // 如果没有初始值类型不能省略c = 3 // 明确赋值可重

2021-10-24 00:03:24 262

原创 SpringBoot启动指定profile的8种方式你懂了吗?

配置文件中设置通常在公司级别的项目中,我们可能会写多个application- dev/prod.yml ,然后我们通常会在application.yml配置文件中写入spring: profiles: active: dev这里会指定激活的profile是application- dev.yml注意:application.yml中类似Java中的父类,其他application- dev/prod.yml会继承这个文件,可以进行重写,没有进行重写的属性我们也是能直接读取的,比如a

2021-09-11 17:24:41 9071 3

原创 Java中的Pair完美解决了我的一个BUG。。。

文章目录概念基本使用实际业务使用(Bug解决)在最近的工作中有一个Bug的解决用到了Pair,之前还没用过Pair这个类,只是见过,这次顺便记录学习一下概念配对(Pair):它提供了一种方便方式来处理简单的键值关联,有两种场景可以使用:第一种使用场景比较简单,我这里主要讲下第二种,我的Bug解决也是说的第二种1、当我们想从方法返回两个值时特别有用2、当我们使用单个字段无法识别某个对象的唯一性,还需要加上一个字段辅助识别的情况下就可以使用Pair(下面会讲)基本使用这里我Pair使用的是c

2021-09-01 19:16:08 734 1

原创 10分钟带你彻底搞懂企业服务总线

文章目录什么是企业服务总线?路由器转换器端点我相信你一定有生病去医院的经历,你一般通过什么渠道挂号呢?我们很多人会借助在线挂号 App 或小程序来预约挂号,但你有没有想过,全国有这么多家医院,每个医院内部都可能有自己的信息化系统,在线挂号 App 是怎么帮你准确而高效地找到目标医院和医生的呢?我们看一下挂号预约的整个业务流程,你就明白了。这里的移动医疗系统就是 App 供应商所开发的系统,而医院信息系统则位于各个医院的内部。那么,怎么实现这个场景呢?这里的核心需求在于,使用合适的系统集成机制来整合我

2021-08-07 15:48:34 7404 3

原创 10分钟带你彻底搞懂微内核架构

文章目录什么是微内核架构?如何实现微内核架构?总结在日常开发过程中,我们经常会遇到这样的需求:针对某个业务场景,我们希望在系统中添加一种新的处理逻辑,但又不想对现有的系统造成太大的影响。从架构设计上讲,这是一种典型的系统扩展性需求。针对这样的扩展性需求,本质上开发人员想要的是一种类似插件化的架构体系,调用者通过一个插件工厂获取想要的插件,而插件工厂则基于配置动态创建对应的插件,这样整体系统就像搭积木一样可以进行动态的组装。基于插件化系统,我们往现有系统中添加新的业务逻辑时,就只需要实现一个新的插件并

2021-07-26 13:44:47 4279

原创 10分钟带你彻底搞懂服务限流和服务降级

文章目录服务限流计数器法滑动窗口法漏桶算法令牌桶算法服务降级我们知道,在分布式系统中,当面对高并发、大流量的应用场景时,系统就会面临崩溃的风险。这时候,为了提高系统可用性,我们就需要对外部流量进行限制,以减少对现有系统的影响。目前,业界主流的两种最佳实践是服务限流和服务降级,这节课我们就来深入了解这两种解决方案。假如你正在设计和开发一个分布式服务系统,各个服务为了满足特定业务需求,通常都会相互依赖形成一种复杂的调用链路。那么,在这样的调用链路中,服务可能因为自身无法承受大量的请求而发生调用失败,或者可能

2021-07-26 13:43:08 3107 3

Java版俄罗斯方块(源码+exe/无需安装环境+带音乐+超好看UI)

Java版本百分百可直接运行exe文件+源码,不用安装java任何环境!!带音乐+超好看UI!! 博客链接:https://blog.csdn.net/belongtocode/article/details/105979473

2020-05-07

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除