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

websocket中spring注入失效

一个null指针引发的思考

websocket中spring注入失效

  • 一个null指针引发的思考
    • 场景
    • 代码
        • SpringBoot入口类
        • 配置类
        • websocket类
    • 问题
      • 排查
        • 问题1:
        • 问题2:
    • 反思
    • 解决
      • 方案一:
      • 方案二:
      • 方案三:
      • 方案四:

场景

首页有个websocket的连接,初始化的时候需要去后台获取数据,然后会定时5s一次获取后端的数据。

代码

SpringBoot入口类

扫描注册到spring中

package com;import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;@ComponentScan(basePackages = {com.xxx})//扫描com.xxx及子包
@EnableScheduling//开启定时任务
@SpringBootApplication //启动springboot
public class Application implements ApplicationRunner {public static void main(String[] args) throws Exception {SpringApplication.run(Application.class, args);}@Overridepublic void run(ApplicationArguments args) throws Exception {}}
配置类
package com.xxx.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
websocket类

实现和web前端的交互,获取web后端的数据

package com.xxx.webSocket;import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xxx.service.IOverviewService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;/*** 首页概况** @author 阿明* @date 2023/11/30-15:39*/
@Slf4j
@ServerEndpoint("/websocket/v3/overview")
@Component
public class WebSocketServerOverview {private static final int CARD = 5;private static final Map<String, DataWrap<OverviewVo>> dataWrapMap = new ConcurrentHashMap<>();@Resourceprivate IOverviewService overviewService;@Scheduled(cron = "*/5 * * * * ? ")public void sendCard() throws InterruptedException {try {for (DataWrap<OverviewVo> value : dataWrapMap.values()) {OverviewVo overviewData = overviewService.card();//new CardVo(totalDatas, cls, toDay, history, totalRules, use, cpu, hardDisk, memory, traffic);value.getSession().getBasicRemote().sendText(JSONUtil.toJsonStr(overviewData));}} catch (IOException e) {log.error("websocket overview错误:", e);}}/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session) {log.info("连接成功");}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(Session session) {Iterator<DataWrap<OverviewVo>> iterator = dataWrapMap.values().iterator();while (iterator.hasNext()) {DataWrap<OverviewVo> value = iterator.next();if (value.getSession().equals(session)) {//清除缓存数据 value.getType()iterator.remove();}}log.info("连接关闭");}/*** 收到客户端消息后调用的方法,第一次连接成功,这里会发送一次消息** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {JSONObject jsonObject = JSONUtil.parseObj(message);//无效消息,避免发送心跳解析失败if (jsonObject.isNull("userId")) {return;}String userId = (String) jsonObject.get("userId");Integer type = (Integer) jsonObject.get("type");Integer dataId = null;if (!jsonObject.isNull("dataId")) {dataId = (Integer) jsonObject.get("dataId");}if (!dataWrapMap.containsKey(userId + "_" + type) || dataWrapMap.containsKey(userId + "_" + type) && !Objects.equals(dataWrapMap.get(userId + "_" + type).getDataId(), dataId)) {DataWrap<OverviewVo> dataWrap = new DataWrap<>(userId, type, dataId, session, new LinkedList<>());try {switch (type) {case CARD:dataWrapMap.put(userId + "_" + type, dataWrap);OverviewVo overviewData = overviewService.card();//overviewService会是null;// OverviewVo overviewData = SpringUtil.getBean(IOverviewService.class).card();session.getBasicRemote().sendText(JSONUtil.toJsonStr(overviewData));break;default:break;}} catch (IOException e) {log.error("websocket overview错误:", e);}}log.info("收到..消息:" + message);}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {Iterator<DataWrap<OverviewVo>> iterator = dataWrapMap.values().iterator();while (iterator.hasNext()) {DataWrap value = iterator.next();if (value.getSession().equals(session)) {iterator.remove();}}log.error("发生错误", error);}
}

问题

小A问我他项目遇到个问题,前端页面先和后端建立连接,等连接成功后,前端会发送个{“type”:5,“userId”:“admin-uuid”}给到后端,开始的时候用的@Scheduled注解的sendCard方法5s一执行,执行到overviewService正常返回数据,今天测试说,你这个一进来没数据,等5s才有数据,想让首页一进来就有数据,所以他就打算前端发送上来数据直接去查库,返回一次数据,返回的时候OnMessage注解的onMessage方法中overviewService属性一直为空,想不到为啥为null。

排查

  • 这个时候的思路肯定是执行的OnMessage注解的onMessage方法没走spring的bean,具体是为啥,开始分析,经过排查发现
问题1:

Tomcat 在 org.apache.tomcat.websocket.server.WsServerContainer 里注册 @ServerEndpoint

@Override
public void addEndpoint(Class<?> clazz) throws DeploymentException {ServerEndpoint annotation = clazz.getAnnotation(ServerEndpoint.class);if (annotation == null) {throw new DeploymentException("Missing @ServerEndpoint annotation");}ServerEndpointConfig sec = ServerEndpointConfig.Builder.create(clazz, annotation.value()).build();addEndpoint(sec);
}

📌 关键点

  • Tomcat 通过 clazz.getAnnotation(ServerEndpoint.class) 发现 @ServerEndpoint 标注的类
  • Tomcat 直接 new 这个类(它不会用 Spring 方式去创建 Bean)
  • Spring 的 @Component@Autowired 机制不会生效
问题2:

其实这个不算问题,算是为什么。

@Scheduled 是由 Spring 管理的,所以 @Autowired 可以用。
@ServerEndpoint 由 Tomcat 创建,不是 Spring Bean,所以 @Autowired 不能用。
💡 如果想在 WebSocket 里用 @Autowired 的 Bean,可以用 staticSpringContextUtil 获取。

Spring 类加载器加载的@Scheduled 注解的类,WebSocket 容器类加载器加载的@ServerEndpoint 注解的类。

反思

  • 做java的一直用spring,虽然spring帮我们做了很多事,但是也让我们养成了懒惰的思维,习惯了spring的依赖注入,然后想当然的认为都可以直接依赖使用,这种惯性思维导致了这种问题。

解决

方案一:

可以注释掉overviewService使用SpringUtil.getBean(IOverviewService.class)替代,这种直接使用spring的上下文直接取IOverviewService类对象,肯定是取到了,直接用就行。

方案二:

使用SpringConfigurator 来注入 Spring Bean

package com.xxx.autoconfig;import cn.hutool.extra.spring.SpringUtil;
import org.springframework.context.ApplicationContext;import javax.websocket.server.ServerEndpointConfig;public class SpringConfigurator extends ServerEndpointConfig.Configurator {@Overridepublic <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {ApplicationContext applicationContext = SpringUtil.getApplicationContext();if (applicationContext == null) {throw new InstantiationException("Spring ApplicationContext is null");}return applicationContext.getBean(clazz);}
}
@ServerEndpoint("/websocket/v3/overview")改为
@ServerEndpoint(value = "/websocket/v3/overview", configurator = SpringConfigurator.class)

方案三:

  • 使用 @Component + ServerEndpointExporter没管用,证明WebSocket 端点的实例仍然不是由 Spring 管理的,而是由 Tomcat管理的。最终看源码:

    package org.springframework.web.socket.server.standard;
    public class ServerEndpointExporter extends WebApplicationObjectSupportimplements InitializingBean, SmartInitializingSingleton {protected void registerEndpoints() {Set<Class<?>> endpointClasses = new LinkedHashSet<>();if (this.annotatedEndpointClasses != null) {endpointClasses.addAll(this.annotatedEndpointClasses);}ApplicationContext context = getApplicationContext();if (context != null) {String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);for (String beanName : endpointBeanNames) {//这里虽然会执行,但是最终的这个bean是放到tomcat里边了endpointClasses.add(context.getType(beanName));}}for (Class<?> endpointClass : endpointClasses) {registerEndpoint(endpointClass);}if (context != null) {Map<String, ServerEndpointConfig> endpointConfigMap = context.getBeansOfType(ServerEndpointConfig.class);for (ServerEndpointConfig endpointConfig : endpointConfigMap.values()) {registerEndpoint(endpointConfig);}}}
    

    源码主要是这里tomcat-embed-websocket-9.0.39.jar

    package org.apache.tomcat.websocket.server; 
    public class WsServerContainer extends WsWebSocketContainerimplements ServerContainer {void addEndpoint(Class<?> pojo, boolean fromAnnotatedPojo) throws DeploymentException {if (deploymentFailed) {throw new DeploymentException(sm.getString("serverContainer.failedDeployment",servletContext.getContextPath(), servletContext.getVirtualServerName()));}ServerEndpointConfig sec;try {ServerEndpoint annotation = pojo.getAnnotation(ServerEndpoint.class);if (annotation == null) {throw new DeploymentException(sm.getString("serverContainer.missingAnnotation",pojo.getName()));}String path = annotation.value();// Validate encodersvalidateEncoders(annotation.encoders());// ServerEndpointConfig 这里使用了Configurator,这里就是为啥方案二能成功的原因。Class<? extends Configurator> configuratorClazz =annotation.configurator();Configurator configurator = null;if (!configuratorClazz.equals(Configurator.class)) {try {configurator = annotation.configurator().getConstructor().newInstance();} catch (ReflectiveOperationException e) {throw new DeploymentException(sm.getString("serverContainer.configuratorFail",annotation.configurator().getName(),pojo.getClass().getName()), e);}}//这里直接拿到这个类从tomcat生成了sec = ServerEndpointConfig.Builder.create(pojo, path).decoders(Arrays.asList(annotation.decoders())).encoders(Arrays.asList(annotation.encoders())).subprotocols(Arrays.asList(annotation.subprotocols())).configurator(configurator).build();} catch (DeploymentException de) {failDeployment();throw de;}addEndpoint(sec, fromAnnotatedPojo);}
    

方案四:

  • 见网上好多用@EnableWebSocket的我是没成功,去官网找的用@EnableWebSocketMessageBroker这种更好,格式更规范

  • 用spring自己的websocketGetting Started | Using WebSocket to build an interactive web application

  • git clone https://github.com/spring-guides/gs-messaging-stomp-websocket.git

接受实体类HelloMessage

package com.example.messagingstompwebsocket;public class HelloMessage {private String name;public HelloMessage() {}public HelloMessage(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

发送实体类Greeting

package com.example.messagingstompwebsocket;public class Greeting {private String content;public Greeting() {}public Greeting(String content) {this.content = content;}public String getContent() {return content;}}

控制层GreetingController

package com.example.messagingstompwebsocket;import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;@Controller
public class GreetingController {@MessageMapping("/hello")@SendTo("/topic/greetings")public Greeting greeting(HelloMessage message) throws Exception {Thread.sleep(1000); // simulated delayreturn new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");}}

配置类WebSocketConfig

package com.example.messagingstompwebsocket;import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/topic");//配置订阅消息的目标前缀config.setApplicationDestinationPrefixes("/app");//配置应用程序的目的地前缀}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/gs-guide-websocket");//配置端点}}

启动类MessagingStompWebsocketApplication

package com.example.messagingstompwebsocket;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MessagingStompWebsocketApplication {public static void main(String[] args) {SpringApplication.run(MessagingStompWebsocketApplication.class, args);}
}

主页面index.html

<!DOCTYPE html>
<html>
<head><title>Hello WebSocket</title><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><link href="/main.css" rel="stylesheet"><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@7.0.0/bundles/stomp.umd.min.js"></script><script src="/app.js"></script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript beingenabled. Please enableJavascript and reload this page!</h2></noscript>
<div id="main-content" class="container"><div class="row"><div class="col-md-6"><form class="form-inline"><div class="form-group"><label for="connect">WebSocket connection:</label><button id="connect" class="btn btn-default" type="submit">Connect</button><button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect</button></div></form></div><div class="col-md-6"><form class="form-inline"><div class="form-group"><label for="name">What is your name?</label><input type="text" id="name" class="form-control" placeholder="Your name here..."></div><button id="send" class="btn btn-default" type="submit">Send</button></form></div></div><div class="row"><div class="col-md-12"><table id="conversation" class="table table-striped"><thead><tr><th>Greetings</th></tr></thead><tbody id="greetings"></tbody></table></div></div>
</div>
</body>
</html>

app.js

const stompClient = new StompJs.Client({brokerURL: 'ws://localhost:8080/gs-guide-websocket'
});stompClient.onConnect = (frame) => {setConnected(true);console.log('Connected: ' + frame);stompClient.subscribe('/topic/greetings', (greeting) => {showGreeting(JSON.parse(greeting.body).content);});
};stompClient.onWebSocketError = (error) => {console.error('Error with websocket', error);
};stompClient.onStompError = (frame) => {console.error('Broker reported error: ' + frame.headers['message']);console.error('Additional details: ' + frame.body);
};function setConnected(connected) {$("#connect").prop("disabled", connected);$("#disconnect").prop("disabled", !connected);if (connected) {$("#conversation").show();}else {$("#conversation").hide();}$("#greetings").html("");
}function connect() {stompClient.activate();
}function disconnect() {stompClient.deactivate();setConnected(false);console.log("Disconnected");
}function sendName() {stompClient.publish({destination: "/app/hello",body: JSON.stringify({'name': $("#name").val()})});
}function showGreeting(message) {$("#greetings").append("<tr><td>" + message + "</td></tr>");
}$(function () {$("form").on('submit', (e) => e.preventDefault());$( "#connect" ).click(() => connect());$( "#disconnect" ).click(() => disconnect());$( "#send" ).click(() => sendName());
});

main.css

body {background-color: #f5f5f5;
}#main-content {max-width: 940px;padding: 2em 3em;margin: 0 auto 20px;background-color: #fff;border: 1px solid #e5e5e5;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;
}

在这里插入图片描述

启动项目

访问 http://localhost:8080/
点击connect
What is your name?输入名字点击send

Greetings下显示响应结果

相关文章:

websocket中spring注入失效

一个null指针引发的思考 websocket中spring注入失效 一个null指针引发的思考场景代码SpringBoot入口类配置类websocket类 问题排查问题1&#xff1a;问题2&#xff1a; 反思解决方案一&#xff1a;方案二&#xff1a;方案三&#xff1a;方案四&#xff1a; 场景 首页有个webso…...

Nat Commun:网络结构在塑造神经表征的强度中扮演着‘幕后推手’的角色

摘要 人类通过一系列离散事件构建他们对世界的心智模型。这一过程被称为图学习&#xff0c;它产生了一个编码事件间转移概率图的模型。近期的研究表明&#xff0c;一些网络比其他网络更容易学习&#xff0c;但这种效应的神经基础仍然未知。在这里&#xff0c;本研究使用功能磁共…...

Driver具体负责什么工作

在 Apache Spark 中&#xff0c;Driver&#xff08;驱动程序&#xff09; 是 Spark 应用的核心控制节点&#xff0c;负责协调整个应用的执行流程。它是用户编写的 Spark 应用程序&#xff08;如 main() 方法&#xff09;的入口点&#xff0c;直接决定了任务的调度、资源分配和结…...

LeetCode 热题 100----2.移动零

LeetCode 热题 100----2.移动零 题目描述 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。示例 1:输入: nums [0,1,0,3,12] 输出: [1,3,12,…...

能源革命新突破:虚拟电厂赋能微电网智能调控,构建低碳生态新格局

在“双碳”目标的引领下&#xff0c;中央一号文件明确提出了“推进农村能源革命&#xff0c;深化绿色低碳技术应用”。作为能耗集中区域&#xff0c;产业园区如何实现清洁能源高效消纳与碳减排的目标成为了难题&#xff0c;中电国为推出的虚拟电厂与风光储充柴多能互补的微电网…...

Java集合框架深度剖析:从数据结构到实战应用

引言 Java集合框架是Java开发中的核心组件之一&#xff0c;其设计目标是提供高性能、高复用性的数据容器。无论是数据处理、缓存设计还是高并发场景&#xff0c;集合框架都扮演着关键角色。本文将从List、Map、Set三大核心接口出发&#xff0c;深入剖析其主流实现类&#xff0…...

基于灵动微单片机SPIN系列的两轮车解决方案

电动车需配备与电机兼容性更高的双模控制器。灵动针对两轮车提供了相应的方案和解决算法。在两轮车的霍尔传感器出现故障时&#xff0c;系统应能继续有效地驱动电机。除了常规的过流、过压、过温保护措施外&#xff0c;灵动的方案还支持防盗功能&#xff0c;具备电刹车能力&…...

ngx_http_core_server_name

定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {ngx_http_core_srv_conf_t *cscf conf;u_char ch;ngx_str_t *value;ngx_uint_t i;ngx_…...

【Docker系列一】Docker 简介

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

[C++面试] 你了解transform吗?

层级核心知识点入门基本语法、与for_each对比、单/双范围操作进阶动态扩展、原地转换、类型兼容性、异常安全高阶性能优化、C20 Ranges、transform_if模拟 一、入门 1、描述std::transform的基本功能&#xff0c;并写出两种版本的函数原型 std::transform函数是 C 标准库<…...

MSE分类时梯度消失的问题详解和交叉熵损失的梯度推导

下面是MSE不适合分类任务的解释&#xff0c;包含梯度推导。以及交叉熵的梯度推导。 前文请移步笔者的另一篇博客&#xff1a;大模型训练为什么选择交叉熵损失&#xff08;Cross-Entropy Loss&#xff09;&#xff1a;均方误差&#xff08;MSE&#xff09;和交叉熵损失的深入对比…...

docker 安装部署 canal

1 mysql 安装 1.1 拉取镜像 docker pull mysql:8.4.41.2 创建挂载目录 mkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/confmkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/datamkdir -p /user/lzl/tool/docker/mysql/mysql_8.4.4/home/log1.3 编辑配置文…...

flowable适配达梦7 (2.1)

经过第一版的问题解决&#xff0c;后端项目可以启动&#xff0c;前端页面也集成进去。 前端在流程设计页面报错 之后发现主要是组件中modelerStore这个值没有 解决方法:在data增加对象 给component/process/designer.vue 中涉及到的每个子组件传入 :modelerStore“modeler…...

优化 Docker 镜像 技巧

优化 Docker 镜像可以提高构建速度、减少镜像大小、提高安全性和效率。以下是一些优化 Docker 镜像的方法&#xff1a; 使用适当的基础镜像 选择合适的基础镜像可以减小镜像大小&#xff0c;并确保基础镜像的安全性和更新性。Alpine、Ubuntu Minimal 等轻量级基础镜像是常用选…...

Spring Boot框架中常用注解

以下是Spring Boot框架中常用注解的详细说明&#xff0c;包括名称、用途、用法、使用位置及扩展示例&#xff0c;按功能模块分类整理&#xff1a; 一、核心启动与配置注解 1. SpringBootApplication 用途&#xff1a;主启动类注解&#xff0c;整合了 Configuration、EnableAu…...

Linux笔记之Ubuntu22.04安装IBus中文输入法教程

Linux笔记之Ubuntu22.04安装IBus中文输入法教程 code review&#xff01; 文章目录 Linux笔记之Ubuntu22.04安装IBus中文输入法教程安装 IBus 并配置中文输入法步骤 1: 安装 IBus 和拼音插件步骤 2: 设置 IBus 为默认输入法框架步骤 3: 重启会话步骤 4: 添加中文输入法步骤 5: …...

(UI自动化测试web端)第二篇:元素定位的方法_xpath属性定位

看代码里的【driver.find_element_by_xpath( )】()里的路径怎么写&#xff1f; xpath元素定位有多种写法&#xff0c;那我们现在说的就是在元素定位时&#xff0c;根据网页的实际情况来选择适合的xpath元素定位的写法。 文章主要介绍了xpath属性定位的方法和属性扩展使用的方法…...

Linux中执行 ifconfig 命令时提示 “未找到命令”

在 Linux 系统里&#xff0c;若执行 ifconfig 命令时提示 “未找到命令” 通常是由于系统没有安装 net-tools 包&#xff0c;或者该命令不在系统的 PATH 环境变量所包含的路径中 安装 net-tools 包 # Ubuntu/Debian sudo apt update sudo apt install net-tools# CentOS 7 及以…...

UE4学习笔记 FPS游戏制作15修正可以换枪中可以继续换枪和开火的Bug

现在存在的问题是换枪动作没完成时&#xff0c;可以继续换枪或者开枪 因为换枪这个动作是由玩家进行的&#xff0c;所以应该修改FppShooter脚本 我们添加两个参数 最后一次换枪的时间和换枪动画的长度 EquipmentLength 设置默认值0.6秒 添加一个新函数IsInEquip&#xff0c;返…...

SSL/TLS 和 SSH 介绍以及他们的区别

目录 SSL/TLS SSL/TLS工作原理的核心步骤握手阶段&#xff08;Handshake Protocol&#xff09;加密通信阶段&#xff08;Encrypted Communication Phase&#xff09;会话恢复&#xff08;Session Resumption&#xff09; SSH SSH 加密机制的核心步骤 SSH 和 SSL 区别 SSL/TLS …...

AudioTrack

AudioTrack是Android Audio系统提供给应用开发者&#xff08;java/C&#xff09;的API&#xff0c;用于操作音频播放的数据通路。MeidaPlayer在播放音乐时用到的是它&#xff0c;我们可以也可以直接使用AudioTrack进行音频播放。它是最基本的音频数据输出类。 AudioTrack.java…...

Windows安装Rust环境(详细教程)

一、 安装mingw64(C语言环境) Rust默认使用的C语言依赖Visual Studio&#xff0c;但该工具占用空间大安装也较为麻烦&#xff0c;可以选用轻便的mingw64包。 1.1 安装地址 (1) 下载地址1-GitHub&#xff1a;Releases niXman/mingw-builds-binaries GitHub (2) 下载地址2-W…...

监控IP,网站将异常情况通过飞书机器人发至指定群内

界面如下&#xff0c;丑是丑了点&#xff0c;但主打一个实用。 主要就是通过ping&#xff0c;就是一直在ping&#xff0c;当不通的时候&#xff0c;就根据你设置的报警时间&#xff0c;主要是利用飞书机器人来给飞书指定群里发异常信息报警。 直接上代码 import subprocess i…...

JVM 02

今天是2025/03/23 19:07 day 10 总路线请移步主页Java大纲相关文章 今天进行JVM 3,4 个模块的归纳 首先是JVM的相关内容概括的思维导图 3. 类加载机制 加载过程 加载&#xff08;Loading&#xff09; 通过类全限定名获取类的二进制字节流&#xff08;如从JAR包、网络、动态…...

局域网设备访问虚拟机 挂载NFS

目录 引言&#xff1a;网络IP问题配置虚拟机网络有线网络&#xff1a;无线网络&#xff1a; NFS文件挂载服务端配置客户端连接 引言&#xff1a; 需求&#xff1a;局域网下树莓派设备想要访问电脑主机上的虚拟机。这样可以通过nfs挂载网络设备&#xff0c;有利于交叉编译环境调…...

零、ubuntu20.04 安装 anaconda

1.anaconda下载 地址&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 选择&#xff1a;Anaconda3-2023.07-2-Linux-x86_64.sh 2.anaconda安装 选择下载目录&#xff0c;选在在终端中打开&#xff0c;然后在终端输入安装命…...

IntelliJ IDEA 将 Spring Boot 项目远程部署到服务器

使用 IntelliJ IDEA 将 Spring Boot 项目远程部署到服务器的详细步骤&#xff0c;涵盖多种常见方法&#xff1a; 方法一&#xff1a;通过 SSH Maven 插件直接部署 1. 服务器环境准备 确保服务器已安装&#xff1a; Java 运行环境&#xff08;与项目 JDK 版本一致&#xff0…...

利用dify打造命令行助手

利用dify打造命令行助手 前言 我是mac os 的使用者。 如果说macos哪个工具我使用最频繁&#xff0c;最能提高效率的工作工具非zsh莫属(当然&#xff0c;我安装了iterm)。前不久&#xff0c;我要扩容线上的k8s集群。便想统计一下每个node上运行的pod数量。我不知道合适的命令&…...

前端面试整理

一、csshtml 二、js 三、vue 四、react 1.React 类组件与函数式组件核心区别 定义方式的不同&#xff0c;类组件用ES6的class&#xff0c;继承React.Component&#xff0c;而函数式组件用函数声明‌。 状态管理方面&#xff0c;类组件用this.state和setState&#xff0c;函…...

Perl语言的计算机网络

Perl语言在计算机网络中的应用 引言 在计算机科学的众多领域中&#xff0c;网络编程是一个极具挑战性和广泛应用的领域。在这其中&#xff0c;Perl语言以其强大的文本处理能力和简洁的语法&#xff0c;成为了网络编程的重要工具之一。自从1987年Larry Wall创造Perl以来&#…...

数据结构初阶-二叉树的应用

1.单值二叉树 题目链接&#xff1a;https://leetcode.cn/problems/univalued-binary-tree/description/ 题目思路&#xff1a;我们把根结点与左孩子和右孩子进行比较&#xff0c;只有左右子树都是单值二叉树的时候才为单值二叉树。但是我们需要先返回的是false&#xff0c;最…...

【赵渝强老师】在Docker中运行达梦数据库

Docker是一个客户端服务器&#xff08;Client-Server&#xff09;架构。Docker客户端和Docker守护进程交流&#xff0c;而Docker的守护进程是运作Docker的核心&#xff0c;起着非常重要的作用&#xff08;如构建、运行和分发Docker容器等&#xff09;。达梦官方提供了DM 8在Doc…...

掌握C#循环:for、while、break与continue详解及游戏案例

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...

备份比赛数据【算法赛】

0备份比赛数据【算法赛】 - 蓝桥云课 问题描述 蓝桥杯大赛的组委会最近遇到了一个棘手的问题。他们有 N 台电脑需要备份比赛数据&#xff0c;每台电脑所需的备份时间分别为 A1​,A2​,…,AN​ 分钟。 备份必须按编号顺序依次进行&#xff0c;即先第 1 台&#xff0c;再第 2 …...

【算法笔记】图论基础(二):最短路、判环、二分图

目录 最短路松弛操作Dijkstra朴素Dijkstra时间复杂度算法过程例题 堆优化Dijkstra时间按复杂度算法过程例题 bellman-ford时间复杂度为什么dijkstra不能处理负权边&#xff1f;dijkstra的三个步骤&#xff1a;反例失效的原因 算法过程例题 spfa时间复杂度算法过程例题spfa求最短…...

【性能优化点滴】odygrd/quill 中一个简单的标记位作用--降低 IO 次数

在 StreamSink 类中&#xff0c;成员变量 _write_occurred 的作用是 跟踪自上次刷新&#xff08;Flush&#xff09;以来是否有写入操作发生&#xff0c;其核心目的是 优化 I/O 性能。以下是详细解析&#xff1a; _write_occurred 的作用 1. 避免不必要的刷新&#xff08;Flush…...

Unity2022发布Webgl2微信小游戏部分真机黑屏

复现规律&#xff1a; Unity PlayerSetting中取消勾选ShowSplashScreen 分析&#xff1a; 在Unity中&#xff0c;Splash Screen&#xff08;启动画面&#xff09; 不仅是视觉上的加载动画&#xff0c;还承担了关键的引擎初始化、资源预加载和渲染环境准备等底层逻辑。禁用后导…...

TDengine 3.3.2.0 集群报错 Post “http://buildkitsandbox:6041/rest/sql“

原因&#xff1a; 初始化时处于内网环境下&#xff0c;Post “http://buildkitsandbox:6041/rest/sql“ 无法访问 修复&#xff1a; vi /etc/hosts将buildkitsandbox映射为本机节点 外网环境下初始化时没有该问题...

基于yolov11的中空圆柱形缺陷检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

【背景介绍】 中空圆柱形缺陷检测在多个领域具有深远意义。在石油、天然气及化工行业&#xff0c;缺陷检测可预防泄漏事故&#xff0c;避免火灾、爆炸及环境污染&#xff0c;保障人员与财产安全。建筑、桥梁及航空航天领域则依赖此技术确保中空圆柱形结构的稳定性&#xff0c;…...

Python爬虫-爬取AliExpress商品搜索词排名数据

前言 本文是该专栏的第49篇,后面会持续分享python爬虫干货知识,记得关注。 本文,笔者以AliExpress平台为例。基于Python爬虫,通过某个指定的“搜索关键词”,批量获取该“搜索关键词”的商品排名数据。 具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。废…...

20250321在荣品的PRO-RK3566开发板的buildroot系统下使用ll命令【直接编译进IMG】

./buildroot/system/skeleton/etc/profile # some more ls aliases alias llls -alF alias lals -A alias lls -CF 20250321在荣品的PRO-RK3566开发板的buildroot系统下使用ll命令【直接编译进IMG】 2025/3/21 16:53 cd /etc/ echo "" >> # some more ls ali…...

Flink 自定义数据源:从理论到实践的全方位指南

目录 第一章:自定义数据源的基础概念 数据源是什么?它在 Flink 中扮演什么角色? Flink 的内置数据源:开箱即用的 “标配” 为什么需要自定义数据源?它的杀手锏在哪? 第二章:自定义数据源的实现之道 接口选择:从简单到高级,选对工具事半功倍 SourceFunction:入门…...

如何在 Java 中查找 PDF 页面大小(教程)

PDF 文件并未被 Java 直接支持。本教程将向您展示如何使用 JPedal Java PDF 库 以简单的步骤提取 PDF 文件的页面大小&#xff08;高度和宽度&#xff09;。页面大小可以以 厘米、英寸或像素 为单位获取。 为什么要使用第三方库处理 PDF 文件&#xff1f; PDF 文件是一种复杂…...

java版嘎嘎快充玉阳软件互联互通中电联云快充协议充电桩铁塔协议汽车单车一体充电系统源码uniapp

演示&#xff1a; 微信小程序&#xff1a;嘎嘎快充 http://server.s34.cn:1888/ 系统管理员 admin/123456 运营管理员 yyadmin/Yyadmin2024 运营商 operator/operator2024 系统特色&#xff1a; 多商户、汽车单车一体、互联互通、移动管理端&#xff08;开发中&#xff09; 另…...

使用Mastra.ai构建AI智能体:一次动手实践

Mastra框架提供了一种简洁高效的AI智能体构建方式。 本文将分享我使用Mastra.ai的实践经历。 我们将逐步完成环境搭建、探索框架核心功能,并构建一个能与工具交互的基础智能体。 过程中我会总结成功经验、遇到的问题以及收获的启示。 如果你对AI开发感兴趣,或正在寻找一个…...

Redis之大key问题

BigKey 常见面试题目 你会么&#xff1f; MoreKey 案例 大批量往redis里面插入2000W测试数据key Linux Bash下面执行&#xff0c;批量插入100W for((i1;i<100*10000;i)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done;生成100W条redis批量设置kv的…...

Excel第41套全国人口普查

2. 导入网页中的表格&#xff1a;数据-现有链接-考生文件夹&#xff1a;网页-找到表格-点击→变为√-导入删除外部链接关系&#xff1a;数据-点击链接-选中连接-删除-确定&#xff08;套用表格格式-也会是删除外部链接&#xff09;数值缩小10000倍&#xff08;除以10000即可&am…...

深度学习驱动的车牌识别:技术演进与未来挑战

一、引言 1.1 研究背景 在当今社会&#xff0c;智能交通系统的发展日益重要&#xff0c;而车牌识别作为其关键组成部分&#xff0c;发挥着至关重要的作用。车牌识别技术广泛应用于交通管理、停车场管理、安防监控等领域。在交通管理中&#xff0c;它可以用于车辆识别、交通违…...

PageHiOffice网页组件(WebOffice文档控件)开发集成技巧专题一

PageHiOffice网页组件作为最新一代的WebOffice文档控件&#xff0c;这是目前市场上唯一能做到在Chrome等最新版浏览器中实现内嵌网页运行的商用文档控件&#xff0c;是OA及ERP等系统处理各种文档的福音。从发布到完善已经超过3年&#xff0c;不管是功能性还是稳定性都已经有了长…...

A2 最佳学习方法

记录自己想法的最好理由是发现自己的想法&#xff0c;并将其组织成可传播的形式 (The best reason for recording what one thinks is to discover what one thinks and to organize it in transmittable form.) Prof Ackoff 经验之谈&#xff1a; 做培训或者写文章&#xff…...