您的位置:首页 > 新闻 > 资讯 > 网页编辑器在线使用_logo设计公司报价_网络营销试卷_长沙网站seo排名

网页编辑器在线使用_logo设计公司报价_网络营销试卷_长沙网站seo排名

2025/5/7 21:38:15 来源:https://blog.csdn.net/qq_36232611/article/details/147467405  浏览:    关键词:网页编辑器在线使用_logo设计公司报价_网络营销试卷_长沙网站seo排名
网页编辑器在线使用_logo设计公司报价_网络营销试卷_长沙网站seo排名

加群联系作者vx:xiaoda0423

仓库地址:https://webvueblog.github.io/JavaPlusDoc/

https://1024bat.cn/

📦 AppCtxHolder 的作用

这是一个Spring上下文工具类,主要是为了在非 Spring 管理的地方(比如普通的工具类、线程、WebSocket类等)
也能拿到 Spring 容器里的 Bean 对象,实现全局访问 Spring 容器

🌟 主要功能总结

方法

作用

setApplicationContext(ApplicationContext context)

Spring 启动时,自动注入 ApplicationContext

getSpringBean(String beanName)

根据 bean 名字,获取 Spring 容器里的对象

getBeanDefinitionNames()

获取所有已注册的 Spring Bean 名字列表

🔥 为什么要有 AppCtxHolder?

因为有些时候我们想拿到 Spring 中的 Bean,但是:

  • 当前类不是被 Spring 托管的(比如普通 Java 类、第三方库、手动 new 出来的对象)

  • 不是通过 @Autowired 注入的

  • 也不是通过 @Component/@Service 扫描到的

这时就需要有一个能全局存 ApplicationContext 的工具类 ➔ 也就是 AppCtxHolder

这样就能做到:

MyService myService = (MyService) AppCtxHolder.getSpringBean("myService");

直接拿到 Bean 用!

📌 应用场景举例

场景

是否适合用 AppCtxHolder

WebSocket 的 @ServerEndpoint 类中注入 Service

✅ 很常用

普通工具类中调用 Spring Bean

自定义线程(比如 Runnable、TimerTask)中想用 Spring Bean

外部 SDK / 框架接入后要访问 Spring 服务

Spring Boot正常托管的 Controller、Service中

❌ 不需要,直接 @Autowired

🛠️ 一个典型使用案例

比如我们有一个 @ServerEndpoint 的 WebSocket 类:

@ServerEndpoint("/ws")
public class MyWebSocket {private MyService myService;@OnOpenpublic void onOpen(Session session) {this.myService = (MyService) AppCtxHolder.getSpringBean("myService");myService.doSomething();}
}

✅ 这样,WebSocket也能用上 Spring 的依赖了!
而不需要传统的 @Autowired,因为 @ServerEndpoint 本身是由 Web容器(Tomcat/Undertow/Jetty)托管的,不是 Spring 托管的!

⚡ 注意小点

  • AppCtxHolder.context 是静态的,所以是全局唯一的。

  • 在项目启动阶段(Spring容器加载完成后),context 就被赋值好了。

  • 如果发现 context==null,说明可能是 没有被 Spring 扫描到(比如没加 @Component),或者项目启动顺序有问题。

🧠 总结一句话

AppCtxHolder 是让你在任何地方都能访问 Spring 容器中 Bean 的万能工具。

主要问题 & 风险点

1. BlockingQueue没有指定泛型,导致是原生的裸类型

static BlockingQueue blockingQueue = new LinkedBlockingQueue();

🔴 风险:类型不安全,可能会导致 ClassCastException。 ✅ 建议改成带泛型

static BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>();

2. WebSocket @Autowired 注入问题

WebSocket 实例是多实例(每连接一个客户端就 new 一个),而Spring容器默认是单例

你直接用 @Autowired,在生产环境高并发下,可能注入失败或者导致奇怪的问题

🔴 风险:依赖注入失效,空指针异常。

✅ 标准做法是用静态注入,比如写个静态工具类或 BaseEndpointConfigure 中注册注入(Spring Boot 2.3+ 支持这种方式),或者简单一点手动持有:

private static HttpInvokeService httpInvokeServiceStatic;
@Autowired
public void setHttpInvokeService(HttpInvokeService httpInvokeService){RTDataWebSocket.httpInvokeServiceStatic = httpInvokeService;
}

3. fixedThreadPool线程池无保护

你 publishTopic 里的线程池任务,虽然有队列大小判断,但是线程池本身是没有拒绝策略的(默认 AbortPolicy),如果高并发或者阻塞严重,可能导致抛异常。

🔴 风险RejectedExecutionException 把线程打爆。 ✅ 建议加保护,比如 try-catch 包裹:

try {fixedThreadPool.submit(() -> {...});
} catch (RejectedExecutionException e) {log.error("任务提交失败: {}", e.getMessage(), e);
}

或者给线程池配置自定义 RejectedExecutionHandler(比如丢弃、日志打印)。

4. 部分地方存在并发安全风险

虽然大部分用了 ConcurrentHashMapCopyOnWriteArraySet,但是:

  • topicSessionMap.get(topic).add(session) 和 topicSessionMap.get(topic) 这种先 get 再 add的模式,在极端并发下可能出现 NPE

  • 因为 get() 后对象可能被其他线程 remove() 了。

✅ 建议做保护判断

Set<Session> sessions = topicSessionMap.get(topic);
if (sessions != null) {sessions.add(session);
}

否则可能偶现空指针。

5. 异常处理太轻了

在 @OnMessagepublishTopic 中,异常都是简单 log,实际上在生产环境要更细分:

  • 客户端非法数据 ➔ 可直接 close

  • JSON 解析失败 ➔ 返回错误提示

  • 内部服务异常 ➔ 正常返回 error code,不要让客户端无限重连

✅ 可以增加一层异常分类,比如:

catch (JsonSyntaxException e) {log.error("非法JSON:{}", e.getMessage(), e);session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "Invalid JSON"));
} catch (Exception e) {log.error("系统异常:{}", e.getMessage(), e);
}

@OnOpen

可以记录连接数,或者加白名单校验(防止乱连)

内存泄漏

如果客户端断开了但 topicSessionMap 里的 session 没移除干净,会慢慢堆积,最好在 onClose 保证彻底清理

WebSocket标准一般需要定时心跳机制(比如客户端每隔30秒 ping),防止假死连接。如果没有,需要后续考虑

监听 Kafka 消息 ➔ 解析 JSON 成对象 ➔ 根据事件类型做不同处理逻辑 ➔ 最后手动提交 offset

系统版本迭代升级时,像这种存在于 内存(ConcurrentHashMap 中的心跳数据(状态)会全部丢失
这是因为:内存 = 进程级存储,一旦程序重启、崩溃或者升级部署,JVM内存清空,所以这些心跳数据也会全部消失

1. 轻量型方案 —— 临时丢失可以接受

如果心跳数据只是为了监控“当前状态”,短时间丢失是可以接受的(比如上线后几秒内就能补回新的心跳),
内存存储+客户端自动补报心跳是足够的,
部署时加个提示或者在界面上打个“升级中”的小标识就行。

适合:

  • 客户端每隔几秒发送心跳。

  • 丢几秒的数据对业务无影响。

✅ 优点:简单,资源占用小。
❗ 缺点:升级瞬间状态断档,可能影响监控系统准确率。

2. 中等方案 —— 心跳数据持久化到 Redis

如果要求稍微高一点,希望系统升级重启后依然能拿到上一次心跳数据

系统重启时,可以从 Redis 恢复一部分最近的心跳数据

适合:

  • 需要比较稳定的心跳状态展示。

  • 升级过程中不能影响监控准确率太多。

✅ 优点:高可用,快速恢复。
❗ 缺点:稍微增加一点 Redis 使用量和开发复杂度。

3. 重型方案 —— 心跳+状态全量落盘(数据库)

如果你需要心跳记录做审计、报警,或者心跳信息必须长时间保留,
那就不仅要存 Redis,还要异步入库(MySQL / PostgreSQL):

  • 心跳数据写一张 heartbeat_status 表。

  • 每次心跳更新一个字段 last_online_time

适合:

  • 金融、政府、电力、医疗等必须记录设备状态变化的领域。

  • 需要对心跳数据做离线分析、报表统计。

✅ 优点:超稳定,满足数据留存需求。
❗ 缺点:开发复杂,性能开销大,要设计好表和更新策略。

小结一下

方案

适用场景

优点

缺点

只内存

能接受短时断档

简单快速

升级必丢数据

Redis缓存

要求重启后快速恢复

可容灾,性能高

增加Redis压力

Redis+数据库持久化

需要完整心跳记录,审计需求

数据不丢,功能完整

开发复杂,读写压力大

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com