前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[开源框架 ]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
ZooKeeper
...ka、Hadoop等开源项目的实际案例,我们可以看到ZooKeeper在大型集群管理、服务注册与发现等方面的广泛应用。比如,在Kafka中,ZooKeeper不仅用于Broker节点的管理和协调,还为生产者和消费者提供动态的数据订阅服务,进一步凸显了其在分布式系统中的核心价值。 综上所述,深入研究和掌握ZooKeeper的工作原理及其最新进展,对于构建高可用、高性能的分布式系统至关重要。同时,理解并借鉴其在各类实战场景中的最佳实践,将有助于开发者们更好地应对未来分布式计算环境中的挑战与机遇。
2023-07-04 14:25:57
73
寂静森林
Hibernate
...作为一款强大的ORM框架,极大地简化了Java对象与关系型数据库之间的映射操作。然而,在实际做项目的时候,我们常常会碰到关于数据库表权限分配的难题,尤其在那种用户多、角色乱七八糟的复杂系统里头,这个问题更是频繁出现。这篇文儿,咱们要接地气地聊聊Hibernate究竟是怎么巧妙应对和化解这类权限问题的,并且会结合实际的代码例子,掰开了揉碎了给你细细道来。 2. Hibernate与数据库权限概述 在使用Hibernate进行持久化操作时,开发者需要理解其底层是如何与数据库交互的。默认情况下,Hibernate是通过连接数据库的用户身份执行所有CRUD(创建、读取、更新、删除)操作的。这就意味着,这个用户的数据库权限将直接影响到应用能否成功完成业务逻辑。 3. 权限控制的重要性 假设我们的系统中有不同角色的用户,如管理员、普通用户等,他们对同一张数据表的访问权限可能大相径庭。例如,管理员可以完全操作用户表,而普通用户只能查看自己的信息。这个时候,咱们就得在Hibernate这个环节上动点小心思,搞个更精细化的权限管理,确保不会因为权限不够而整出什么操作失误啊,数据泄露之类的问题。 4. Hibernate中的权限控制实现策略 (a) 配置文件控制 首先,最基础的方式是通过配置数据库连接参数,让不同的用户角色使用不同的数据库账号登录,每个账号具有相应的权限限制。在Hibernate的hibernate.cfg.xml配置文件中,我们可以设置如下: xml admin secret (b) 动态SQL与拦截器 对于更复杂的场景,可以通过自定义拦截器或者HQL动态SQL来实现权限过滤。例如,当我们查询用户信息时,可以添加一个拦截器判断当前登录用户是否有权查看其他用户的数据: java public class AuthorizationInterceptor extends EmptyInterceptor { @Override public String onPrepareStatement(String sql) { // 获取当前登录用户ID Long currentUserId = getCurrentUserId(); return super.onPrepareStatement(sql + " WHERE user_id = " + currentUserId); } } (c) 数据库视图与存储过程 另外,还可以结合数据库自身的安全性机制,如创建只读视图或封装权限控制逻辑于存储过程中。Hibernate照样能搞定映射视图或者调用存储过程来干活儿,这样一来,我们就能在数据库这一层面对权限实现滴水不漏的管控啦。 5. 实践中的思考与挑战 尽管Hibernate提供了多种方式实现权限控制,但在实际应用中仍需谨慎对待。比如,你要是太过于依赖那个拦截器,就像是把所有鸡蛋放在一个篮子里,代码的侵入性就会蹭蹭上涨,维护起来能让你头疼到怀疑人生。而如果选择直接在数据库层面动手脚做权限控制,虽然听起来挺高效,但特别是在那些视图或者存储过程复杂得让人眼花缭乱的情况下,性能可是会大打折扣的。 因此,在设计权限控制系统时,我们需要根据系统的具体需求,结合Hibernate的功能特性以及数据库的安全机制,综合考虑并灵活运用各种策略,以达到既能保证数据安全,又能优化性能的目标。 6. 结语 总之,数据库表访问权限管理是构建健壮企业应用的关键一环,Hibernate作为 ORM 框架虽然不能直接提供全面的权限控制功能,但通过合理利用其扩展性和与数据库的良好配合,我们可以实现灵活且高效的权限控制方案。在这个历程里,理解、探索和实践就像是我们不断升级打怪的“能量饮料”,让我们一起在这场技术的大冒险中并肩前进,勇往直前。
2023-09-21 08:17:56
419
夜色朦胧
Golang
...言和Gorm ORM框架,成功实现了复杂交易系统的重构。该公司报告称,在引入Go语言后,其交易处理速度提升了40%,同时由于Go语言的垃圾回收机制,系统内存使用率降低了约15%。这些改进不仅提升了公司的市场竞争力,也为其未来的业务扩展打下了坚实的基础。 由此可见,无论是电商还是金融行业,Go语言及其相关技术在提升数据库性能和系统稳定性方面展现出了巨大的潜力。未来,随着更多企业的加入,我们有望看到更多基于Go语言的创新解决方案涌现出来,共同推动整个行业的进步和发展。
2024-10-21 15:42:48
78
百转千回
转载文章
...view-ui(UI框架)+ vuex来完成这个功能。其中,vuex主要是用来存储当前的tabbar内容的。 3. 开始撸 3.1 设置 tabbar.js 配置不同角色不同的菜单 在utils文件夹下新建一个tabbar.js,来存储不同权限下的底部导航数据。我这里有两种不同的权限,第二种权限比第一种权限多了两项菜单。 // 普通用户tabbarlet tab1 = [{"pagePath": "/pages/loginLogRecord/index","text": "登录记录","iconPath": "/static/icon_bx.png","selectedIconPath": "/static/icon_bx_hover.png"},{"pagePath": "/pages/accessRecord/index","text": "存取记录","iconPath": "/static/icon_adress.png","selectedIconPath": "/static/icon_adress_hover.png"},{"pagePath": "/pages/person/index","text": "我的","iconPath": "/static/icon_user.png","selectedIconPath": "/static/icon_user_hover.png"}]// 管理员用户tabbarlet tab2 = [{"pagePath": "/pages/loginLogRecord/index","text": "登录记录","iconPath": "/static/icon_bx.png","selectedIconPath": "/static/icon_bx_hover.png"},{"pagePath": "/pages/accessRecord/index","text": "存取记录","iconPath": "/static/icon_adress.png","selectedIconPath": "/static/icon_adress_hover.png"},{"pagePath": "/pages/authorizationList/index","text": "授权名单","iconPath": "/static/authorization.png","selectedIconPath": "/static/authorization_hover.png"},{"pagePath": "/pages/inventory/index","text": "盘点","iconPath": "/static/inventory.png","selectedIconPath": "/static/inventory_hover.png"},{"pagePath": "/pages/person/index","text": "我的","iconPath": "/static/icon_user.png","selectedIconPath": "/static/icon_user_hover.png"}]export default [tab1,tab2] 3.2 设置 page.json 在page.json文件里,把tabbar里的几个页面去重放进去。只是单纯的写个路径,什么都不要添加。test,iconPath,selectedIconPath 字段全部删掉这里不需要配置。 "tabBar": {"color": "333333","selectedColor": "328CFA","backgroundColor": "FFFFFF","list": [{"pagePath": "pages/loginLogRecord/index"},{"pagePath": "pages/accessRecord/index"},{"pagePath": "pages/authorizationList/index"},{"pagePath": "pages/inventory/index"},{"pagePath": "pages/person/index"}]} 3.3 vue 配置 uniapp是可以直接使用vuex的,所以,直接在项目的根目录下新建一个store文件夹,存储相关数据。 import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)import tabBar from '@/utils/tabbar.js'const store = new Vuex.Store({state: {wx_token: '',tabBarList: [],roleId: 0, //0 普通员工,1管理员},mutations: {// 设置wx_tokensetWxtoken(state, data) {state.wx_token = data;uni.setStorageSync('wx_token',data)},// 设置用户角色IDsetRoleId(state, data) {state.roleId = data;uni.setStorageSync('roleId',data)state.tabBarList = tabBar[data];uni.setStorageSync('tabBarList',tabBar[data])},},})export default store 在入口文件 main.js 中使用 import Vue from 'vue'import App from './App'import uView from "uview-ui";import store from './store/index'Vue.use(uView);Vue.config.productionTip = falseVue.prototype.$store = storeApp.mpType = 'app'const app = new Vue({...App,store})app.$mount() 3.4 tabBar组件代码 <template><view><u-tabbar :list="tabBarList" :active-color="activeColor" :inactive-color="inactiveColor" :height="84":border-top="borderTop"></u-tabbar></view></template><script>import store from '@/store'export default {props:{tabBarList:{type:Array,default:uni.getStorageSync('tabBarList')} },data() {return {borderTop: true,inactiveColor: '909399',activeColor: '328CFA',} },}</script> 3.5 setRole方法 登录时,获取返回的权限,然后再调用setRole方法 <script>import { mapMutations } from 'vuex';export default {data() {return {roleId:0,};},methods: {methods: {...mapMutations(['setRoleId']),},//登录login() {this.setRoleId(this.roleId)// 0或者1uni.switchTab({url: '../index/index' //然后跳转到登录后的首页})} }}</script> 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_36410795/article/details/109075488。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-06 15:14:00
136
转载
Shell
...优化详解”)。此外,开源社区中的“Advanced Bash-Scripting Guide”项目持续更新中,提供了大量关于Shell高级特性、陷阱规避以及最佳实践的深度解读。 与此同时,随着DevOps文化的普及,以Shell为核心技术栈的工具链如Ansible、Terraform等在自动化运维领域大放异彩。例如,InfoQ的一篇专题报道“Shell Scripting in DevOps: Beyond the Basics”,详细探讨了如何将Shell脚本融入CI/CD流程,并结合实际案例展示其在容器编排、持续部署等方面的应用场景。 最后,推荐一本新近出版的技术书籍《Mastering Unix Shell Scripting: From Beginner to Advanced》,该书不仅详尽梳理了Shell编程的体系知识,还涵盖了最新的Shell特性、调试技巧及安全注意事项,是进阶学习的理想参考资料。 总之,在数字化转型的大潮下,Shell编程的价值愈发凸显,不断跟进最新技术和应用场景的学习,将助力我们在IT职业生涯中游刃有余,勇攀高峰。
2023-09-05 16:22:17
101
山涧溪流_
Kubernetes
...(简称K8s)是一个开源的容器管理系统,由Google开发并捐赠给Cloud Native Computing Foundation (CNCF)。在本文语境中,Kubernetes作为容器编排平台的核心,负责管理Pod(即一组共享存储和网络空间的容器集合),确保它们能够高效、稳定地运行,并在网络层面实现各个Pod及其中容器之间的互联互通。 CNI插件 , CNI(Container Network Interface)是Kubernetes为了支持不同网络模型而设计的一种标准化接口规范,允许第三方开发者编写符合该规范的插件来配置容器的网络环境。在文章中提到,当Kubernetes集群中的Pod内容器间通信出现异常时,问题可能就出在所使用的CNI插件配置或其工作状态上,例如Flannel就是一种常用的CNI插件,它负责创建和管理网络桥接设备,确保Pod间的连通性和Pod内容器间的网络共享。 网络桥接 , 网络桥接是一种计算机网络技术,通过虚拟化技术将多个网络接口连接在一起形成一个逻辑上的单一网络层设备——网络桥。在Kubernetes环境中,网络桥接主要通过CNI插件实现,比如Flannel会在宿主机上创建名为cni0的网桥,将Pod对应的虚拟网卡veth pair一端挂载到该网桥上,这样就可以让同一Pod内的所有容器共享同一个IP地址并通过该网络桥接进行通信。如果网络桥接出现问题,可能会导致Pod内部的容器之间无法正常通信。
2024-03-01 10:57:21
122
春暖花开
Netty
...tty作为其网络通信框架。最近,一项关于Netty性能优化的研究引起了广泛关注。研究团队发现,在高并发场景下,通过优化Channel和EventLoop的配置,可以显著提升系统的吞吐量和响应速度。他们建议在选择Channel类型时,应根据实际应用场景选择最适合的实现方式,例如对于低延迟需求,可以选择NioSocketChannel;而对于高并发场景,则推荐使用EpollSocketChannel。 此外,Netty社区也一直在不断更新和完善,最新版本中引入了一些新特性,如改进的内存管理机制、增强的安全性功能以及对HTTP/3协议的支持。这些更新不仅提升了Netty的性能,还增强了其在现代网络环境下的适应性和安全性。 值得一提的是,Netflix作为Netty的重要用户之一,也在其内部项目中大量使用了Netty。Netflix的技术博客中分享了他们在大规模分布式系统中使用Netty的经验和最佳实践,其中包括如何有效地管理和扩展EventLoop线程池,以及如何利用ChannelPipeline进行复杂的业务逻辑处理。这些经验对于正在考虑使用Netty的企业和技术人员来说,具有很高的参考价值。 通过上述案例可以看出,Netty作为一种高性能的网络通信框架,在实际应用中展现出强大的能力和灵活性。无论是针对特定场景的优化,还是社区持续的技术更新,都使得Netty成为构建现代分布式系统不可或缺的一部分。对于希望提升系统性能和可靠性的开发者而言,深入学习和掌握Netty的相关知识无疑是非常必要的。
2025-02-26 16:11:36
60
醉卧沙场
Netty
...、超级抗压的网络编程框架。有了Netty,咱们处理网络通信就等于有了个高效能的法宝,轻轻松松就把这事儿给搞定了! 然而,在大规模的数据传输过程中,我们需要关注的一个重要问题就是资源管理。如果不妥善管理内存和其他资源,就像不好好打扫房间乱丢垃圾一样,久而久之就会出现内存泄漏这样的“漏洞”,这可是会直接影响到我们系统的健康状况和运行速度。因此,了解Netty中的资源回收机制是非常重要的。 二、Netty中的资源管理 在Netty中,我们可以通过多种方式来管理资源,包括手动释放资源和自动垃圾回收。 2.1 手动释放资源 在Netty中,我们可以手动调用对象的close()方法来释放资源。例如,当我们创建一个Channel时,我们可以这样操作: java ServerBootstrap b = new ServerBootstrap(); ChannelFuture f = b.bind(new InetSocketAddress(8080)).sync(); f.channel().close(); 在这个例子中,我们首先创建了一个ServerBootstrap实例,然后绑定到本地的8080端口,并同步等待服务启动。最后,我们关闭了服务器通道。这就是手动释放资源的一种方式。 2.2 自动垃圾回收 除了手动释放资源外,Netty还提供了自动垃圾回收的功能。在Java中,我们通常会使用垃圾回收器来自动回收不再使用的对象。而在Netty中,我们也有一套类似的机制。 具体来说,Netty会定期检查系统中的活跃对象列表,如果发现某个对象已经不再被引用,就会将其加入到垃圾回收队列中,等待垃圾回收器对其进行清理。这其实是一种超级给力的资源管理方法,能够帮我们大大减轻手动清理资源的繁琐劳动。 三、Netty中的资源回收机制 那么,Netty中的资源回收机制又是怎样的呢?实际上,Netty主要通过两种方式来实现资源回收:一是使用垃圾回收器,二是使用内部循环池。 3.1 垃圾回收器 在Java中,我们通常会使用垃圾回收器来自动回收不再使用的对象。而在Netty中,我们也有一套类似的机制。 具体来说,Netty会定期检查系统中的活跃对象列表,如果发现某个对象已经不再被引用,就会将其加入到垃圾回收队列中,等待垃圾回收器对其进行清理。这其实是一种超级给力的资源管理方法,能够帮我们大大减轻手动清理资源的繁琐劳动。 3.2 内部循环池 除了垃圾回收器之外,Netty还使用了一种称为内部循环池的技术来管理资源。这种技术主要是用于处理一些耗时的操作,如IO操作等。 具体来说,Netty会在运行时预先分配一定的线程数量,并将这些线程放入一个线程池中。当我们要进行一项可能耗时较长的操作时,就可以从这个线程池里拽出一个线程宝宝出来帮忙处理任务。当这个操作圆满完成后,咱就顺手把这个线程塞回线程池里,让它继续在那片池子里由“线程大管家”精心打理它的生老病死。 这种方式的好处是,它可以有效地避免线程的频繁创建和销毁,从而提高了系统的效率。同时,由于线程池是由Netty管理的,所以我们可以不用担心资源的泄露问题。 四、结论 总的来说,Netty提供了多种有效的资源管理机制,可以帮助我们更好地管理和利用系统资源。无论是手动释放资源还是自动垃圾回收,都可以有效地避免资源的浪费和泄露。另外,Netty的独门秘籍——内部循环池技术,更是个狠角色。它能手到擒来地处理那些耗时费力的操作,让系统的性能和稳定性嗖嗖提升,真是个给力的小帮手。 然而,无论哪种资源管理方式,都需要我们在编写代码时进行适当的规划和设计。只有这样操作,咱们才能稳稳地保障系统的正常运行和高性能表现,而且还能顺带给避免那些烦人的资源泄露问题引发的各种故障和损失。所以,在用Netty做网络编程的时候,咱们不仅要摸透它的基本功能和操作手法,更得把它的资源管理机制给研究个门儿清,理解得透透的。
2023-03-21 08:04:38
209
笑傲江湖-t
MyBatis
...秀的 Java持久层框架,它将 SQL 语句与对象绑定起来,使得开发者无需关心底层数据库操作的繁琐细节。在查询结果处理这个环节,MyBatis特地提供了超级实用的和标签大法,就是为了帮我们轻松搞定基本的数据类型转换,还能无缝衔接处理一对一、一对多这种复杂的关系映射问题,让数据映射过程既简单又省心。但对于复杂的数据结构转换,例如 JSON,MyBatis本身并未直接支持,需要借助一些额外的技术手段。 三、实体类与JSON数据之间的映射 1. 使用第三方库——Jackson或Gson 对于实体类与JSON之间的转换,最常用的方法是借助诸如 Jackson 或 Gson 这样的 JSON 库。首先,在项目中引入相应的依赖: xml com.fasterxml.jackson.core jackson-databind 2.13.4 // 或者 Gson com.google.code.gson gson 2.9.1 接下来,为实体类定义一个对应的 toString() 方法,使其自动生成 JSON 字符串: java public class User { private String id; private String name; // getters and setters @Override public String toString() { return new Gson().toJson(this); } } 然后在 MyBatis 的 XML 映射文件中使用 语句,并设置其 resultType 为 String 类型,配合 toString() 方法即可得到 JSON 数据:xml SELECT FROM user WHERE id = {id} 通过这种方式,MyBatis 会调用用户自定义的 toString() 方法生成对应的 JSON 字符串。 2. 自定义类型处理器(TypeHandler) 然而,如果我们想要更灵活地控制数据转换过程,或者映射包含嵌套的对象结构,可以考虑自定义类型处理器。这里以 Jackson 为例,创建一个继承自 org.apache.ibatis.type.TypeHandler 的 UserToJsonTypeHandler 类: java import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedTypes; @MappedTypes(User.class) public class UserToJsonTypeHandler extends BaseTypeHandler { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public void setNonNullParameter(PreparedStatement ps, int i, User parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, OBJECT_MAPPER.writeValueAsString(parameter)); } @Override public User getNullableResult(ResultSet rs, String columnName) throws SQLException { String jsonString = rs.getString(columnName); return OBJECT_MAPPER.readValue(jsonString, User.class); } @Override public User getNullableResult(ResultSet rs, int columnIndex) throws SQLException { // ... (类似地处理其他获取方式) } @Override public User getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { // ... (类似地处理其他获取方式) } } 在配置文件中注册这个自定义类型处理器: xml INSERT INTO user (json_data) VALUES (?) SELECT json_data FROM user WHERE id = {id} 现在,User 对象可以直接插入和查询为 JSON 字符串形式,而不需要手动调用 toString() 方法。 四、总结与讨论 通过本篇文章的学习,我们可以了解到 MyBatis 在默认情况下并不直接支持实体类与 JSON 数据的自动转换。不过,要是我们借助一些好用的第三方JSON工具,比如Jackson或者Gson,再配上自定义的类型处理器,就能超级灵活、高效地搞定这种复杂的数据映射难题啦,就像变魔术一样神奇!在我们实际做开发的时候,就得瞅准业务需求,挑那个最对味的解决方案来用。而且啊,你可别忘了把 MyBatis 的其他功能也玩得溜溜转,这样一来,你的应用性能就能噌噌往上涨,开发效率也能像火箭升空一样蹭蹭提升。同时呢,掌握并实际运用这些小技巧,也能让你在面对其他各种复杂场景下的数据处理难题时,更加游刃有余,轻松应对。
2024-02-19 11:00:31
76
海阔天空-t
MemCache
...mcached是一款开源、高性能、分布式内存对象缓存系统,设计用于减轻数据库负载,通过存储和检索常用数据以加速动态Web应用的响应速度。在系统中,它作为一个临时存储层,允许开发者暂时将数据存储在内存中,从而减少对持久化数据库的访问频率。 LRU(最近最少使用)算法 , LRU是一种常用的缓存淘汰策略,在Memcached中被用来决定何时移除缓存项。该算法基于“最近最少使用的数据最可能在未来不再被需要”的假设,当缓存空间不足时,会优先淘汰最近最少被访问的数据。结合Memcached中的过期时间设定,LRU确保了既能优先处理已过期的数据,又能有效地利用有限的缓存空间。 TTL(Time To Live) , 在计算机网络和缓存系统中,TTL是指数据包或缓存项从创建开始到其失效所需经过的时间长度。在Memcached中,用户可以为每个存储的对象设置一个TTL值,表示这个缓存项在被创建后多少秒后将会过期并自动从缓存中移除。然而,实际的过期删除并非严格按照精确的TTL时刻执行,而是与LRU算法配合,根据缓存空间的使用情况和其他因素综合判断。
2023-06-17 20:15:55
122
半夏微凉
转载文章
...yer之后,Flex框架已转向Apache Flex项目,并支持以JSFL(JavaScript Flash库)的形式运行在现代浏览器上,结合最新的web开发技术如Angular、React等,继续为开发者提供高效构建企业级应用的解决方案。 深入到服务器端编程领域,Node.js、Python Flask/Django、Java Spring Boot等平台提供了丰富的API接口设计和开发工具,使得前后端的数据交换更为灵活高效。这些技术同样强调事件驱动和异步编程模型,与ActionScript 3.0中的网络通信原理不谋而合。 总的来说,尽管Flash的时代已经过去,但它所承载的技术思想和模式在现代web开发中得到了延续和升华。理解并掌握这些核心概念,无论是在学习新的前端技术栈还是优化现有系统的过程中,都将大有裨益。
2023-09-10 18:10:29
67
转载
Netty
...作为Java NIO框架中的佼佼者,其对内存管理的精妙设计让人叹为观止。这篇文咱们要接地气地聊聊Netty这个大神级框架中的一个核心小秘密——ByteBuf的内存管理机制。咱会用到一些鲜活的例子,配上详尽的代码演示,就像是手拉手带你穿越进Netty那既充满智慧又高效无比的内存魔法世界一样。 1. ByteBuf 打破传统枷锁的新颖设计 不同于Java NIO库中的ByteBuffer,Netty自创了一套高效、灵活且易于使用的字节缓冲区抽象——ByteBuf。嘿,你知道吗?这家伙可不只是提供了更多更丰富的API接口那么简单,它还在内存管理这块玩出了大招,采用了一种超前卫的策略,这样一来,性能嗖嗖地往上窜,连垃圾回收的压力都大幅减轻了,真是让人眼前一亮! 1.1 不同类型的ByteBuf实现 ByteBuf有两种主要类型: - HeapByteBuf:基于JVM堆内存分配,访问速度快但受限于堆大小; java ByteBuf heapBuffer = Unpooled.buffer(1024); // 创建一个1KB的堆内ByteBuf - DirectByteBuf:直接使用操作系统提供的内存,绕过Java堆,适合大量数据传输,但分配和释放成本相对较高; java ByteBuf directBuffer = Unpooled.directBuffer(1024); // 创建一个1KB的直接ByteBuf 2. 内存池(PooledByteBufAllocator):节约资源的艺术 Netty为了进一步优化性能,引入了内存池的概念,通过PooledByteBufAllocator类来高效地管理和复用内存块。当你需要构建一个ByteBuf的时候,系统会默认优先从内存池里找找看有没有现成的内存块可以用。这样一来,就省去了频繁分配和回收内存的操作,这可是能有效避免让GC(垃圾回收)暂停的小诀窍! java // 使用内存池创建ByteBuf PooledByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT; ByteBuf pooledBuffer = allocator.buffer(1024); // 从内存池中获取或新建一个ByteBuf 3. 扩容机制 智能适应的数据容器 ByteBuf在写入数据时,如果当前容量不足,会自动扩容。这个过程是经过精心设计的,以减少拷贝数据的次数,提高效率。扩容这个事儿,一般会根据实际情况来,就像咱们买东西,需要多少就加多少。比如说,如果发现内存有点紧张了,我们就可能选择翻倍扩容,这样既能保证内存的高效使用,又能避免总是小打小闹地一点点加,费时又费力。说白了,就是瞅准时机,一步到位,让内存既不浪费也不捉襟见肘。 java ByteBuf dynamicBuffer = Unpooled.dynamicBuffer(); dynamicBuffer.writeBytes(new byte[512]); // 当容量不够时,会自动扩容 4. 内存碎片控制 volatile与AtomicIntegerFieldUpdater的应用 Netty巧妙地利用volatile变量和AtomicIntegerFieldUpdater来跟踪ByteBuf的读写索引,减少了对象状态同步的开销,并有效地控制了内存碎片。这种设计使得并发环境下对ByteBuf的操作更为安全,也更有利于JVM进行内存优化。 结语:思考与探讨 面对复杂多变的网络环境和苛刻的性能要求,Netty的ByteBuf内存管理机制犹如一位深思熟虑的管家,细心照料着每一份宝贵的系统资源。它的设计真有两把刷子,一方面,开发团队那帮家伙对性能瓶颈有着鹰眼般的洞察力,另一方面,他们在实际动手干工程时,也展现出了十足的匠心独运,让人不得不服。深入理解并合理运用这些机制,无疑将有助于我们构建出更加稳定、高效的网络应用服务。下回你手里捏着ByteBuf这把锋利的小家伙时,不妨小小地惊叹一下它里面蕴藏的那股子深厚的技术功底,同时,也别忘了那些开发者们对卓越品质那份死磕到底的热情和坚持。
2023-11-04 20:12:56
292
山涧溪流
Element-UI
最近,随着前端框架和技术的不断演进,越来越多的开发者开始关注组件库的选择和使用。ElementUI作为一款基于Vue.js的UI组件库,凭借其丰富的组件库和良好的文档支持,一直受到广大开发者的青睐。然而,随着Ant Design Vue和Naive UI等新晋组件库的崛起,开发者们对于选择哪款组件库产生了更多的思考。 以Ant Design Vue为例,这款组件库不仅继承了Ant Design的设计理念,还针对Vue框架进行了深度优化,提供了更为现代化和灵活的组件。特别是在国际化支持方面,Ant Design Vue做得更为出色,能够更好地满足全球化项目的需要。此外,Naive UI作为一个相对较新的组件库,虽然在社区规模上不如ElementUI和Ant Design Vue,但在轻量级和高性能方面有着独特的优势,尤其适合对性能有较高要求的项目。 除了组件库的选择,如何在实际项目中有效地利用这些组件库也是一个值得探讨的话题。例如,在处理复杂的表单验证逻辑时,开发者可以结合Form组件库提供的各种验证规则,简化代码实现。再如,在构建多语言支持的网站时,可以利用i18n插件和国际化组件库,确保不同地区的用户都能获得一致且友好的使用体验。 总之,选择合适的组件库只是第一步,更重要的是如何结合自身项目的需求,灵活运用这些工具,从而提升开发效率和产品质量。未来,随着前端技术的不断发展,相信会有更多优秀的组件库涌现出来,为开发者提供更多选择和便利。同时,开发者也需要不断学习和探索,才能跟上时代的步伐,打造出更加优秀的产品。
2024-10-29 15:57:21
77
心灵驿站
ActiveMQ
...ctiveMQ是一个开源的消息代理,它的功能非常强大,能够处理大量的消息,并且具有很高的可靠性。这个工具超级 versatile(多才多艺),既能一对一聊天,也能像广播一样发消息给大家。而且,它跟各种编程语言都能愉快地玩耍,比如 Java、C、Python 这些,完全没有沟通障碍!这使得它成为构建复杂分布式系统的理想选择。设想一下,你正忙着搞一个实时客服系统,结果各种渠道的海量请求一股脑儿涌来——电邮、社交媒体、电话,应有尽有。这时你会发现,有个能高效处理这些消息的队列简直是救星啊! 3. 实时客户服务系统的需求分析 在设计一个实时客户服务系统时,我们需要考虑几个关键因素: - 高并发性:系统需要能够同时处理大量用户请求。 - 低延迟:响应时间要快,不能让用户等待太久。 - 可扩展性:随着业务的增长,系统需要能够轻松地进行水平扩展。 - 可靠性:即使出现故障,也不能丢失任何一条消息。 为了满足这些需求,我们可以利用ActiveMQ的强大功能来搭建我们的消息传递平台。接下来,我将通过几个具体的例子来展示如何使用ActiveMQ来实现这些目标。 4. 使用ActiveMQ实现消息传递 4.1 创建一个简单的点对点消息传递系统 首先,我们需要创建一个生产者(Producer)和消费者(Consumer)。生产者负责发送消息,而消费者则负责接收并处理这些消息。 java // 生产者代码示例 import org.apache.activemq.ActiveMQConnectionFactory; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; public class Producer { public static void main(String[] args) throws Exception { // 创建连接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); // 创建连接 Connection connection = connectionFactory.createConnection(); connection.start(); // 创建会话 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建队列 Queue queue = session.createQueue("CustomerSupportQueue"); // 创建消息生产者 MessageProducer producer = session.createProducer(queue); // 发送消息 TextMessage message = session.createTextMessage("Hello, Customer!"); producer.send(message); System.out.println("Message sent successfully."); // 关闭资源 session.close(); connection.close(); } } java // 消费者代码示例 import org.apache.activemq.ActiveMQConnectionFactory; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Queue; import javax.jms.Session; public class Consumer { public static void main(String[] args) throws Exception { // 创建连接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); // 创建连接 Connection connection = connectionFactory.createConnection(); connection.start(); // 创建会话 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建队列 Queue queue = session.createQueue("CustomerSupportQueue"); // 创建消息消费者 MessageConsumer consumer = session.createConsumer(queue); // 接收消息 Message message = consumer.receive(1000); if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; System.out.println("Received message: " + textMessage.getText()); } else { System.out.println("Received non-text message."); } // 关闭资源 session.close(); connection.close(); } } 4.2 实现发布/订阅模式 在实时客服系统中,我们可能还需要处理来自多个来源的消息,这时候可以使用发布/订阅模式。 java // 发布者代码示例 import org.apache.activemq.ActiveMQConnectionFactory; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.MessageProducer; import javax.jms.Topic; import javax.jms.Session; import javax.jms.TextMessage; public class Publisher { public static void main(String[] args) throws Exception { // 创建连接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); // 创建连接 Connection connection = connectionFactory.createConnection(); connection.start(); // 创建会话 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建主题 Topic topic = session.createTopic("CustomerSupportTopic"); // 创建消息生产者 MessageProducer producer = session.createProducer(topic); // 发送消息 TextMessage message = session.createTextMessage("Hello, Customer!"); producer.send(message); System.out.println("Message sent successfully."); // 关闭资源 session.close(); connection.close(); } } java // 订阅者代码示例 import org.apache.activemq.ActiveMQConnectionFactory; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.Session; import javax.jms.Topic; import javax.jms.TopicSubscriber; public class Subscriber implements MessageListener { public static void main(String[] args) throws Exception { // 创建连接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); // 创建连接 Connection connection = connectionFactory.createConnection(); connection.start(); // 创建会话 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建主题 Topic topic = session.createTopic("CustomerSupportTopic"); // 创建消息订阅者 TopicSubscriber subscriber = session.createSubscriber(topic); subscriber.setMessageListener(new Subscriber()); // 等待接收消息 Thread.sleep(5000); // 关闭资源 session.close(); connection.close(); } @Override public void onMessage(Message message) { if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { System.out.println("Received message: " + textMessage.getText()); } catch (javax.jms.JMSException e) { e.printStackTrace(); } } else { System.out.println("Received non-text message."); } } } 5. 总结 通过以上示例,我们可以看到,ActiveMQ不仅功能强大,而且易于使用。这东西能在咱们的实时客服系统里头,让消息传得飞快,提升大伙儿的使用感受。当然了,在实际操作中你可能会碰到更多复杂的情况,比如要处理事务、保存消息、搭建集群之类的。不过别担心,只要你们把基础的概念和技能掌握好,这些难题都能迎刃而解。希望这篇文章对你有所帮助,如果有任何问题或者想法,欢迎随时交流讨论!
2025-01-16 15:54:47
85
林中小径
SpringCloud
...Cloud这款微服务框架可厉害了,它功能强大得不得了,而且还特别好上手,这使得无数开发者都对它爱不释手,真可谓圈粉无数啊!在 SpringCloud 这个大家族里,OpenFeign 可是个重量级角色。它相当于给咱们提供了一个超好用的 Java REST 客户端神器,让咱们能够轻轻松松地进行远程调用,可真是个不可或缺的小帮手呢!然而,在实际操作的时候,我们可能会遇到一些小插曲,比如 OpenFeign 里的那个 @FeignClient 注解,有时候它的 path 参数突然闹脾气、不工作了。 首先,我们需要了解什么是 @FeignClient 注解。这个东西啊,是SpringCloud带给我们的一个小神器,它是个注解,专门用来定义远程服务的。有了它,咱们就可以跟那些繁琐的传统XML配置说拜拜了,简单又高效,贼好用!用上 @FeignClient 这个注解,你就能把服务设计成一个接口的样子,然后就像操作本地接口那样,通过这个“伪装”的接口去调用远程的服务。这就像是给远程服务安了个门铃,我们只要按这个门铃(调用接口),远程服务就会响应我们的请求。下面是一个简单的 @FeignClient 注解的例子: less @FeignClient(name = "remote-service", url = "${remote.service.url}") public interface RemoteService { @GetMapping("/{id}") String sayHello(@PathVariable Long id); } 在这个例子中,我们定义了一个名为 remote-service 的远程服务,它的 URL 是 ${remote.service.url}。然后,我们捣鼓出一个叫 sayHello 的小玩意儿,这个方法可有意思了,它专门接收一个 Long 类型的 ID 号码作为“礼物”,然后呢,就精心炮制出一个 String 类型的结果送给你。 接下来,让我们来看看如何在实际项目中使用这个注解。首先,我们需要在项目的 pom.xml 文件中添加相应的依赖: php-template org.springframework.cloud spring-cloud-starter-openfeign 然后,我们可以在需要调用远程服务的地方使用上面定义的 RemoteService 接口: typescript @Autowired private RemoteService remoteService; public void test() { String result = remoteService.sayHello(1L); System.out.println(result); // 输出: Hello, 1 } 现在,我们可以看到,当我们调用 remoteService.sayHello 方法时,实际上是在调用远程服务的 /{id} 路径。这是因为我们在 @FeignClient 注解中指定了 URL。 但是,有时候我们可能需要自定义远程服务的 URL 路径。例如,我们的远程服务地址可能是 http://example.com/api 。如果我们想要调用的是 http://example.com/api/v1/{id} ,我们就需要在 @FeignClient 注解中指定 path 参数: kotlin @FeignClient(name = "remote-service", url = "${remote.service.url}", path = "/v1") public interface RemoteService { @GetMapping("/{id}") String sayHello(@PathVariable Long id); } 然而,此时我们会发现,当我们调用 remoteService.sayHello 方法时,实际上还是在调用远程服务的 /{id} 路径。这是因为我们在使用 @FeignClient 这个注解的时候,给它设定了一个 path 参数值,但是呢,我们却忘了在 RemoteService 接口里面也配上对应的路径。这就像是你给了人家地址的一部分,却没有告诉人家完整的门牌号,人家自然找不到具体的位置啦。 那么,我们如何才能让 RemoteService 接口调用 http://example.com/api/v1/{id} 呢?答案是:我们需要在 RemoteService 接口中定义对应的路径。具体来说,我们需要修改 RemoteService 接口如下: typescript @FeignClient(name = "remote-service", url = "${remote.service.url}", path = "/v1") public interface RemoteService { @GetMapping("/hello/{id}") String sayHello(@PathVariable Long id); } 这样,当我们调用 remoteService.sayHello 方法时,实际上是调用了 http://example.com/api/v1/hello/{id} 路径。这是因为我们在 RemoteService 接口里边,给它设计了一个特定的路径 "/hello/{id}",想象一下,这就像是在信封上写了个地址。然后呢,我们又在 @FeignClient 这个神奇的小标签上,额外添加了一层邮编 "/v1"。所以,当这两者碰到一起的时候,就自然而然地拼接成了一个完整的、可以指引请求走向的最终路径啦。 总结起来,SpringCloud OpenFeign @FeignClient 注解的 path 参数不起作用的原因主要有两点:一是我们在 @FeignClient 注解中指定了 path 参数,但是在 RemoteService 接口中没有定义对应的路径;二是我们在 RemoteService 接口中定义了路径,但是没有正确地与我们在 @FeignClient 注解中指定的 path 参数结合起来。希望这篇文章能对你有所帮助!
2023-07-03 19:58:09
90
寂静森林_t
Kylin
...che Kylin等开源大数据工具的最新动态和应用实践备受业界关注。 近日,Apache Kylin社区宣布发布了4.0版本,新版本引入了一系列重要改进,如支持更丰富的SQL功能、优化Cube构建速度以及增强与云环境的兼容性等(来源:Apache Kylin官网)。这一重大更新标志着Kylin在提升大数据查询性能和易用性方面又向前迈进了一大步,为更多企业在实时分析、数据可视化及复杂报表生成等方面提供强有力的支持。 此外,有越来越多的企业开始结合Kylin与其他大数据生态系统组件,如Hadoop、Spark、Flink以及各类BI工具进行深度整合,构建起全面的数据仓库解决方案。例如,《利用Apache Kylin加速企业级大数据分析》一文中详尽解读了某电商巨头如何借助Kylin有效应对“双11”期间产生的海量交易数据,实现业务洞察的实时化和精准化。 总的来说,Kylin凭借其实时分析能力和卓越的扩展性,在大数据领域持续发光发热,值得企业和开发者深入研究并应用于实际业务场景中。紧跟Kylin社区的发展动态和成功案例,将有助于我们更好地掌握前沿的大数据分析技术,并为企业决策赋能。
2023-05-03 20:55:52
112
冬日暖阳-t
JSON
...度。 此外,学术界和开源社区也正积极研究和完善针对JSON线段格式的优化算法和工具,如simdjson项目利用现代CPU的SIMD指令集加速JSON解析,对于JSON线段格式的数据同样能发挥显著性能提升效果。 总之,JSON线段格式作为数据序列化的重要手段,不仅为海量数据处理提供了新的解决方案,而且随着技术生态的持续发展,其价值和影响力将在更多实际应用场景中得到验证和体现。对于开发者而言,掌握并灵活运用JSON线段格式,无疑会是提升自身数据处理能力,应对未来挑战的关键技能之一。
2023-03-08 13:55:38
495
断桥残雪
转载文章
...入理解Mybatis框架中关于映射器注册失败及XML映射文件加载异常的问题后,我们发现正确配置和管理这些组件对于项目稳定运行至关重要。近期,随着Spring Boot与Mybatis整合使用的普及,这类问题在开发者社区中的讨论热度不减。在实际开发过程中,不仅需要关注基础的配置错误,还应关注到如自动配置、多环境适配以及热加载等高级特性对映射器注册与映射文件加载的影响。 例如,某开发者在集成Spring Boot与Mybatis时,通过@EnableAutoConfiguration注解实现自动化配置,但忽略了@ComponentScan注解导致Mapper接口未被扫描并注册至Spring容器中。此外,随着微服务架构的发展,多模块项目中映射文件路径处理也需要特别注意,确保在不同环境下能准确找到对应的XML资源。 另外,在持续集成/持续部署(CI/CD)场景下,Mybatis热加载功能成为解决此类问题的有效途径之一。当修改了映射文件后,Mybatis Plus等增强工具支持动态刷新Mapper,无需重启服务即可生效,大大提高了开发效率和系统的稳定性。 总的来说,针对Mybatis框架中的报错信息,开发者不仅要熟练掌握基本的配置技巧,还需紧跟技术发展潮流,灵活运用各种最佳实践和工具来应对复杂应用场景下的挑战,从而确保项目的高效稳健运行。
2023-06-08 12:10:23
129
转载
ReactJS
...性和性能。近期,知名开源项目React-DOM团队发布了一篇博客,深入探讨了Fragment在实际项目中的最佳实践。 在这篇文章中,作者首先回顾了Fragment的基本概念,并强调了它在简化代码结构方面的优势。接着,作者指出,在大型项目中,过度使用Fragment可能会导致一些意想不到的问题。例如,当Fragment包裹了大量的子元素时,可能会增加React虚拟DOM的处理负担,从而影响整体性能。为此,作者提出了一些实用的建议,如合理使用Fragment,尽量避免不必要的嵌套;对于频繁渲染且状态变化不频繁的组件,可以考虑使用React.memo或PureComponent来优化性能。 此外,文章还提到,一些开发者已经开始探索如何结合其他技术(如Suspense和Concurrent Mode)来进一步提升Fragment的使用效果。这些新技术不仅可以帮助开发者更好地控制组件的加载顺序,还能在一定程度上缓解Fragment带来的性能压力。例如,通过使用Suspense,可以在数据加载完成之前显示一个加载指示器,从而提升用户体验。 总之,随着React技术的不断发展,如何在大型项目中高效地使用Fragment已成为许多开发者关注的重点。通过合理规划和优化,我们完全可以在享受Fragment带来的便利的同时,避免潜在的问题,使代码更加健壮和高效。希望这篇文章能为正在探索这一领域的开发者们提供一些有价值的参考。
2024-12-06 16:01:42
48
月下独酌
Python
...nsformer”的开源模型正引发广泛关注。该模型基于Python环境开发,能够理解和生成高质量的长序列音乐,使得通过AI创作完整曲目成为现实。相关开发者社区也积极举办各类编程马拉松和挑战赛,鼓励更多程序员利用Python探索音乐数据挖掘、音乐推荐系统以及音乐治疗等前沿交叉领域。 此外,Python也在音乐教育中发挥着独特作用,如MIT的“听觉计算实验室”正在研发一套基于Python的互动式音乐教学工具,旨在帮助学生通过可视化和实时分析音频数据来更直观地理解音乐理论及结构。 总的来说,Python在音乐世界的编程艺术远未止步,它正在持续推动音乐创作、教育和欣赏方式的革新,为全球音乐爱好者和专业人士提供了一个前所未有的科技视角与平台。未来,我们期待更多由Python驱动的音乐科技创新成果涌现,共同构建更加丰富多彩的音乐未来。
2023-08-07 14:07:02
222
风轻云淡
Cassandra
...需求愈发强烈。例如,开源社区中针对Kubernetes环境设计的分布式锁服务如分布式锁控制器(Distributed Lock Controller for Kubernetes),通过集成K8s API实现了跨多个Pod的安全锁定机制,大大提升了资源协调效率和系统的整体稳定性。 与此同时,一些数据库厂商也正在探索将分布式锁功能内置于产品中以简化开发者工作流程。例如,CockroachDB作为一款新型的分布式SQL数据库,其内置的分布式事务支持为解决并发控制问题提供了新的思路。虽然本文主要介绍了基于Cassandra实现分布式锁的方法,但了解其他数据库在此领域的创新有助于拓宽视野,选择最适合特定场景的解决方案。 此外,关于分布式锁的理论研究也在不断深化。有学者和专家正从CAP定理出发,结合现代分布式系统的特性,探讨如何优化分布式锁在复杂网络环境下的性能表现,以及如何在确保数据一致性的前提下,最大程度地提高并发处理能力。这些研究成果对于指导实际工程实践具有重要的参考价值。 综上所述,在面对高并发分布式系统的锁管理挑战时,不仅需要掌握具体技术工具的使用方法,更要关注领域内的前沿动态与发展趋势,以便更好地应对未来的系统设计与优化需求。
2023-03-13 10:56:59
504
追梦人
Kibana
...search 是一个开源、分布式、RESTful 风格的搜索和分析引擎,它提供实时、可扩展的数据存储、检索和分析能力。在本文中,Elasticsearch 作为 Kibana 的数据源,Kibana 通过配置文件连接到 Elasticsearch 以获取并可视化数据。 JVM堆大小(server.heap.size) , JVM(Java Virtual Machine)堆是Java应用程序运行时的主要内存区域,用于存储对象实例。在Kibana的配置文件中,server.heap.size 参数用来指定分配给Kibana服务的JVM堆内存大小。当Kibana启动时由于内存不足导致服务器内部错误时,可以通过调整这个参数来增大Kibana可以使用的内存资源,确保其能够顺利启动和运行。 兼容性对照表 , 兼容性对照表是指由软件供应商提供的官方文档,列出了不同版本软件之间的兼容关系。在本文上下文中,指的是Elastic官方发布的Kibana与Elasticsearch各个版本之间的兼容情况列表。用户在安装或升级过程中,需要参照此对照表,确保所使用的Kibana版本能够与已安装的Elasticsearch版本协同工作,避免因版本不匹配引发的各种问题,如本文提到的“服务器内部错误”。
2023-11-01 23:24:34
340
百转千回
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
screen
- 启动多窗口终端会话,用于长时间运行任务或远程连接断开后恢复工作。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"