自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

努力分享一些高质量干货内容

纯干货,没有一点水

  • 博客(96)
  • 收藏
  • 关注

原创 如何从代码层面避免内存泄漏

内存泄漏是指不使用的对象持续占有内存使得内存得不到释放,从而造成内存空间的浪费。内存泄露最明显问题频繁GC,从而STW次数增加,导致用户体验变差。如果内存泄露问题严重,会导致OOM,直接导致程序不能正常运行。大多数内存泄露的原因是,长生命周期的对象引用了短生命周期的对象。例如,A对象引用B对象,A对象的生命周期(t1-t4)比B对象的生命周期(t2-t3)长的多。当B对象没有被应用程序使用之后,A对象仍然在引用着B对象。这样,垃圾回收器就没办法将B对象从内存中移除,从而导致内存泄露问题。

2024-07-22 17:16:47 482

原创 如何写出优雅的代码

优雅的代码就是那种看起来简单、易懂,而且好维护的代码。它的设计让人一眼就能明白每部分的作用,避免了复杂和冗余的部分。它使用清晰的变量和方法名称,能让你很快理解代码在做什么,而不是去猜测。优雅的代码还遵循一些编程的好习惯,比如把代码分成小块,每块负责一个特定的功能,这样更容易修改和扩展。

2024-07-22 17:12:59 576

原创 Java程序中常见问题

资源有序分配法指的是,线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。举例,现有公司B、公司A、公司T,想要从银行分别贷款70亿、40亿、50亿,假设银行只有100亿供放贷,如果借不到企业最大需求的钱,钱将不会归还,怎么才能合理的放贷?

2024-07-21 09:39:01 794

原创 Java程序的故障排查

线程快照是当前JVM内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。命令可以获得运行中的JVM的堆的快照,从而可以离线分析堆,来检查内存泄漏、检查一些严重影响性能的大对象的创建、检查系统中什么对象最多,各种对象所占内存的大小等等。通过这些命令,可以生成和分析堆转储,查看线程状态,获取JVM配置信息等。可用于显示虚拟机进程及进程的配置和环境信息,监视应用程序的CPU、GC、堆、方法区及线程的信息等,甚至代替。

2024-07-21 09:23:23 817

原创 解决死锁问题

资源有序分配法指的是,线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。举例,现有公司B、公司A、公司T,想要从银行分别贷款70亿、40亿、50亿,假设银行只有100亿供放贷,如果借不到企业最大需求的钱,钱将不会归还,怎么才能合理的放贷?

2024-07-20 11:25:34 951

原创 Java中的枚举详解

枚举在Java中是一种特殊的类,用来定义一组固定的常量。它在Java5中引入,提供了一种类型安全的方式来定义和使用常量集合。尽管enum看起来像是新的数据类型,但它实际上是一个受限制的类,继承自。在编译时,编译器生成的类包含了所有定义的常量,并提供了内置的方法,如values()和valueOf(),用来获取所有枚举常量或根据名称返回特定常量。枚举的引入不仅增强了代码的可读性,还提供了更强大的功能和灵活性。Java枚举不仅可以定义常量,还可以实现接口,提供额外的行为和功能。

2024-07-20 09:56:22 1100

原创 Spring详解

Spring是一个轻量级的Java开源框架,是为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面(AOP)。Spring虽然把它当成框架来使用,但其本质是一个容器,即IOC容器。里面最核心是如何创建对象和管理对象,包含了Bean的生命周期和Spring的一些扩展点,也包含对AOP的应用。除此之外,Spring真正的强大之处在于其生态,它包含了、、等一些列框架,极大提高了开发效率。、和是Java生态系统中常见的三个框架:Spring启动流程的主要步骤及对应的代码如下:初

2024-07-19 09:51:43 862

原创 Spring中的事务详解

但是随着事务越来越大,执行时间也会变长,就需要将这个大事务拆分成多个事务,如果确保这个事务能够拆分成多个事务,就需要指定Spring的事务传播行为。比如,在用户注册时候,需要记录注册日志,这时候可以将记录日志的操作单独划分为一个事务,而注册是另一个单独的事务,可以将保存日志的方法指定。事务隔离级别,即数据库中事务隔离级别,指的是一个事务对数据的修改与另一个并行的事务的隔离程度。事务传播行为指,当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行,是应该加入现有事务,还是应该启动一个新事务。

2024-07-19 09:33:23 842

原创 Spring中的AOP详解

代理对象在客户端和目标对象之间起到中介的作用,可以在不修改目标对象的情况下,扩展其功能。实现AOP的技术,主要分为两类,一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入有关“切面”的代码,属于静态代理。在Spring AOP中,注意切面执行顺序非常重要,因为不同切面可能会对同一个方法执行不同的逻辑,这些逻辑的执行顺序可能会影响应用程序的行为和结果。,这个方法就是代理创建的雏形。

2024-07-19 09:26:44 937

原创 Spring启动流程

【代码】Spring启动流程。

2024-07-18 12:09:37 758

原创 Spring中的IOC详解

单例Bean和多实例Bean的生命周期主要区别在于实例化和销毁的管理方式,单例Bean在容器启动时创建一个实例,并由容器负责管理其生命周期的完整过程。在Spring框架中,Bean是应用程序的核心组件,它们由Spring容器创建、组装和管理,以帮助开发者实现松耦合、可测试和可维护的代码。IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。Bean的自动装配是Spring框架提供的一种便捷的方式,用于自动解析和设置Bean之间的依赖关系,而无需显式配置每一个依赖关系的方式。

2024-07-18 09:20:47 1066

原创 Spring循环依赖与三级缓存

简单来说,首先检查一级、二级和三级缓存中是否有BeanA,如果没有,开始创建BeanA。又因为BeanB依赖BeanA,此时三级缓存中有BeanA,从三级缓存中获取BeanA,然后将BeanA提前暴露到二级缓存。继续初始化BeanB,完成后将BeanB放入一级缓存,并从三级缓存中移除。在Spring Boot 2.6.0及之后的版本中,默认情况下,Spring不再自动解决循环依赖。在Spring框架中,为了解决循环依赖问题,Spring使用了三级缓存机制。

2024-07-18 09:11:17 361

原创 七种软件设计原则

当两个模块之间存在紧密的耦合关系时,最好的方法就是分离接口和实现,即在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。某些时候,实现类并非需要所有的接口定义,在设计上这是“浪费”,而且在实施上这会带来潜在的问题,对胖接口的修改将导致一连串的客户端程序需要修改,有时候这是一种灾难。其核心思想为,降低类之间的耦合。类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成搏击,也就是说,信息的隐藏促进了软件的复用。

2024-07-17 10:14:42 801

原创 HashSet详解

如果尝试添加一个已经存在的元素,集合将保持不变,所以该集合在线程不安全的情况下可替代。中添加一个已经存在的元素,新添加的集合元素不会覆盖已有元素,从而保证了元素的不重复。不允许存储重复的元素,即集合中的元素是唯一的。方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。,则说明哈希码冲突,但实际上是不同的对象,此时将新元素添加到。方法比较相等的元素,则不添加,否则添加新元素到集合中。中的元素,而值则是一个占位对象,用来表示键已经存在。,则认为新元素与已存在元素相同,不进行添加操作,返回。

2024-07-17 10:09:49 800

原创 ArrayList详解

二分查找法:也称为折半查找法,是一种适用于大量数据查找的方法,但是要求数据必须的排好序的,每次以中间的值进行比较,根据比较的结果可以直接舍去一半的值,直至全部找完(可能会找不到)或者找到数据为止。底层是数组,而数组的中的元素内存分配都是连续的,并且数组中的元素只能存放一种,这就造成了数组中的元素地址是有规律的,数组中查找元素快速的原因正是利用了这一特点。在进行添加,删除操作时,会用二分查找法找到将要添加或删除的元素,之后再设置对象的下一个结点来进行添加或删除操作,所以增加删除的效率高。

2024-07-16 10:01:51 1112

原创 Java中的泛型详解

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。泛型方法是Java中一种特殊的方法,它在声明时可以使用泛型类型参数,使得方法在调用时可以接受不同类型的参数,并且能够保证类型安全。需要注意的是,泛型在Java中是通过类型擦除来实现的,这意味着泛型信息只在编译时存在,而在运行时会被擦除。在Java中,泛型是一种强大的编程特性,允许类、接口和方法在定义时声明一种参数化类型,而在使用时可以指定具体的类型参数。在编译时,泛型类型被擦除,实际操作的对象是原始类型。

2024-07-16 09:53:15 1291

原创 Java中的23种设计模式

原型模式作为一种快速创建大量相同或相似对象的方式,在软件开发中应用较为广泛,很多软件提供的复制和粘贴操作就是原型模式的典型应用。通过clone的方式在获取大量对象的时候性能开销基本没有什么影响,而new的方式随着实例的对象越来越多,性能会急剧下降,所以原型模式是一种比较重要的获取实例的方式。当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,提高创建对象的效率。可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,可辅助实现撤销操作。

2024-07-15 11:45:03 760

原创 Java中常见的语法糖

在编译阶段,编译器将使用语法糖编写的高级语法转换为更基础、更原始的语法结构,便于生成相应的目标代码,如字节码或机器码,这就是解语法糖的过程。内部类可以在一个类内部定义,但在编译时会被转换为独立的类文件,并不是真正套在一个类的内部,而是分成两个类编译。表达式是Java中的一种语法糖,它提供了一种简洁地表示匿名函数的方法,在语法上的简洁性大大提升了代码的可读性和编写效率。但在Java的字节码结构中,其实并没有枚举类型,枚举类型只是一个语法糖,在编译完成后被编译成一个普通的类。原理是编译器把它转换成了。

2024-07-15 09:57:14 1162

原创 Java中JUC包详解

傀儡结点的后结点则指向添加的第一个结点。在当前线程释放锁的时候,线程B获取到了锁,该方法会判断当前头结点的下一个结点中存放的线程跟当前线程是否相同。修饰了,一个线程获取了对应的锁,并执行该代码块时,其他线程只能一直等待,等待获取锁的线程释放锁。如果不是第一次调用,即尾结点不为空,队列中已经有了其他线程结点,则会直接将当前线程的前结点指向尾结点,即队列中最后一个线程结点。在放入等待队列的过程中,首先要检查队列是否为空队列,如果为空队列,需要创建虚拟的头节点,然后把对当前线程封装的节点加入到队列尾部。

2024-07-13 22:42:33 864

原创 ThreadLocal详解

是修饰变量的,重点是在控制变量的作用域,初衷不是为了解决线程并发和线程冲突的,而是为了让变量的种类变的更多更丰富,方便使用。变量的线程都有自己的隔离副本,这样防止了线程之间的干扰,消除了同步的需要。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

2024-07-13 22:23:10 993

原创 Java中常用线程安全的集合

锁定分段,在执行插入、删除或更新操作时,只有操作涉及的分段会被锁定,其他分段不受影响。在进行插入操作时,先根据键的哈希值确定应该操作哪个分段,然后锁定该分段并进行操作。它的基本原理是每次修改操作都会创建该列表的一个新副本,因此读操作不需要加锁,可以并发执行。每个分段独立加锁,细化了锁的粒度,同时允许多个线程同时操作不同的分段,从而提高并发性能。改进了这一点,不再使用固定的分段数量,而是根据当前的容量动态调整分段的数量,从而更好地适应不同的并发场景,提升了并发性能和灵活性。实例时,必须指定初始的分段数量。

2024-07-13 20:20:50 776

原创 Java中创建线程的方式

在实际开发中用哪个线程池?上面的三种一个都不用,我们生产上只能使用自定义的。Executors类中已经给你提供了,为什么不用?摘自《阿里巴巴开发手册》【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。说明:线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。【强制】线程池不允许使用Executors去创建,而是通过。

2024-07-13 20:10:26 802

原创 synchronized关键字详解

Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。也就是说,仅仅是发生在STW的时候,只有垃圾回收线程能够观测到它,在我们正常使用的过程中是不会发生锁降级的,只有在GC的时候才会降级。修饰的代码,在开始执行时会加锁,执行完成后会进行解锁。所以,在JDK1.6中出现对锁进行了很多的优化,进而出现轻量级锁,偏向锁,锁消除,适应性自旋锁,锁粗化。

2024-07-13 19:55:31 640

原创 CAS详解

在多线程环境中,CAS就是比较当前线程工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较,直到主内存和当前线程工作内存中的值一致为止。当一个线程在某个CPU核心上修改了共享变量的值时,其他CPU核心上缓存中的该变量会被标记为无效,这样其他线程再访问该变量时就会重新从主内存中获取最新值,从而保证了数据的一致性。CPU处理器速度远远大于在主内存中的速度,为了加快访问速度,现代CPU引入了多级缓存,如L1、L2、L3 级别的缓存,这些缓存离CPU越近就越快。,它提供了硬件级别的原子操作。

2024-07-12 22:22:36 690

原创 volatile关键字详解

缓存一致性协议: 每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器要对这个数据进行修改操作的时候,会强制重新从系统内存里把数据读到处理器缓存里。在多线程环境下,CPU轮流切换线程执行,有可能某个线程修改了数据,准备回主内存,此时CPU切换到另一个线程修改了数据,并且写回到了主内存,此时就导致数据的不准确。的作用就是,当某个线程工作内存中的值与主内存中的值,如果不相同就会一直。

2024-07-12 22:15:28 838

原创 Java内存模型

这个概念的核心思想是,编译器和计算机系统在进行优化时,可以重新排列和改变指令的执行顺序,只要最终程序的执行结果与按照程序顺序执行时的结果一致即可。因此在最终执行的指令序列中,c不能被重排序到A和B的前面,c如果排到a和b的前面,程序的结果将会被改变。如果一个操作A在另一个操作B之前,那么在内存模型中,A的所有操作结果对于B是可见的,并且A的执行顺序在B之前。有序性指的是程序的执行顺序按照代码的顺序执行,编译器和处理器可能会进行优化,但这些优化不会影响单线程的语义。关键字会禁止编译器指令重排,来保证。

2024-07-11 16:54:26 975

原创 Java中的锁都有什么

资源有序分配法指的是,线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态,直到获取到某个锁超过一定的自旋次数后才会阻塞线程。但是如果线程间存在锁竞争,偏向锁会失效,此时会涉及到锁的撤销,将锁状态升级为适合多线程竞争的轻量级锁或者重量级锁,这个过程可能会引入额外的开销,影响性能。

2024-07-10 16:50:27 1376

原创 JVM详解

除了这三种类加载器之外,用户还可以加入自定义的类加载器来进行拓展,以满足自己的特殊需求。就比如说,我们可以对 Java 类的字节码(.class文件)进行加密,加载时再利用自定义的类加载器对其解密。隔离加载类修改类加载的方式扩展加载源防止源码泄漏若要实现自定义类加载器,只需要继承类,按需重写相关方法即可。如果不想打破双亲委派模型,那么只需要重写findClass方法如果想打破双亲委派模型,那么就重写整个loadClass方法。

2024-06-26 10:46:55 1321

原创 JVM中的垃圾回收机制

垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存爆掉。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。如果不及时对内存中的垃圾进行清理,那么这些垃圾对象所占的内存空间会一直保留到应用程序的结束,被保留的空间无法被其它对象使用,甚至可能导致内存溢出。垃圾收集,不是Java语言的伴生产物。早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。垃圾收集机制是Java的招牌能力,极大地提高了开发效率。

2024-06-20 17:56:51 688

原创 JVM中的垃圾回收器

从名字中的Mark Sweep这两个词可以看出,CMS 收集器是一种 “标记-清除”算法实现的,以获取最短回收停顿时间为目标,采用“标记-清除”算法,分 4 大步进行垃圾收集,其中初始标记和重新标记会 STW,JDK 1.5 时引入,JDK9 被标记弃用,JDK14 被移除。是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。不过,默认的垃圾回收器依然是 G1。

2024-06-20 17:42:51 783

原创 Java资源干货

文章目录大厂技术博客干货资源网站大厂技术博客美团技术团队: https://tech.meituan.com阿里技术团队: https://102.alibaba.com小米技术团队: https://xiaomi-info.github.io360技术团队: https://blogs.360.net有道技术博客: http://techblog.youdao.com字节跳动博客: https://opensource.bytedance.com/blog淘宝前端团队: https://

2024-06-18 13:58:40 500

原创 整合支付功能

Slf4j@Override// 前置处理log.debug("开始执行前置处理.");if (!throw new PayException("支付前置处理失败,不能继续执行");log.debug("前置处理执行完毕");// 执行log.info("开始执行,请求参数 {}", JSON.toJSONString(orderInfo));log.info("执行完毕,响应参数 {}", JSON.toJSONString(result));// 后置处理。

2024-04-19 14:52:54 941

原创 管道流设计模式结合业务

Override@Override@Override// 执行// 是否继续执行调用链/*** 执行器* @param context 上下文对象*/

2024-04-18 11:18:50 851

原创 简要概述如何做好程序设计

【代码】简要概述如何做好程序设计。

2024-04-18 11:05:07 471

原创 解决内存泄漏问题

内存泄露是指,程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。简单来说,就是应该被垃圾回收的对象没有回收掉,导致占用的内存越来越多,最终导致内存溢出。如果当前完全垃圾回收后内存增长到一个值之后,又能回落,总体上处于一个动态平衡,那么内存泄漏基本可以排除;也可以隔断时间抽取老年代占用内存情况,如果老年代占用情况持续上升也很有可能存在内存泄露的情况。,找到堆内存中占用最大的对象,内存泄漏很有可能就是由大对象导致的;

2024-04-17 16:35:32 766

原创 如何优雅规范编写Java代码

else并不会降低代码的复杂度,相反比较少见的写法可能会增加认知负荷,从而进一步增加了复杂度。else是为了对代码进行解耦合,方便扩展代码,最终方便对代码的维护。思路:定义一个注解,将需要校验的参数对象都标注该注解,利用SpringAOP,拦截该注解,将其中标注的参数取出,最后通过BeanValidator进行校验。是因为通常在编码过程中我们不只自己进行开发,通常需要一个团队来进行,开发好之后还需要维护,所以编码规范就显的尤为重要。代码维护时间比较长,那么保证代码可读性就显得很重要。

2024-04-17 16:30:58 1000

原创 Hystrix熔断及工作流程

当微服务系统的一个服务出现故障时,故障会沿着服务的调用链路在系统中疯狂蔓延,最终导致整个微服务系统的瘫痪,这就是“雪崩效应”。为了防止此类事件的发生,微服务架构引入了“断路器”的一系列服务容错和保护机制。

2024-04-17 10:26:56 1085

原创 SpringBoot整合Validator

String message() default "请输入中文";Class

2024-04-17 09:49:35 623

原创 使用Hugo、Github Pages搭建自己的博客

需要注意的是,Github Pages需要在跟路径下创建一个docs文件夹,这个文件夹就是你的网站页面,我的是这样,docs里面保证根目录有一个index.html文件即可。除此之外,Hugo内置web服务器,可以在修改MarkDown文章之后切换到浏览器,页面会检测到更新并且自动刷新,呈现出最终效果,能极大的提高博客书写效率。它的极速和简约风格符合我的需求,让我能够专注于内容的创作。最初希望能将自己学习的知识记录下来,梳理自己的思想,于是开始搭建博客。就可以访问得到你的博客了,这就完成了博客的部署。

2024-04-15 11:21:38 936

原创 MQ概览及Kafka详解

为保证 producer 发送的数据,能可靠的发送到指定的 topic,topic 的每个 partition 收到 producer 发送的数据后,都需要向 producer 发送 ack(acknowledgement 确认收到),如果 producer 收到 ack,就会进行下一轮的发送,否则重新发送数据。这个问题怎么解决呢?由于index文件中的每条对应log文件中存储内容大小都相同,所以想要找到指定的消息,只需要用index文件中的该条的大小加上该条的偏移量即可得出log文件中指定消息的位置。

2024-04-13 13:26:12 1261

前端知识点总结,课程学习路线及学习链接

前端知识点总结,课程学习路线及学习链接。部分内容如下: ## 基础知识 ### 网络知识 1. [HTTP](https://www.bilibili.com/video/BV1js411g7Fw/) 2. [DNS](https://www.bilibili.com/video/BV1GW411j7Ts/) 3. [域名](https://www.bilibili.com/video/BV1zA411x7Pj/) 4. [云服务](https://www.bilibili.com/video/BV1Rt411u7k4/)

2024-04-17

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

TA关注的人

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