- 博客(481)
- 收藏
- 关注
原创 Java 并发之 Fork/Join 框架
Fork/Join框架是一种在JDK7引入的线程池,用于并行执行把一个大任务拆成多个小任务并行执行,最终汇总每个小任务结果得到大任务结果的特殊任务。通过其命名也很容易看出框架主要分为Fork和Join两个阶段,第一阶段Fork是把一个大任务拆分为多个子任务并行的执行,第二阶段Join是合并这些子任务的所有执行结果,最后得到大任务的结果。这里不难发现其执行主要流程首先判断一个任务是否足够小,如果任务足够小,则直接计算,否则,就拆分成几个更小的小任务分别计算,这个过程可以反复的拆分成一系列小任务。分治(...
2022-07-27 13:38:13
255
原创 Java 内存模型
在并发编程中,当多个线程同时访问同一个共享的可变变量时,会产生不确定的结果,所以要编写线程安全的代码,其本质上是对这些可变的共享变量的访问操作进行管理。导致这种不确定结果的原因就是可见性、有序性和原子性问题,Java为解决可见性和有序性问题引入了Java内存模型,使用互斥方案(其核心实现技术是锁)来解决原子性问题。这篇先来看看解决可见性、有序性问题的Java内存模型(JMM)。Java内存模型在维基百科上的定义如下共享的内存模型定义了线程和主内存之间的关系Java内存模型(JMM)。......
2022-07-27 13:37:05
230
原创 MySQL驱动中关于时间的坑
最终返回了MySQL数据库中的默认时区,因为我们MySQL中默认时区是CST,所以这里也符合我们观察到的现象,最终保存到数据库的日期比实际我们当前的东8区慢14个小时,但是为什么使用mybatis的另外一个项目就没有问题呢,要知道这两个项目使用的测试数据库是同一个的,这就很奇怪,到这里,我决定再在另一个项目中也debug一下,看下问题到底出在了哪里;然后我瞬间明白了,这个问题与mybatis没有任何关系,是两个项目的MySQL驱动不一致导致的,使用mybatis的项目使用的MySQL驱动版本是。...
2022-07-27 13:35:38
727
原创 领域事件 disruptor 使用场景之实现Spring事件驱动模型
领域驱动设计,基于LMAX架构。单一职责原则,可以给系统的可扩展、高伸缩、低耦合达到极致。异步高并发、线程安全的、使用disruptor环形数组来消费业务。可并发执行,性能超高,执行1000W次事件只需要1.1秒左右(这个得看你的电脑配置)。使用事件消费的方式编写代码,使得业务在复杂也不会使得代码混乱,维护代码成本更低。可灵活的定制业务线程模型插件形式提供事件领域,做到了可插拔,就像玩乐高积木般有趣。领域事件的本质是对disruptor的封装使用。定义领域实体–并实现Eo接口。...
2022-07-27 13:34:57
715
原创 如何利用 RPA 实现自动化获客?
如图,运行「百度地图获客RPA机器人」,自动选择「杭州」城市,自动输入「五金」,最后自动输出对应的客户手机号。RPA流程其实就是个输入和输出,你只要批量的输入城市列表、关键词列表,然后运行完后,输出的就是你想要的分好类的客户号码列表。RoboticProcessAutomation(简称RPA)机器人流程自动化,是一种技术,是以软件机器人+AI/OCR等科技能力结合,在软件上的某些业务操作场景中,达到机器替人,实现重复的工作自动化。RPA的应用场景是在线上的。...
2022-07-27 13:32:57
677
原创 k8s配置集ConfigMap详解
ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷,ConfigMap对象用于为容器中的应用提供配置文件等信息。但是比较敏感的数据,例如密钥、证书等由Secret对象来进行配置。它们将相应的配置信息保存于对象中,而后在Pod资源上以存储卷的形式挂载并获取相关的配置,以实现配置与镜像文件的解耦。1.首先在容器外面创建一个redis.conf的配置文件,然后根据这个配置文件创建出一个名为redis.conf的ConfigMapapiVersionv1data注https。...
2022-07-26 13:29:27
1771
原创 基于ABP实现DDD--领域逻辑和应用逻辑
不知道你们是否会遇到一种情况,通过ABP构建了一个后端的API项目,刚开始是为Web端项目(比如,Vue)提供后端接口服务的,随着项目的发展和业务的复杂,增加了移动端的App,或者公众号、小程序等,这样不仅要为Web端提供API服务,而且还需要为移动端的App,或者公众号、小程序等提供API服务。这个场景就是多应用层的问题。Web应用程序比如使用的ASP.NETCoreMVC技术,主要用来给用户展示产品,游客模式是可以查看产品的,并不需要登录和验证。后端管理应用程序移动应用程序。...
2022-07-26 13:27:31
330
原创 通过源码深度分析线程池中Worker线程的执行流程
Worker类实现了Runnable接口,需要重写run方法,而Worker的run方法本质上调用的是ThreadPoolExecutor类的runWorker方法,在runWorker方法中,会首先调用unlock方法,该方法会将state置为0,所以这个时候调用shutDownNow方法就会中断当前线程,而这个时候已经进入了runWork方法,就不会在还没有执行runWorker方法的时候就中断线程。(2)获取锁累加完成的任务数量,并将完成的任务从workers集合中移除,并释放,如下所示。...
2022-07-26 13:25:48
539
原创 MyBatis-Plus联表查询的短板,终于有一款工具补齐了
经过简单的测试,个人感觉mpj这款工具在联表查询方面还是比较实用的,能更应对项目中不是非常复杂的场景下的sql查询,大大提高我们的生产效率。当然,在项目的issues中也能看到当前版本中也仍然存在一些问题,希望在后续版本迭代中能继续完善。httpshttpshttpshttpshttpshttps。...
2022-07-26 13:23:41
228
原创 Spring Data JPA与Mybatis的对比
我们再看看hibernate的官方概念,Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。完成以上步骤,基本上完成了体统中主要的业务概念类和表结构的设计工作,只是完成表结构设计的出发点事如何持久化系统的对象,同时兼顾数据库表、字段、字段类型、表的关联关系的合理性和合规性,而不是单纯表设计。.
2022-07-26 13:17:59
4191
原创 服务器内存故障预测居然可以这样做
随着互联网业务的快速发展,基础设施的可用性也越来越受到业界的关注。然而硬件故障一直以来都是一种普遍存在的现象,由于硬件故障而造成的损失往往是巨大的。在服务器各个部件中,除硬盘故障以外,内存故障是第二大常见的硬件故障类型。并且服务器内存的数量众多,vivo的内存数量达到40w+条,内存故障造成的最严重的后果是会直接导致系统崩溃,服务器宕机,这些对于上层业务而言都是不能接受的。内存故障可分为UCE(UncorrectableError)和CE(CorrectableError)。标记CE错误。...
2022-07-26 13:15:42
756
原创 聊聊如何用 Redis 实现分布式锁?
比如在有些场景中,一个线程A获取到了锁之后,由于业务代码执行时间可能比较长,导致超过了锁的超时时间,自动失效,注意A线程没执行完,后续线程B又意外的持有了锁,意味着可以操作共享资源,那么两个线程之间的共享资源就没办法进行保护了。加锁失败后,客户端向所有Redis节点发起释放锁的操作,释放锁的操作和在单节点上释放锁的操作一样,只要执行释放锁的Lua脚本就可以了。它是基于多个Redis节点的分布式锁,即使有节点发生了故障,锁变量仍然是存在的,客户端还是可以完成锁操作。...
2022-07-26 13:13:25
158
原创 服务发现原理分析与源码解读
在微服务架构中,有许多绕不开的技术话题。比如服务发现、负载均衡、指标监控、链路追踪,以及服务治理相关的超时控制、熔断、降级、限流等,还有RPC框架。这些都是微服务架构的基础,只有打牢这些基础,才敢说对微服务是有了一点理解,出门也好意思和别人打招呼了,被人提问的时候也能侃侃而谈了,线上出了问题往往也能寻根溯源内心不慌了,旁边的女同事小芳看着你的时候也是满眼的小可爱了。在《微服务实践》公众号,之前写了《go-zero微服务实战系列》的系列文章,这个系列的文章更多的是偏向业务功能和高并发下的服务优化等。和。...
2022-07-26 13:10:05
233
原创 2022最新Java面试题含答案,整合面试复盘笔记
除了你看到的惊人的问题数量,我也尽量保证质量。我不止一次分享各个重要主题中的问题,也确保包含所谓的高级话题,这些话题很多程序员不喜欢准备或者直接放弃,因为他们的工作不会涉及到这些。Java NIO 和 JVM 底层就是最好的例子。你也可以将设计模式划分到这一类中,但是越来越多有经验的程序员了解 GOF 设计模式并应用这些模式。我也尽量在这个列表中包含 2015 年最新的面试问题,这些问题可能是来年关注的核心。为了给你一个大致的了解,下面列出这份 Java 面试问题列表包含的主题:多线程,并发及线程基础数据类
2022-07-25 15:59:01
288
原创 万字长文 | 深入理解 OpenFeign 的架构原理
上次我们深入讲解了Ribbon 的架构原理,这次我们再来看下 Feign 远程调用的架构原理。远程调用怎么理解呢? 和 是相对的,那我们先说本地调用更好理解些,本地调用就是同一个 Service 里面的方法 A 调用方法 B。那远程调用就是不同 Service 之间的方法调用。Service 级的方法调用,就是我们自己构造请求 URL和请求参数,就可以发起远程调用了。在服务之间调用的话,我们都是基于 HTTP 协议,一般用到的远程服务框架有 OKHttp3,Netty, HttpURLConnection
2022-07-25 15:44:07
398
原创 要不你给我说说什么是长轮询吧?
传统的静态配置方式想要修改某个配置时,必须重新启动一次应用,如果是数据库连接串的变更,那可能还容易接受一些,但如果变更的是一些运行时实时感知的配置,如某个功能项的开关,重启应用就显得有点大动干戈了。配置中心正是为了解决此类问题应运而生的,特别是在微服务架构体系中,更倾向于使用配置中心来统一管理配置。配置中心最核心的能力就是配置的动态推送,常见的配置中心如Nacos、Apollo等都实现了这样的能力。在早期接触配置中心时,我就很好奇,配置中心是如何做到服务端感知配置变化实时推送给客户端的?...
2022-07-25 15:42:15
159
原创 2w字详解数据湖:概念、特征、架构与案例
数据湖是目前比较热的一个概念,许多企业都在构建或者计划构建自己的数据湖。但是在计划构建数据湖之前,搞清楚什么是数据湖,明确一个数据湖项目的基本组成,进而设计数据湖的基本架构,对于数据湖的构建至关重要。关于什么是数据湖,有如下定义。Wikipedia是这样定义的数据湖是一类存储数据自然/原始格式的系统或存储,通常是对象块或者文件。数据湖通常是企业中全量数据的单一存储。全量数据包括原始系统所产生的原始数据拷贝以及为了各类任务而产生的转换数据,各类任务包括报表、可视化、高级分析和机器学习。...
2022-07-25 15:40:59
275
原创 Java 的七种垃圾收集器
用C或C++这样的编程语言写一个应用时,需要编写代码来销毁内存中不再需要的对象。当应用程序扩展得越来越复杂时,未使用对象被忽略释放的可能性就越大。这会导致内存泄露,最终内存耗尽,在某个时刻将没有更多的内存可以分配。结果就是应用程序运行失败并出现OutOfMemoryError错误。但在Java中,垃圾收集器GarbageCollection(GC)会在程序执行过程中自动运行,减轻了手动分配内存和可能的内存泄漏的任务。...
2022-07-25 15:39:37
1202
原创 线程崩了,为什么不会导致 JVM 崩溃呢?如果是主线程呢?
那么线程崩溃后,进程是如何崩溃的呢,这背后的机制到底是怎样的,答案是信号,大家想想要干掉一个正在运行的进程是不是经常用kill-9pid这样的命令,这里的kill其实就是给指定pid发送终止信号的意思,其中的9就是信号,其实信号有很多类型的,在Linux中可以通过kill-l查看所有可用的信号。......
2022-07-25 15:33:30
409
原创 咱就是来聊聊并发编程的三大核心问题。
并发编程有三大核心问题分工问题同步问题互斥问题并发编程并不是一项孤立存在的技术,也不是脱离现实生活场景而提出的一项技术。相反,并发编程是一项综合性的技术,同时,它与现实生活中的场景有着紧密的联系。本文就对这三大核心问题进行简单的介绍。...
2022-07-25 15:32:09
100
原创 一点一点理解微服务
也就是说,集群下的任务仍是单机性质的应用,包含了多个业务能力,且没有与其他节点进行通信,任务自始至终都在单个节点中的进程完成。最开始Web服务器、数据库、文件资源是在同一台机器上跑的,一个服务器的处理能力是有限的,先将它们分离Web服务器独立一台机器、数据库独立一台机器、文件存储独立一台机器——显然,静态资源的文件如图片、视频等不需要动态处理,那么采用Apache或Nginx即可,无须Tomcat,或者部署在阿里云OSS专门优化文件的存储,甚至加入网络优化的CDN机制。...
2022-07-25 15:27:32
130
原创 通用 DAO 接口设计
数据访问对象DAO(DataAccessObject)本质是个名词,但我们更多语境中不是作名词用,需要的是一套通用的接口去使用,至于返回的对象是什么,可以是JavaBean或者Map键对值。假设我们背后有一套数据访问机制,是MyBatis、原生JDBC无所谓,只要能提供数据就可以了,那么目前需要设计一套标准的DAO接口,会是这样的。我们的目的是尽量可能简单衔接底层的据访问机制,提供常见的findById、findList、create、update等的操作,而且还允许扩展。...
2022-07-25 15:25:54
261
原创 GitHub中Fork来的仓库如何进行双向更新
做了如上图配置,右侧选择了源仓库的tagv3.0,如愿的识别出了差异,但此时才发现原来的createpullrequest按钮没有了,首先我想阅读的是指定版本的源码,例如tomcat的10.0.21版本,这需要我去clone它的tag10.0.21,这样才能保证版本一致。当一个仓库被Fork过来之后,它是不会随着源仓库更新的,那么如果想同步源仓库的更新过来如何操作呢?需创建并切换到一个新的分支。图中红框部分显示了提交修改的方向,即从自己账号仓库的main分支提交到源仓库的main分支。...
2022-07-22 13:53:18
4242
原创 SpringBoot数据库管理 - 用flyway对数据库管理和迁移
Flyway是一款数据库迁移(migration)工具。简单点说,就是在你部署应用的时候,帮你执行数据库脚本的工具。Flyway支持SQL和Java两种类型的脚本,你可以将脚本打包到应用程序中,在应用程序启动时,由Flyway来管理这些脚本的执行,这些脚本被Flyway称之为migration。PS本质上和liquibase机制一致。按照verion的顺序(和数据库中的更新记录对比,找到未更新的),更新如下更新记录如下Flyway中的变迁(migrations)前缀(PS。...
2022-07-22 13:51:53
1208
原创 SpringBoot到底是什么?
打开创建好的springboot程序,可以看见pom.xml文件中的这里的2.6.4就是自己使用的springboot版本,打开后可以发现其中又继承了一个坐标,引入了很多依赖再次点击打开,就可以找到其中的奥秘了。从下图我们可以发现各式各样的依赖版本号属性,下面列出依赖版本属性的局部,可以看的出来,定义了若干个技术的依赖版本号starter。引导类。...
2022-07-22 13:50:35
316
原创 kubernetes 静态存储与动态存储
普通Volume的设计目标不是为了持久地保存数据,而是为同一个Pod中多个容器提供可共享的存储资源,因此Volume具有十分明确的生命周期——与挂载它的Pod相同的生命周期,这意味着尽管普通Volume不具备持久化的存储能力,但至少比Pod中运行的任何容器的存活期都更长,Pod中不同的容器能共享相同的普通Volume,当容器重新启动时,普通Volume中的数据也会能够得到保留。因此两者并不是谁引用谁的固定关系,而是根据实际情况动态匹配的,两者配合工作的具体过程如下。...
2022-07-22 13:49:04
808
原创 JavaScript进阶内容——BOM详解
BOM(BrowserObjectModel)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是windowBOM由一系列相关的对象构成,并且每个对象都提供了很多方法和属性(BOM包含DOM)它是JS访问浏览器窗口的一个接口它是一个全局变量,定义在全局作用域的变量,函数都会变成window对象的属性和方法在调用时可以省略window,前面学习的对话框都属于window方法,如alert(),prompt()等代码展示...
2022-07-22 13:47:50
219
原创 并发程序的噩梦——数据竞争
在本文当中我主要通过不同线程对同一个数据进行加法操作的例子,层层递进,使用忙等待、和锁去解决我们的问题,切实体会为什么数据竞争是并发程序的噩梦。在本文当中会有一个贯穿全文的例子不同的线程会对一个全局变量不断的进行加的操作!然后比较结果,具体来说我们设置一个静态类变量data,然后使用两个线程循环10万次对data进行加一操作!!!像这种多个线程会存在同时对同一个数据进行修改操作的现象就叫做数据竞争。数据竞争会给程序造成很多不可预料的结果,让程序存在许多漏洞。而我们上面的任务就是一个典型的数据竞争的问题。..
2022-07-22 13:46:29
127
原创 透过Redis源码探究Hash表的实现
我们在学习Redis的Hash表的时候难免脑子里会想起其他Hash表的实现,然后进行一番对比。有没有并发操作;Hash冲突如何解决;以什么样的方式扩容。对Redis来说,首先它是单线程的工作模式,所以不需要考虑并发问题,这题pass。对于Hash冲突的解决,通常来说有,开放寻址法、再哈希法、拉链法等。但是大多数的编程语言都用拉链法实现哈希表,它的实现复杂度也不高,并且平均查找的长度也比较短,各个用于存储节点的内存都是动态申请的,可以节省比较多的存储空间。。ht[0]和。...
2022-07-22 13:45:18
222
原创 2022最新Mybatis面试题总结
MyBatis框架是一个开源的数据持久层框架。它的内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis作为持久层框架,其主要思想是将程序中的大量SQL语句剥离出来,配置在配置文件当中,实现SQL的灵活配置。这样做的好处是将SQL与程序代码分离,可以在不修改代码的情况下,直接在配置文件当中修改SQL。...
2022-07-21 15:29:58
173
原创 Java中两大怪物? 附带面试题
这位球友在做自我介绍时,就是自己想到哪里说到哪里,没亮点,有点拼凑的意思,另外,自我介绍不到30秒就结束了。面试官,当时懵逼的回了一句,结束了?言外之意就是,你的简历我都还没有看完,你的自我介绍却已经over了。建议绝多数人适用的方式,先给自己写一个自我介绍,抽时间背下来,面试的时候带有节奏性的背就阔以了。1、DNS解析(通过访问的域名找出其IP地址,递归搜索)。2、HTTP请求,当输入一个请求时,建立一个Socket连接发起TCP的3次握手。如果是HTTPS请求,会略微有不同。...
2022-07-21 15:27:22
99
原创 Kubernetes调度概念与工作流程
kubernetes集群中的调度程序 会 未分配节点的新创建的Pod,并未该Pod找到可运行的最佳(特定)节点。那么这些动作或者说这些原理是怎么实现的呢,让我们往下剖析下。对于新创建的 pod 或其他未调度的 pod来讲,kube-scheduler 选择一个最佳节点供它们运行。但是,Pod 中的每个容器对资源的要求都不同,每个 Pod 也有不同的要求。因此,需要根据具体的调度要求对现有节点进行过滤。在Kubernetes集群中,满足 Pod 调度要求的节点称为可行节点 ( FN ) 。如果没有合适的
2022-07-21 15:15:04
252
原创 并发开篇——带你从0到1建立并发知识体系的基石
在本篇文章当中主要跟大家介绍并发的基础知识,从最基本的问题出发层层深入,帮助大家了解并发知识,并且打好并发的基础,为后面深入学习并发提供保证。在本篇文章当中主要给大家介绍了一些并发的需求和基础概念,并且使用了一个求积分的例子带大家切身体会并发带来的效果提升,并且给大家介绍了在Java当中3中实现并发的方式,并且给大家梳理了一下FutureTask的方法的大致工作过程,帮助大家更好的理解FutureTask的使用方式。httpshttpshttpshttpshttpshttpshttps。...
2022-07-21 15:02:44
124
原创 7种 实现web实时消息推送的方案
推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用。消息推送(push)通常是指网站的运营工作等人员,通过某种工具对用户当前网页或移动设备APP进行的主动消息推送。消息推送一般又分为web端消息推送和移动端消息推送。上边的这种属于移动端消息推送,web端消息推送常见的诸如站内信、未读邮件数量、监控报警数量等,应用的也非常广泛。+1就可以了。push)和拉(pull)两种形式,下边我们逐个了解下。钱能解决的需求都不是问题。...
2022-07-21 14:59:12
646
原创 Harbor企业级私服Docker镜像仓库搭建及应用
DockerHub作为Docker默认官方公共镜像,如果想要自己搭建私有镜像,Harbor是企业级镜像库非常好的选择。所谓私有仓库,也就是在本地(局域网)搭建的一个类似公共仓库的东西,搭建好之后,我们可以将将镜像提交到私有仓库中。这样我们既能使用Docker来运行我们的项目镜像,也避免了商业项目暴露出去的风险。Harbor作为一个企业级私有Registry服务器,提供了更好的性能和安全,提升了用户使用Registry构建和运行环境传输镜像的效率。Harbor整体架构主机名角色备注。...
2022-07-21 14:57:46
670
原创 多线程与高并发—— Synchronized 加锁解锁流程
由于Monitor基于操作系统调用,上下文切换导致开销大,在竞争不激烈时性能不算很好,在jdk6之后进了系列优化。从重量级锁的优化开始讲,一是自旋锁,二是尽量避免进入Monitor,即使用轻量级锁讲解轻量级锁及加锁解锁流程轻量级锁在没有竞争时,每次重入仍然需要执行cas操作,为解决这个问题,因而产生了偏向锁详细介绍偏向锁Synchronized的原理和优化就暂且讲到这,两篇文章主要都是对概念的介绍、各个状态的锁的结构介绍和阐述简化后的流程。...
2022-07-21 14:56:15
544
原创 22张图带你深入剖析前缀、中缀、后缀表达式以及表达式求值
在本篇文章当中主要跟大家介绍以下几点前缀、中缀和后缀表达式。如何将中缀表达式转化成后缀表达式。如何使用后缀表达式进行求值。表达式求值这是一个比较经典的计算机系统基础问题,但是整个过程比较抽象,本文主要通过图解的方法帮助大家理解这个问题。后缀表达式也称作逆波兰表达式,前缀表达式也称作波兰表达式,这个是因为这是由波兰数学家杨-武卡谢维奇提出来的,用于简化命题逻辑的一种方法。本文主要给大家介绍了如何将中缀表达式转化成后缀表达式,以及代码根据后缀表达式求值。httpshttpshttpshttps。...
2022-07-21 14:54:02
1280
原创 JavaScript进阶内容——DOM详解
当我们已经熟练掌握JavaScript的语法之后,我们就该进入更深层次的学习了首先我们思考一下JavaScript是用来做什么的?JavaScript诞生就是为了能够让它在浏览器中运行那么DOM就是我们学习中不可或缺的一个环节,下面让我们深入了解DOM文档对象模型(DOM),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口用来修改网页内容,结构和样式我们用一个图片来表示(来自B站黑马程序员Pink老师)给元素添加事件,被称为注册事件或者绑定事件传统注册方法。...
2022-07-21 14:51:49
462
原创 8 种最坑SQL语法,工作中踩过吗?
数据库编译器产生执行计划,决定着SQL的实际执行方式。但是编译器只是尽力服务,所有数据库的编译器都不是尽善尽美的。上述提到的多数场景,在其它数据库中也存在性能问题。了解数据库编译器的特性,才能避规其短处,写出高性能的SQL语句。程序员在设计数据模型以及编写SQL语句时,要把算法的思想或意识带进来。编写复杂SQL语句要养成使用WITH语句的习惯。简洁且思路清晰的SQL语句也能减小数据库的负担。...
2022-07-20 14:44:12
91
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅