当前位置: 首页 > news >正文

设计模式之单例模式~

设计模式包含很多,但与面试相关的设计模式是单例模式,单例模式的写法有好几种,我们主要学习这三种—饿汉式单例,懒汉式单例、登记式单例,这篇文章我们主要学习饿汉式单例

单例模式:

满足要点:

私有构造
提供静态全局变量
提供专门访问静态全局变量的方法

饿汉式实现:

实现类:

import java.io.Serializable;//1:饿汉式
public class Singleton1 implements Serializable {//私有构造private Singleton1(){System.out.println("private Singleton1");}//提供静态的全局变量private  static final Singleton1 INSTANCE= new Singleton1();//相对于懒汉式是提前创建的//提供专有的方法去获得静态变量public static Singleton1 getInstance(){return  INSTANCE;}public static void otherMethod(){System.out.println("otherMethod()");}
}

测试类:

public class Test_Singleton1 {public static void main(String[] args) {//触发当前类的加载链接--导致该类的初始化操作被创建,当我们调用otherMethod()方法时,该类已经被创建,因为在输出的内容中,包含该类私有构造中的内容Singleton1.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");//下面我们调用getInstance()方法时,得到的对象为上述已经创建好的对象System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());}
}

输出:

private Singleton1
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Singleton1@7ef20235
Singleton1@7ef20235

由于上述的单例我们实现的是Serializable接口,因此很容易被破坏,常见的破坏方式有以下几种:

反射破坏单例:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;public class Test_Singleton1 {Singleton1.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());//反射破坏单例reflection(Singleton1.class);}private static void reflection(Class<?> classz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//通过getDeclaredConstructor获得私有构造Constructor<?> constructor=classz.getDeclaredConstructor();//通过setAccessible使得私有的构造方法也可以被使用constructor.setAccessible(true);//使用newInstance创建新的对象System.out.println("反射创建实例:"+constructor.newInstance());}
}

输出:

private Singleton1
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Singleton1@7ef20235
Singleton1@7ef20235
private Singleton1
反射创建实例:Singleton1@15aeb7ab

经过反射操作的Singleton1已经不是单例了,由于getInstance和反射创建的对象并不是同一个,一个类有两个对象,并不符合单例

newInstance()和new()区别:

创建对象的方式不同,newInstance()是实用类的加载机制,new()则是直接创建一个类newInstance创建类是这个类必须已经加载过且已经连接(Class.forName(“A”)这个过程)new创建类是则不需要这个类加载过

newInstance实际上是把new这个方式分解为两步,首先调用class的加载方法加载某个类,然后实例化,这样做的好处体现在我们可以在调用class的静态加载方法forName时获得更好的灵活性

newInstance 是弱类型(GC是回收对象的限制条件很低,容易被回收)、低效率、只能调用无参构造

new是强类型(GC不会自动回收,只有所有的指向对象的引用被移除是才会被回收,若对象生命周期已经结束,但引用没有被移除,经常会出现内存溢出)

预防反射破坏单例:

解决方法:

在私有构造中加入如下代码,当单例对象已经被创建过时,则直接抛出异常

if(INSTANCE!=null) {throw new RuntimeException("单例对象不能重复创建");
}

测试结果如下:

对象只被创建了一次,第二次通过反射创建对象时,直接抛出异常

在这里插入图片描述

反序列化破坏单例:

import java.io.*;
import java.lang.reflect.InvocationTargetException;public class Test_Singleton1 {public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {Singleton1.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());//反序列化破坏单例serializable(Singleton1.getInstance());}private static void  serializable(Object instance) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();//创建输出流对象ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);//通过writeObject将获取到的对象转变为字节流objectOutputStream.writeObject(instance);//创建文件输入流对象//toByteArray()方法是将一个ByteArrayOutputStream对象转换为byte字符数组返回ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));//通过readObject将转变后的字节流还原成对象System.out.println("反序列化创建实例:"+objectInputStream.readObject());}
}

输出:

这种反序列化的过程不仅可以产生新的对象,且并不实现构造方法

private Singleton1
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Singleton1@7ef20235
Singleton1@7ef20235
反序列化创建实例:Singleton1@1a93a7ca

预防反序列化破坏单例:

解决办法为在Singleton1类中重写readResolve方法,使得它的返回值为初始创建的instance对象,而不是通过反序列化再创建新的对象

public Object readResolve(){return INSTANCE;}

Unsafe破坏单例:

 unsafe(Singleton1.class);private static void unsafe(Class<?> clazz) throws InstantiationException {Object o = UnsafeUtils.getUnsafe().allocateInstance(clazz);System.out.println("Unsafe 创建实例:" + o);
}

Unsafe是JDK内置的一个类,它并不是Java标准类,一般的开发者不会涉及此类的开发,它不需要调用构造函数,且这种破坏方式目前没有解决的办法

枚举类实现饿汉式单例:

enum_Sington类:

public enum enum_Sington {INSTANCE;private enum_Sington(){System.out.println("private enum_Sington()");}public static enum_Sington getInstance(){return INSTANCE;}@Overridepublic String toString() {return getClass().getName()+"@"+Integer.toHexString(hashCode());}public static void otherMethod(){System.out.println("otherMethod()");}
}

测试类:

import java.io.*;
import java.lang.reflect.InvocationTargetException;
public class Test_Sington2 {//单例模式-饿汉式public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException,IOException, ClassNotFoundException {enum_Sington.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");System.out.println(enum_Sington.getInstance());System.out.println(enum_Sington.getInstance());}
}

输出:

private enum_Sington()
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
enum_Sington@7ef20235
enum_Sington@7ef20235

然而对于枚举类,反序列化并不能将其破坏掉,验证如下:

在上述的测试类中加入反序列的代码,如下所示:

 serializable(enum_Sington.getInstance());private static void  serializable(Object instance) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);//通过writeObject将获取到的对象转变为字节流objectOutputStream.writeObject(instance);ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));//通过readObject将转变后的字节流还原成对象System.out.println("反序列化创建实例:"+objectInputStream.readObject());}

输出:

private enum_Sington()
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
enum_Sington@7ef20235
enum_Sington@7ef20235
反序列化创建实例:enum_Sington@7ef20235

通过输出结果,我们会发现,反序列化创建的对象和上述枚举类创建的对象是同一个

那么反射可以破坏吗?

验证如下:

reflection(enum_Sington.class);
private static void reflection(Class<?> classz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//通过getDeclaredConstructor获得私有构造Constructor<?> constructor=classz.getDeclaredConstructor();//通过setAccessible使得私有的构造方法也可以被使用constructor.setAccessible(true);System.out.println("反射创建实例:"+constructor.newInstance());}

在这里插入图片描述

newInstance实例化对象只能调用无参构造方法(如果重写了一个带参构造方法,想要使用newInstance,则必须指定一个无参构造方法,否则会报初始化错误)

在这里插入图片描述

懒汉式实现:

import java.io.Serializable;public class Singleton3 implements Serializable {private Singleton3(){System.out.println("private Singleton3()");}private static Singleton3 INSTACE =null;//开始将其置为null,当要使用它时,才创建该对象public static Singleton3 getInstance() {if (INSTACE == null) {INSTACE = new Singleton3();}return INSTACE;}public static void otherMethod() {System.out.println("otherMethod()");}
}
class Test_Singleton1 {public static void main(String[] args) {//INSTACE对象此时还不会被创建Singleton3.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");//当调用getISTACE方法时,INSTACE对象才会被创建System.out.println(Singleton3.getInstance());System.out.println(Singleton3.getInstance());}
}
otherMethod()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
private Singleton3()
Singleton3@7ef20235
Singleton3@7ef20235

但懒汉式会出现一个问题,也就是不加线程的保护下,多个线程都可以调用getINSTACE方法,那么当多线程调用这个方法时,就会出现下述问题:

线程1首次调用getINSATCE方法,发现INSTACE是null没有被创建,因此进行创建,当线程1执行到if语句中的代码时,线程二也调用该方法,假设此时线程1还没有完成将刚创建好的对象赋值给INSTACE的这个操作,就会出现当线程2调用该方法时,INSTACE显示还是为null,它也会创建新的INSTACE对象,此时就不能被称为是单例了

在这里插入图片描述

这就是我们在多线程环境下执行单例存在的问题,那么该如何解决呢?

给getInstance方法加安全保护,也就是用sychronized进行修饰,其原理就是给该方法加锁

当加锁后的运行过程如下所示:

在这里插入图片描述
在这里插入图片描述

当线程2获得使用权后,进入该方法,发现INSTCE不为null,则不进行该对象的创建,直接返回前面线程1已经创建好的INSTCE对象,这样就能有效的避免多线程下单例模式的正确运行

但这样做的性能并不是最好的,原因是:我们加锁的目的就是为了防止INSTACE被多次创建,这样虽然能够解决首次仅由一个线程创建该对象,但当下次调用该方法的时候,加锁似乎没什么意义,因为对象已经被创建出来了

我们理想的目标是首次调用该方法加锁,而后续调用不加锁

优化方法——使用双检锁:

在这里插入图片描述

注意:

在这里插入图片描述

使用双检锁的INSTACE对象必须用volatile关键字修饰:主要利用内存屏障,保证有序性,在多线程下防止发生指令重排序

private static  volatile Singleton3 INSTACE =null;

内部类实现懒汉式单例:

发生在懒汉式中的多线程安全问题并没有出现在饿汉式实现单例中,原因是我们将其INSTACE对象的创建赋值给了static修饰的变量,而被static修饰的代码最终都会放在静态代码块中执行,而静态代码块中的线程安全并不需要我们去考虑,java虚拟机会帮我们保证其安全

那我们只需想办法将懒汉式中的INSTACE对象创建过程放在一个静态的代码块中即可,如下所示:

内部类也是符合懒汉式的特征,如果内部类没有被使用,那么类的加载链接初始化过程也不会发生,自然写在其中的INSTACE也不会被重复创建,那么什么时候会使用到它呢?

就是调用getInstace方法的时候,因此我们只需要将类的使用过程写在getInstace方法中

import java.io.Serializable;public class Singleton3 implements Serializable {private Singleton3(){System.out.println("private Singleton3()");}private static class Holder {static Singleton3 INSTACE=new Singleton3();}public static Singleton3 getInstance(){return Holder.INSTACE;}public static void otherMethod() {System.out.println("otherMethod()");}
}
class Test_Singleton1 {public static void main(String[] args) {//触发当前类的加载链接--导致该类的初始化操作被创建,当我们调用otherMethod()方法时,该类已经被创建,因为在输出的内容中,包含该类私有构造中的内容Singleton3.otherMethod();System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");//下面我们调用getInstance()方法时,得到的对象为上述已经创建好的对象System.out.println(Singleton3.getInstance());System.out.println(Singleton3.getInstance());}
}

上述使用内部类的懒汉式,也正是我们所推荐的,不仅符合懒汉式的特征,而且可以保证线程安全

相关文章:

设计模式之单例模式~

设计模式包含很多&#xff0c;但与面试相关的设计模式是单例模式&#xff0c;单例模式的写法有好几种&#xff0c;我们主要学习这三种—饿汉式单例&#xff0c;懒汉式单例、登记式单例,这篇文章我们主要学习饿汉式单例 单例模式&#xff1a; 满足要点&#xff1a; 私有构造 …...

top终端详解

1.top命令行使用 2.top每行意义 3.补充 1.top命令行使用 top命令是一个常用的Linux系统命令&#xff0c;用于实时查看系统的运行状态和进程信息。下面是top命令的几个常用参数的含义&#xff1a; -d seconds&#xff1a;设置top命令的更新间隔时间&#xff0c;单位是秒。默认是…...

解决一个偶现的503 bug,花了俺不少时间

概述 在3月2日晚上&#xff0c;大概8点左右&#xff0c;本想打道回府&#xff0c;回家休息&#xff0c;突然被人在bug群了一下&#xff0c;说是管理后台&#xff0c;访问不了&#xff0c;界面上出现了: 503 service temporarily unavailable我赶紧尝试访问了一下&#xff0c;确…...

什么是栈,如何实现?

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; “但有一枝堪比玉&#xff0c;何须九畹始征兰?” 前言&#xff1a; 栈是一种特殊的线性表&#xff0c;就像开盖的桶一样&#xff0c;从底部开始放数据&#xff0c;从顶部开始取数据&#xff0c;那么栈具体是…...

在我的MacBook上捣鼓ESP8266

周三是我们的篮球日&#xff0c;打篮球后总是会有些兴奋&#xff0c;然后就容易睡不着&#xff0c;额&#xff0c;睡不着就拿我的ESP8266开发板出来捣鼓一下。先下载编译工具链https://github.com/espressif/ESP8266_RTOS_SDK下载sdkgit clone https://github.com/espressif/ES…...

【深度强化学习】(8) iPPO 模型解析,附Pytorch完整代码

大家好&#xff0c;今天和各位分享一下多智能体深度强化学习算法 ippo&#xff0c;并基于 gym 环境完成一个小案例。完整代码可以从我的 GitHub 中获得&#xff1a;https://github.com/LiSir-HIT/Reinforcement-Learning/tree/main/Model 1. 算法原理 多智能体的情形相比于单智…...

77.qt qml-QianWindow-V1版本界面讲解

上章介绍: 76.qt qml-QianWindow开源炫酷界面框架简介(支持白色暗黑渐变自定义控件均以适配) 界面如下所示: 代码结构如下所示:...

RHCE学习日记二

1、在 node1 主机上配置 chrony 时间服务器&#xff0c;将该主机作为时间服务器。 命令&#xff1a; vim /etc/chrony.conf 在文件位置添加命令&#xff1a; #Use public servers from the pool.ntp.org project. #Please consider joining the pool (https://www.pool.ntp.org…...

Dubbo原理简介

Dubbo缺省协议采用单一长连接和NIO异步通讯&#xff0c;适合于小数据量大并发的服务调用&#xff0c;以及服务消费者机器数远大于服务提供者机器数的情况。 作为RPC&#xff1a;支持各种传输协议&#xff0c;如dubbo,hession,json,fastjson&#xff0c;底层采用mina,netty长连接…...

JavaSE基础总结

JDK与JRE JDK&#xff0c;全称Java Development Kit&#xff0c;Java开发工具包 JRE&#xff0c;全称Java Runntime Environment&#xff0c;Java运行环境 JDK包含后者JRE。 JDK也可以说是Java SDK&#xff08;Software Development kit&#xff0c;软件开发工具包&#xff09;…...

5G(NR)信道带宽和发射带宽---频率资源

前言 查看此文之前建议先看看这篇 5G(NR)频率资源划分_nr运营商频段划分_达帮主的博客-CSDN博客NR频率有上面几个划分 &#xff0c;可以使用低于1GHz的频端&#xff0c;既可以使用高于30GHz高频端。使用频端高于30GHz那我们称之为高频或者毫米波。使用毫米波是5G网络区别于4G…...

基于Spring Boot的酒店管理系统

文章目录 项目介绍主要功能截图:登录首页房间类型酒店预约部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring Boot的酒店管理系统…...

Ae:混合模式

Ae 中内置了 Ps 的渲染引擎&#xff0c;同样可在多处应用混合模式 Blending Mode。与 Ps 相比&#xff0c;除了两组图层通道相关的特定模式&#xff0c;其它的混合模式几乎是一模一样。相关快捷键&#xff1a;下一图层混合模式&#xff1a;Shift 上一图层混合模式&#xff1a;…...

JS中的变量

系列文章目录 前端系列文章——传送门 JavaScript系列文章——传送门 文章目录系列文章目录前言1、概念2、定义变量3、变量名的规则4、变量本质5、赋值6、常用操作前言 相对于青龙面板来说&#xff0c;变量就是你填入青龙的cookie&#xff0c;简称ck 在实际项目中&#xff0…...

Hadoop运行模块

二、Hadoop运行模式 1&#xff09;Hadoop官方网站&#xff1a;http://hadoop.apache.org 2&#xff09;Hadoop运行模式包括&#xff1a;本地模式、伪分布式模式以及完全分布式模式。 本地模式&#xff1a;单机运行&#xff0c;只是用来演示一下官方案例。生产环境不用。伪分…...

Web自动化——前端基础知识(二)

1. Web前端开发三要素 web前端开发三要素 什么是HTMl&#xff1f; Html是超文本标记语言&#xff0c;是用来描述网页的一种标记语言HTML是一种标签规则的形式将内容呈现在浏览器中可以以任意编辑器创建&#xff0c;其文件扩展名为.html或.htm保存即可 什么是CSS&#xff1f;…...

NAS系列 硬件组装

转自我的博客文章https://blognas.hwb0307.com/nas/3260&#xff0c;内容更新仅在个人博客可见。欢迎关注&#xff01; 前言 之前我在《NAS系列 硬件选择》里讲述了自己为了升级NAS如何选配硬件。本节我大概说一些我的新NAS硬件组装的注意事项。到目前为止&#xff0c;我只装过…...

IDAFrida

IDA&Frida 前言 偶然间发现了一本秘籍《IDA脚本开发之旅》&#xff0c;这是白龙的系列文章&#xff0c;主要是安卓平台&#xff0c;笔者只是根据他的知识点学习&#xff0c;拓展&#xff0c;可以会稍微提及别的平台。本文并不会贴出他的思路分析&#xff0c;只对于源码进…...

通过百度文心一言大模型作画尝鲜,感受国产ChatGPT的“狂飙”

3月16日下午&#xff0c;百度于北京总部召开新闻发布会&#xff0c;主题围绕新一代大语言模型、生成式AI产品文心一言。百度创始人、董事长兼首席执行官李彦宏&#xff0c;百度首席技术官王海峰出席&#xff0c;并展示了文心一言在文学创作、商业文案创作、数理推算、中文理解、…...

Nacos 注册中心 - 健康检查机制源码

目录 1. 健康检查介绍 2. 客户端健康检查 2.1 临时实例的健康检查 2.2 永久实例的健康检查 3. 服务端健康检查 3.1 临时实例的健康检查 3.2 永久实例服务端健康检查 1. 健康检查介绍 当一个服务实例注册到 Nacos 中后&#xff0c;其他服务就可以从 Nacos 中查询出该服务…...

快速部署Super Qwen Voice World:复古像素风语音合成中心体验

快速部署Super Qwen Voice World&#xff1a;复古像素风语音合成中心体验 1. 项目简介与核心价值 Super Qwen Voice World是一个基于Qwen3-TTS技术构建的语音合成平台&#xff0c;它将传统的语音合成过程转化为一场充满趣味的8-bit游戏冒险。这个项目最吸引人的特点是&#x…...

RVC模型计算机组成原理视角:理解AI推理的硬件底层

RVC模型计算机组成原理视角&#xff1a;理解AI推理的硬件底层 你是不是觉得AI模型推理就像一个黑盒子&#xff1f;输入一段音频&#xff0c;点一下按钮&#xff0c;等一会儿&#xff0c;就得到了变声后的结果。整个过程看似简单&#xff0c;但背后却是一场在GPU硬件上精密上演…...

010Editor逆向实战:从爆破到算法还原的完整通关指南(附注册机源码)

010Editor逆向工程深度解析&#xff1a;从关键跳转定位到注册机实现 1. 逆向工程基础与工具链搭建 逆向工程作为软件安全领域的核心技术&#xff0c;要求分析者具备扎实的汇编语言基础和系统级编程经验。在进行010Editor逆向分析前&#xff0c;需要构建完整的工具链环境&#x…...

告别插件冲突!手把手教你手动安装Obsidian动态目录插件(Dynamic Table of Contents)

告别插件冲突&#xff01;Obsidian动态目录插件手动安装全指南 为什么需要手动安装动态目录插件&#xff1f; Obsidian作为一款强大的知识管理工具&#xff0c;其插件生态让用户能够高度自定义工作流。然而&#xff0c;插件间的兼容性问题常常成为用户痛点。许多用户习惯使用Fl…...

DataGrip安装使用全攻略 (DataGrip更改新建查询存储默认位置)

一、DataGrip安装 下载 DataGrip 安装包 访问 DataGrip 官网:https://www.jetbrains.com/datagrip/download ,下载 DataGrip 2025.3.5 版本的安装包: 我这里也有安装包 链接: https://pan.baidu.com/s/1g5aiHWsv9VyIhFD-7TBdEg?pwd=0908 提取码: 0908 --来自百度网盘超…...

基于Transformer架构解析:Nanbeige 4.1-3B 模型原理与性能调优

基于Transformer架构解析&#xff1a;Nanbeige 4.1-3B 模型原理与性能调优 最近在星图GPU平台上部署和测试Nanbeige 4.1-3B模型时&#xff0c;我发现很多朋友对Transformer架构的理解还停留在“听说过”的阶段&#xff0c;对模型参数、显存占用这些概念更是感到头疼。其实&…...

RVC模型C语言底层接口调用:高性能嵌入式音频处理

RVC模型C语言底层接口调用&#xff1a;高性能嵌入式音频处理 1. 引言 你有没有想过&#xff0c;那些小巧的智能音箱、专业的录音笔&#xff0c;或者高端的车载语音助手&#xff0c;它们是怎么在有限的硬件资源下&#xff0c;实现清晰、实时的声音转换和处理的&#xff1f;这背…...

SpringBoot yml 配置文件,读取 Windows 系统环境变量

SpringBoot yml 配置文件&#xff0c;读取 Windows 系统环境变量 在 Spring Boot 的 application.yml 配置文件中读取 Windows 系统环境变量&#xff0c;主要使用 ${VARIABLE_NAME} 占位符语法。 &#x1f527; 在 yml 文件中引用环境变量 在 application.yml 中&#xff0c;你…...

OpenClaw私有化部署详解:Qwen3-VL:30B+飞书机器人配置

OpenClaw私有化部署详解&#xff1a;Qwen3-VL:30B飞书机器人配置 1. 为什么选择私有化部署 去年我在尝试将AI助手引入团队工作流时&#xff0c;遇到了两个棘手问题&#xff1a;一是敏感数据不敢上传到公有云&#xff0c;二是现有解决方案的响应速度总是不尽如人意。直到发现O…...

暗黑破坏神:技术焕新与经典重构——DevilutionX的跨平台复兴之路

暗黑破坏神&#xff1a;技术焕新与经典重构——DevilutionX的跨平台复兴之路 【免费下载链接】devilutionX Diablo build for modern operating systems 项目地址: https://gitcode.com/gh_mirrors/de/devilutionX 在游戏产业飞速迭代的今天&#xff0c;如何让经典IP在现…...