SpringBoot开启多端口探究(1)
文章目录
- 前情提要
- 发散探索
- 从management.port开始
- 确定否需要开启额外端口
- 额外端口是如何开启的
- ManagementContextFactory的故事
- 从哪儿来
- 创建过程
- management 相关API如何被注册
- 小结
前情提要
最近遇到一个需求,在单个服务进程上开启多网络端口,将API的访问通过端口强行隔离开。
发散探索
- SpringBoot自带的多端口配置,server.port和management.port,将常规的API与管理相关API通过端口拆分开;
- 1中的端口是基于HTTP/1.1通信的,如果需要基于HTTP/2.0(如gRPC)又会有些差别;
- 一般一个进程内SpringApplication对象只有1个,理论上搞多个自然就能开启多个端口,略显粗暴;
本着探索的态度,我会逐个探讨上述3个方向,本文先关注在方向1上。如果你有更NB的问题或者建议,欢迎评论区留言。
从management.port开始
配置生效依赖SpringBoot的AutoConfiguration机制,management相关配置体现在ManagementContextAutoConfiguration中,完成ManagementContext的配置;其中涉及的问题如下。
确定否需要开启额外端口
@ConditionalOnManagementPort决定了是否开启新端口,该注解声明如下
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnManagementPortCondition.class)
public @interface ConditionalOnManagementPort {/*** The {@link ManagementPortType} to match.* @return the port type*/ManagementPortType value();}
其依赖的OnManagementPortCondition会在配置过程中被处理,处理概要过程如下:
- 基于当前的Environment决定实际的ManagementPortType;
- 获得当前注解中value对应的设定ManagementPortType;
- 基于1和2决定被其注解的bean是否初始化,ManagementPortType的定义如下
public enum ManagementPortType {/*** The management port has been disabled.*/DISABLED,/*** The management port is the same as the server port.*/SAME,/*** The management port and server port are different.*/DIFFERENT;/*** Look at the given environment to determine if the {@link ManagementPortType} is* {@link #DISABLED}, {@link #SAME} or {@link #DIFFERENT}.* @param environment the Spring environment* @return {@link #DISABLED} if {@code management.server.port} is set to a negative* value, {@link #SAME} if {@code management.server.port} is not specified or equal to* {@code server.port} and {@link #DIFFERENT} otherwise.* @since 2.1.4*/public static ManagementPortType get(Environment environment) {Integer managementPort = getPortProperty(environment, "management.server.");if (managementPort != null && managementPort < 0) {return DISABLED;}Integer serverPort = getPortProperty(environment, "server.");return ((managementPort == null || (serverPort == null && managementPort.equals(8080))|| (managementPort != 0 && managementPort.equals(serverPort))) ? SAME : DIFFERENT);}private static Integer getPortProperty(Environment environment, String prefix) {return environment.getProperty(prefix + "port", Integer.class);}}
额外端口是如何开启的
到这里,我们可以回到ManagementContextAutoConfiguration,针对性地关注@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)相关类, 也就是下面这段
@Configuration(proxyBeanMethods = false)@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)static class DifferentManagementContextConfiguration implements ApplicationListener<WebServerInitializedEvent> {private final ApplicationContext applicationContext;private final ManagementContextFactory managementContextFactory;DifferentManagementContextConfiguration(ApplicationContext applicationContext,ManagementContextFactory managementContextFactory) {this.applicationContext = applicationContext;this.managementContextFactory = managementContextFactory;}@Overridepublic void onApplicationEvent(WebServerInitializedEvent event) {if (event.getApplicationContext().equals(this.applicationContext)) {ConfigurableWebServerApplicationContext managementContext = this.managementContextFactory.createManagementContext(this.applicationContext,EnableChildManagementContextConfiguration.class,PropertyPlaceholderAutoConfiguration.class);if (isLazyInitialization()) {managementContext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}managementContext.setServerNamespace("management");managementContext.setId(this.applicationContext.getId() + ":management");setClassLoaderIfPossible(managementContext);CloseManagementContextListener.addIfPossible(this.applicationContext, managementContext);managementContext.refresh();}}protected boolean isLazyInitialization() {AbstractApplicationContext context = (AbstractApplicationContext) this.applicationContext;List<BeanFactoryPostProcessor> postProcessors = context.getBeanFactoryPostProcessors();return postProcessors.stream().anyMatch(LazyInitializationBeanFactoryPostProcessor.class::isInstance);}private void setClassLoaderIfPossible(ConfigurableApplicationContext child) {if (child instanceof DefaultResourceLoader) {((DefaultResourceLoader) child).setClassLoader(this.applicationContext.getClassLoader());}}}
从中我们可以发现几个点:
- ManagementContext是在主WebApplicationContext发布事件WebServerInitializedEvent后开始初始化;
- ManagementContext全新的ConfigurableWebServerApplicationContext,这意味着最终启动后,内存中存在至少两个ApplicationContext;如果说开启两个SpringApplication对象是表象的话,那么创建两个WebApplicationContext应该说就是底层的本质了;
- 整个处理过程就是创建ConfigurableWebServerApplicationContext,后续做必要的配置,最后refresh。如果你分析过SpringApplication.run(),那想必你看到了熟悉的味道。
ManagementContextFactory的故事
从哪儿来
对应的子类有两个,ReactiveManagementContextFactory和ServletManagementContextFactory,具体初始化则由xxxManagementContextFactoryAutoConfiguration影响,更进一步的细节藏在
@ConditionalOnWebApplication(type=xxx)中。
创建过程
以ReactiveManagementContextFactory为例
@Overridepublic ConfigurableWebServerApplicationContext createManagementContext(ApplicationContext parent,Class<?>... configClasses) {// 复用EnvironmentEnvironment parentEnvironment = parent.getEnvironment();ConfigurableEnvironment childEnvironment = ApplicationContextFactory.DEFAULT.createEnvironment(WebApplicationType.REACTIVE);if (parentEnvironment instanceof ConfigurableEnvironment) {// 复用ConversionServicechildEnvironment.setConversionService(((ConfigurableEnvironment) parentEnvironment).getConversionService());}AnnotationConfigReactiveWebServerApplicationContext child = new AnnotationConfigReactiveWebServerApplicationContext();child.setEnvironment(childEnvironment);// 这里可以看到最终会是parent和child关系child.setParent(parent);/*
这里以编程的方式完成BeanDefinition注册, 这里的configClass = {EnableChildManagementContextConfiguration.class,PropertyPlaceholderAutoConfiguration.class} */Class<?>[] combinedClasses = ObjectUtils.addObjectToArray(configClasses,ReactiveWebServerFactoryAutoConfiguration.class);child.register(combinedClasses);// 最后保持parent和child的WebFactory一致, 直接复用parent的BeanDefinitionregisterReactiveWebServerFactory(parent, child);return child;}
management 相关API如何被注册
经过前面一波分析,我们已经看到了创建ApplicationContext,注册必要的Class,而后refresh整个容器就要启动,但没有看到management相关API,其实就藏在EnableChildManagementContextConfiguration.class这里, 从这里出发最终找到配置文件ManagementContextConfiguration.imports,链路如下
EnableManagementContext -> ManagementContextConfigurationImportSelector -> META-INFO/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports
ManagementContextConfiguration.imports的内容如下:
org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.security.servlet.SecurityRequestMatchersManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyChildManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration
这些Configuration最终受如下2个注解的解决决定是否初始化
@ManagementContextConfiguration(value = ManagementContextType.xxx, proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.xxx)
最终不同的EndPoint由不同的EndPointDiscover对整个ApplicationContext中的类进行扫描并提取出来,组装为EndPointHandlerMapping。
到这里可以解释一个现象,就是在manage端口上,无法访问到应用端口上的API,因为两者各自关联了一个独立的HandlerMapping。虽然通常child context可以访问到parent context中的所有bean实例,但是各自可见的API被各自的RequestHandlerMapping限制而隔离。
小结
以上是针对mangement API开放独立端口的探究,从中有几个点值得借鉴:
- 独立的ApplicationContext可以作为资源隔离的一种方式,同时又不完全失去与parent的联系;
- 条件初始化在SpringBoot自动配置中的广泛应用;
- WebApplicationContext与ApplicationContext的区别在于WebServerFactory是否存在,以及RequestHandlerMapping+必要的注解识别,有了这点发现,做API隔离可用的方案也会更加丰富;
后续会对另外2种实现方式做探讨,感谢你的阅读。
相关文章:
SpringBoot开启多端口探究(1)
文章目录 前情提要发散探索从management.port开始确定否需要开启额外端口额外端口是如何开启的ManagementContextFactory的故事从哪儿来创建过程 management 相关API如何被注册 小结 前情提要 最近遇到一个需求,在单个服务进程上开启多网络端口,将API的…...
优化算法:2.粒子群算法(PSO)及Python实现
一、定义 粒子群算法(Particle Swarm Optimization,PSO)是一种模拟鸟群觅食行为的优化算法。想象一群鸟在寻找食物,每只鸟都在尝试找到食物最多的位置。它们通过互相交流信息,逐渐向食物最多的地方聚集。PSO就是基于这…...
ThreadLocal面试三道题
针对ThreadLocal的面试题,我将按照由简单到困难的顺序给出三道题目,并附上参考答案的概要。 1. 简单题:请简述ThreadLocal是什么,以及它的主要作用。 参考答案: ThreadLocal是Java中的一个类,用于提供线…...
Git操作指令(已完结)
Git操作指令 一、安装git 1、设置配置信息: # global全局配置 git config --global user.name "Your username" git config --global user.email "Your email"# 显示颜色 git config --global color.ui true# 配置别名,各种指令都…...
大数据采集工具——Flume简介安装配置使用教程
Flume简介&安装配置&使用教程 1、Flume简介 一:概要 Flume 是一个可配置、可靠、高可用的大数据采集工具,主要用于将大量的数据从各种数据源(如日志文件、数据库、本地磁盘等)采集到数据存储系统(主要为Had…...
C语言 #具有展开功能的排雷游戏
文章目录 前言 一、整个排雷游戏的思维梳理 二、整体代码分布布局 三、游戏主体逻辑实现--test.c 四、整个游戏头文件的引用以及函数的声明-- game.h 五、游戏功能的具体实现 -- game.c 六、老六版本 总结 前言 路漫漫其修远兮,吾将上下而求索。 一、整个排…...
npm publish出错,‘proxy‘ config is set properly. See: ‘npm help config‘
问题:使用 npm publish发布项目依赖失败,报错 proxy config is set properly. See: npm help config 1、先查找一下自己的代理 npm config get proxy npm config get https-proxy npm config get registry2、然后将代理和缓存置空 方式一: …...
Springboot 多数据源事务
起因 在一个service方法上使用的事务,其中有方法是调用的多数据源orderDB 但是多数据源没有生效,而是使用的primaryDB 原因 spring 事务实现的方式 以 Transactional 注解为例 (也可以看 TransactionTemplate, 这个流程更简单一点)。 入口:ProxyTransa…...
Python每日学习
我是从c转来学习Python的,总感觉和c相比Python的实操简单,但是由于写c的代码多了,感觉Python的语法好奇怪 就比如说c的开头要有库(就是类似于#include <bits/stdc.h>)而且它每一项的代码结束之后要有一个表示结…...
数据库 执行sql添加删除字段
添加字段: ALTER TABLE 表明 ADD COLUMN 字段名 类型 DEFAULT NULL COMMENT 注释 AFTER 哪个字段后面; 效果: 删除字段: ALTER TABLE 表明 DROP COLUMN 字段;...
前端开发:HTML与CSS
文章目录 前言1.1、CS架构和BS架构1.2、网页构成 HTML1.web开发1.1、最简单的web应用程序1.2、HTTP协议1.2.1 、简介1.2.2、 http协议特性1.3.3、http请求协议与响应协议 2.HTML概述3.HTML标准结构4.标签的语法5.基本标签6.超链接标签6.1、超链接基本使用6.2、锚点 7.img标签8.…...
ctfshow解题方法
171 172 爆库名->爆表名->爆字段名->爆字段值 -1 union select 1,database() ,3 -- //返回数据库名 -1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema库名 -- //获取数据库里的表名 -1 union select 1,group_concat(…...
探索 Blockly:自定义积木实例
3.实例 3.1.基础块 无输入 , 无输出 3.1.1.json var textOneJson {"type": "sql_test_text_one","message0": " one ","colour": 30,"tooltip": 无输入 , 无输出 };javascriptGenerator.forBlock[sql_test_te…...
MongoDB教程(二十三):关于MongoDB自增机制
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…...
展馆导览系统架构解析,从需求分析到上线运维
在物质生活日益丰富的当下,人们对精神世界的追求愈发强烈,博物馆、展馆、纪念馆等场所成为人们丰富知识、滋养心灵的热门选择。与此同时,人们对展馆的导航体验也提出了更高要求,展馆导览系统作为一种基于室内外地图相结合的位置引…...
Servlet详解(超详细)
Servlet详解 文章目录 Servlet详解一、基本概念二、Servlet的使用1、创建Servlet类2、配置Servleta. 使用web.xml配置b. 使用注解配置 3、部署Web应用4、处理HTTP请求和生成响应5、处理表单数据HTML表单Servlet 6、管理会话 三、servlet生命周期1、加载和实例化2、初始化3、 请…...
Meta AI引入Imagine Me功能,上传图片输入提示词即可实现个性化照片
AITOP100平台获悉,Meta 公司在 AI 领域再次迈出了重要的步伐,其发布的 Llama 3.1 开源 AI 模型以及对 Meta AI 功能的更新扩充引发了广泛关注。 其中,新引入的“Imagine Me”功能尤为引人注目。在这一功能下,美国地区的用户只需上…...
常用自启设置
一、开机自启动 1、编辑 vi /lib/systemd/system/nginx.service 文件,没有创建一个 touch nginx.service 然后将如下内容根据具体情况进行修改后,添加到nginx.service文件中: [Unit] Descriptionnginx Afternetwork.target remote-fs.targ…...
模块与组件、模块化与组件化的理解
在React或其他现代JavaScript框架中,模块与组件、模块化与组件化是核心概念,它们对于提高代码的可维护性、复用性和开发效率具有重要意义。以下是对这些概念的理解: 模块与组件 模块(Module) 定义:模块是…...
Rust:cargo的常用命令
1.查看版本 $ cargo --version cargo 1.79.0 (ffa9cf99a 2024-06-03) 2.创建新的项目 $ cargo new hello 创建后的目录结构为 $ tree hello/ hello/ ├── Cargo.toml └── src └── main.rs 3.运行项目 $ cd hello $ cargo run Compiling hello v0.1.0 (/home/c…...
LeetCode 3106.满足距离约束且字典序最小的字符串:模拟(贪心)
【LetMeFly】3106.满足距离约束且字典序最小的字符串:模拟(贪心) 力扣题目链接:https://leetcode.cn/problems/lexicographically-smallest-string-after-operations-with-constraint/ 给你一个字符串 s 和一个整数 k 。 定义函…...
Elasticsearch 与 MySQL 在查询和插入性能上的深度剖析
在当今的数据处理领域,选择合适的数据库对于应用的性能和效率至关重要。Elasticsearch 和 MySQL 作为两款常用的数据库,它们在查询和插入操作上的性能表现各有千秋。本文将对这两款数据库在这两个关键操作上进行详细的对比分析。 一、引言 随着数据量的…...
day4 vue2以及ElementUI
创建vue2项目 可能用到的命令行们 vue create 项目名称 // 创建项目 cd 项目名称 // 只有进入项目下,才能运行 npm run serve // 运行项目 D: //切换盘符 cd .. // 返回到上一级目录 clear // 清空终端 更改 Vue项目的端口配置 基础语法 项目创建完成之后&#…...
把redis用在Java项目
1. Java连接redis Java连接redis的方式是通过jedis,连接redis需要遵循jedis协议。 1.1 引入依赖 <!--引入java连接redis的驱动--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version&…...
GORM:优雅的Go语言ORM库
文章目录 引言GORM原理基础使用安装GORM定义模型连接数据库CRUD操作 高级使用关联事务回调 优点结论 引言 在Go语言开发中,数据库操作是不可或缺的一部分。虽然直接使用SQL语句可以灵活地与数据库交互,但随着项目规模的扩大,SQL语句的编写、…...
Golang | Leetcode Golang题解之第279题完全平方数
题目: 题解: // 判断是否为完全平方数 func isPerfectSquare(x int) bool {y : int(math.Sqrt(float64(x)))return y*y x }// 判断是否能表示为 4^k*(8m7) func checkAnswer4(x int) bool {for x%4 0 {x / 4}return x%8 7 }func numSquares(n int) i…...
Oracle系统表空间的加解密
实验环境 数据库选择的是orclpdb1,当前系统表空间未加密: SQL> show con_nameCON_NAME ------------------------------ ORCLPDB1SQL> select TABLESPACE_NAME, STATUS, ENCRYPTED from dba_tablespaces;TABLESPACE_NAME STATUS …...
pytorch backbone
1 简介 在PyTorch深度学习中,预训练backbone(骨干网络)是一个常见的做法,特别是在处理图像识别、目标检测、图像分割等任务时。预训练backbone通常是指在大型数据集(如ImageNet)上预先训练好的卷积神经网络…...
uniapp 开发app使用renderjs操作dom
需求:把页面中的对话内容另存为一张图片保存到手机相册。 解决方案:这时我们需要使用到document对象创建一个dom对象计算对话内容的宽高、位置等,再利用canvas能力将内容绘制绘制成一张图保存。 现状:总所周知,非H5端&…...
【面试题】MySQL `EXPLAIN`的`Extra`字段:深入解析查询优化的隐藏信息
MySQL EXPLAIN的Extra字段:深入解析查询优化的隐藏信息 引言 在MySQL的EXPLAIN输出中,Extra字段提供了关于查询执行计划的额外信息。这些信息对于理解查询的内部工作机制和优化查询性能至关重要。本文将详细解析Extra字段中常见的几个关键指标…...
Jenkins持续部署
开发环境任务的代码只要有更新,Jenkins会自动获取新的代码并运行 1. pycharm和git本地集成 获取到下面的 Git可执行文件路径 2. pycharm和gitee远程仓库集成 先在pycharm中安装gitee插件 在设置中找到gitee,点击添加账户,并将自己的账户添…...
橙单前端项目下载编译遇到的问题与解决
今天下载orange-admin前端项目,不过下载下来运行也出现一些问题。 1、运行出现下面一堆错误,如下: 2、对于下面这个错误 error Expected linebreaks to be LF but found CRLF linebreak-style 这就是eslint的报错了,可能是原作者…...
在android中怎么处理后端返回列表中包含图片id,如何将列表中的图片id转化成url
在 Android 中实现从包含图片 ID 的列表获取实际图片 URL 并显示图片,你可以使用以下步骤: 定义数据模型:创建一个 Java 或 Kotlin 类来表示列表中的对象。 网络请求:使用 Retrofit 或其他网络库来获取图片 URL。 异步处理:使用 AsyncTask、RxJava 或 Kotlin 协程来处理网…...
IM聊天代码
客户端 Headers inet inet.h #pragma once #include<Winsock2.h>//#pragma comment(lib,"Ws2_32.lib")class INetMediator; class INet { public:INet(){}virtual ~INet(){}//初始化网络virtual bool initNet() 0;//接收数据virtual void recvData() 0;…...
【Go - context 速览,场景与用法】
作用 context字面意思上下文,用于关联管理上下文,具体有如下几个作用 取消信号传递:可以用来传递取消信号,让一个正在执行的函数知道它应该提前终止。超时控制:可以设定一个超时时间,自动取消超过执行时间…...
Linus: vim编辑器的使用,快捷键及配置等周边知识详解
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 vim的安装创建新用户 adduser 用户名Linus是个多用户的操作系统是否有创建用户的权限查看当前用户身份:whoami** 怎么创建设置密码passwdsudo提权(sudo输入的是用户…...
数仓作业延时告警-基于关键路径预推
简介 作业延时告警,通常来说有两种方式: 其一,当作业到目标时间点还没完成触发告警;这类情况,对于目标作业而言,延时已经触发了,风险相对较大;有的是监控接口延时(raw层…...
秋招复习笔记——八股文部分:网络TCP
TCP 三次握手和四次挥手 TCP 基本认识 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。 确认应答号…...
麒麟桌面操作系统上配置Samba
原文链接:麒麟桌面操作系统上配置Samba Hello,大家好啊!今天给大家带来一篇关于在麒麟桌面操作系统上配置Samba的文章。Samba是一种免费的软件,实现了SMB/CIFS网络协议,使得Linux和Windows系统之间可以共享文件和打印机…...
【Go】探索 Go 语言的内建函数 copy
山水间歌声回荡 回荡思念的滚烫 去年的家书两行 读来又热了眼眶 云水边静沐暖阳 烟波里久违的故乡 别来无恙 你在心上 🎵 张靓颖/张杰《燕归巢》 在 Go 语言中,copy 是一个用于在切片之间复制元素的内建函数。它提供了一种简单而高…...
【React】JSX:从基础语法到高级用法的深入解析
文章目录 一、什么是 JSX?1. 基础语法2. 嵌入表达式3. 使用属性4. JSX 是表达式 二、JSX 的注意事项1. 必须包含在单个父元素内2. JSX 中的注释3. 避免注入攻击 三、JSX 的高级用法1. 条件渲染2. 列表渲染3. 内联样式4. 函数作为子组件 四、最佳实践 在 React 开发中…...
JMeter 使用
1.JMeter 是什么? JMeter 是一款广泛使用的开源性能测试工具,由 Apache 软件基金会维护。它主要用于测试 Web 应用程序的负载能力和性能,但也支持其他类型的测试,如数据库、FTP、JMS、LDAP、SOAP web services 等。 2.特点&#x…...
20240724----安装git和配置git的环境变量/如何用命令git项目到本地idea
备注参考博客: 1)可以参考博客,用git把项目git到本地 2)可以参考博客vcs没有git 3)git版本更新,覆盖安装 (一)安装git (1)官网下载的链接 https://git-scm.com/downlo…...
JavaScript实战 - 用Canvas画一个心形
作者:逍遥Sean 简介:一个主修Java的Web网站\游戏服务器后端开发者 主页:https://blog.csdn.net/Ureliable 觉得博主文章不错的话,可以三连支持一下~ 如有疑问或建议,请私信或评论留言! 前言: 如…...
vim gcc
vim 使用 vs filename 分屏 ctrl ww 切窗口 shift zz 快速提出vim vim配置 vim启动时自动读取当前用户的家目录的.vimrc文件 vim配置只影响本用户 其他用户观看同一文件不受影响 gcc指令 & c文件编译过程 动态库 静态库 & 链接方式 有相应库才能进行…...
Symfony 表单构建器:创建和管理表单的最佳实践
Symfony 表单构建器:创建和管理表单的最佳实践 Symfony 是一个流行的 PHP 框架,以其强大的功能和灵活性闻名。表单构建器是 Symfony 中一个非常重要的组件,它提供了简单且高效的方式来创建和管理表单。本文将详细介绍 Symfony 表单构建器的最…...
Intel电脑CPU的选择
酷睿 i5/i7/i9 系列至强 Xeon 系列应用场景家用消费级电脑企业服务器工作站PCIe通道数 16X 最多识别到2张显卡,且每张降速为8X 64X 最多支持8张显卡同时使用 内存信道2通道8通道内存容量最大128GB最大6TB工作时长不建议长期不间断连续使用专为365*24不断电使用而设…...
MySQL字段设置的varchar长度小于数据长度自动截取丢弃超出的长度而不是报错?
MySQL字段设置的varchar长度小于数据长度自动截取丢弃超出的长度而不是报错? 事情是这样的,我们一个订单表存放了商品的快照信息其中快照信息存储的是json格式商品信息,当查看订单是报错了,发现我们后端服务查询到订单的快照信息…...
Linux|多线程(三)
线程池 线程池是一种多线程处理形式,处理过程中它将被提交的任务分配给预先创建好的多个线程中的一个去执行。 线程池的实现 #pragma once #include <pthread.h> #include <vector> #include <string> #include <unistd.h> #include <…...
智能合约中如何返回mapping
在 Solidity 中,直接返回一个 mapping 的所有数据是不可能的,因为 mapping 本身不支持直接遍历。但是,可以使用一些技巧来实现这一目标,例如通过维护一个额外的数组来跟踪 mapping 中的键,并通过这个数组来返回所有的键…...