当前位置: 首页 > 编程日记 > 正文

【原创】Kakfa utils源代码分析(三)

Kafka utils包最后一篇~~~

十五、ShutdownableThread.scala
可关闭的线程抽象类! 继承自Thread同时还接收一个boolean变量isInterruptible表明是否允许中断。既然是可关闭的,因此一定不是守护线程,而是一个用户线程(不会阻塞JVM关闭)。提供的方法有:
1. doWork抽象方法。子类必须实现这个方法,从名字来说应该是指定线程要完成的操作。
2. initiateShutdown发起关闭请求。首先通过CAS的方式判断是否线程在运行中;如果是的话将表明运行状态的isRunning变量设置为false,同时根据该线程的可中断性(通过isInterruptible)调用Thread.interupt方法中断该线程并返回true。
3. awaitShutdown: 用于发起关闭请求(initiateShutdown)之后调用该方法等待关闭操作完全结束。实现方式是调用CountDownLatch的await方法等待shutdownLacth对象变为0——shutdownLatch是该类维护的一个关闭阀门。在运行线程结束之后程序会将该对象减为0。
4. run方法: 复写了Thread的run方法。该类维护的isRunning类似于一个状态标志,控制着线程何时退出执行操作的循环。每次循环前检测isRunning值,如果一旦发现是false,则退出执行并将shutdownLatch阀门至于关闭状态;如果是true,则调用doWork来执行真正的操作。
十六、Throttle.scala
主要目的是限制某些操作的执行速度,其实主要用于清理日志时限制IO速度。这个类会接收一个给定的期望速率(单位是**/每秒,这里的**其实不重要,可以是字节或个数,主要是限制速率)。构造函数参数如下:
1. desiredRatePerSec: 期望速率
2. checkIntervalMs: 检查间隔,单位ms
3. throttleDown: 是否需要往下调节速度,即降低速率
4. metricName: 待调节项名称
5. units: 待调节项单位,默认是字节
6. time: 时间字段
该类还实现了KafkaMetricsGroup trait,你可以认为后者就是构造度量元对象用的(例如通过newMeter)。Throttle类只有一个方法: maybeThrottle。该方法代码写了一大堆,一句一句分析太枯燥,我直接举个例子说吧: 假设我们要限制IO速率,单位是字节/秒,每100毫秒查一次。我们想要限制速率为10字节/毫秒。现在我们在500ms内检测到一共发送了6000字节,那么实际速率是6000/500 = 12字节/毫秒,比期望速率要高,因此我们要限制IO速率,此时怎么办呢?很简单,如果是按照期望速率,应该花费6000/10 = 600ms,比实际多花了100ms,因此程序sleep 100ms把那段多花的时间浪费掉就起到了限制速率的效果。简单来说程序就是这么实现的: )
十七、Time.scala
封装了一些与时间相关的常量,另外提供了很多抽象方法供子类实现,比如milliseconds、nanoseconds和sleep。最后真的提供了一个子类实现了Time trait并实现了前面的三个方法。
十八、ToolsUtils.scala
使用jopt-simple工具库验证命令行参数提供的host/port格式是否正确,validatePortOrDie方法对接收到的hostport字符串进行split,过滤掉那些不符合hostport格式的项得到一个Array[String],如果这个数组的个数与split出来的Array长度不匹配,说明有不合格项,直接打印调用方法并结束程序。
okay! 我们快接近胜利了!不过一想到kafka.uitls包中还有3个超长的源代码文件就脑袋疼。我们还是一个一个啃吧。
 
十九、Utils.scala
按照这个文件中注释提示的那样,这个文件里面的帮助函数都是最最常用的函数,并不限定为Kafka的逻辑服务。因此如果要在这个文件中添加一个函数,一定要确保这个函数有很完善的文档另外还要保证一定不能只在某个特定的领域使用,应该适用于最常见的场景中。
okay,反正是一个个独立的function,还是老规矩,一个一个说:
1. runnable接收一个无返回值的函数封装到一个新建的Java Runnable对象中返回。
2. daemonThread: 创建一个守护线程用于后台执行。注意,只是创建,不开启该线程。一共提供了3个方法,目的都是一样
3. newThread创建新的线程,参数决定线程名称、执行操作以及是否为守护线程
4. readBytes读取一段给定的ByteBuffer以及给定位移到一个字节数组
5. loadProps加载一个给定路径下的.properties文件到一个Properties对象中
6. openChannel根据可变性打开一个文件通道(file channel),如果可以修改,以RandomAccessFile方法打开,如果不可修改,以FileInputStream方法打开
7. swallow执行给定的操作(以函数参数方式传递), 记录下任何异常但绝不抛出异常,而是吞掉异常
8. equal比较两段ByteBuffer——先比较position,然后是remaining,最后是内部的每个字节
9. readString将ByteBuffer中的内容读出来生成一个字符串
10. croak打印错误消息并关闭JVM
11. rm递归地删除文件或子目录
12. registerMBean: 将给定的mbean注册到平台mbean服务器。如果已经注册过会先卸载该mbean再重新注册。该方法不会抛出任何异常,只是简单滴返回false表示注册失败
13. unregisterMBean取消mbean的注册。如果没有注册过,就什么都不做
14. readUnsignedInt一共有2个方法,一个是从ByteBuffer当前位置读取4个字节的integer,并更新位移;另一个是从给定位置读取4个字节的integer,但并不修改position信息
15. writeUnsignedInt也是提供了2个方法一个是将一个long型作为一个4个字节的integer写入ByteBuffer,不考虑溢出的问题;第二个方法就是在给定的位置做第一个方法的事情
16. crc32计算字节数组的CRC32校验码
17. hashcode计算给定参数项的hashCode
18. groupby按照给定的函数计算出来的key进行分组,将相同key的值都放入一个List[V]中,整体作为一个HashMap返回。不过貌似这个函数没有被用到(
19. read读取给定ReadableByteChannel的buffer到一个ByteBuffer,如果读取失败抛出EOFException异常,否则返回读取的字节数
20. notNull带泛型类型的方法,如果给定值是null抛出异常,否则直接返回该值
21. stackTrace获取给定异常类的栈追踪信息(stack trace),作为字符串返回
22. parseCsvMap接收一个逗号分隔的key/value对,类似于key1value1,key2value2,... 使用正则表达式解析成一个HashMap并返回。该方法还有个形式,是返回成一个字符串序列,即字符串数组
23. createObject: 通过反射机制为给定类名表示的类创建一个实例
24. nullOrEmpty: 判断给定字符串是否为空。但实现有个问题,如果是多个空格,该方法就会返回false
25.  loopIterator: 其实就是个无限遍历的迭代器,为传入的集合生成一个无限流Stream,并返回它的迭代器
26. readFileAsString: 读取文件内容并作为一个字符串返回
27. abs: 计算某个整数的绝对值。如果是最小整数返回0——与Java的实现不同
28. replaceSuffix: 替换字符串的后缀,如果无法找到要替换的后缀直接抛出异常
29. createFile: 根据给定路径创建文件
30. asString: 将一个Properties对象转换成字符串返回
31. readProps: 从给定的字符串中读取属性并返回一个Properties
32. readInt: 从字节数组中的指定位移处读取一个integer
33. inLock: 在加锁的情况下执行一段函数
34. inReadLock/inWriterLock: 使用给定的锁分别获取一个读锁和写锁,然后执行函数体
35. JSONEscapeString: 将字符串中的某些字符进行转义,比如\b转成\\b
36. duplicates: 返回列表中重复项
二十、VerifiableProperties.scala
这个类就是封装了Properties对象,同时维护了一个HashSet表示属性名称集合。具体的方法有:
1. containsKey: 判断是否包含某个key
2. getProperty: 将属性名加入到属性名称集合,然后从props中获取某个属性值之后返回
3. getString: 先检测是否包含这个属性,如果包含则调用getProperty返回属性值
4. getInt: 获取一个integer类型的属性值
5. getIntInRange: 返回一个integer类型的属性值,但该值必须在给定的范围内
6. getShort: 返回一个short类型的属性值
7. getShortInRange: 返回一个short类型的属性值,但该值必须在 给定的范围内
8. getLong: 返回一个long类型的属性值
9. getLongInRange: 返回一个long类型的属性值,但该值必须在给定的范围内
10. getDouble: 返回一个double类型的属性值
11. getBoolean: 返回一个boolean类型的属性值
12. getMap: 从一个属性列表中解析出一个Map[String, String]并返回
13. getCompressionCodec: 从属性列表中读取处codec信息。该方法同时支持解析codec的序号和名称,并返回对应的codec
14. verify: 主要就是验证Properties对象中每个属性是否都在属性名称集合中,即使不在也只是打印一个log而已
二十一、ZkUtils.scala
终于到包里面的最后一个文件了。这个文件代码很长,定义了三个class和两个object。先从简单的开始说吧:
1. ZKConfig class: 这个类定义了zookeeper配置信息,其构造函数接收一个VerifiableProperties对象。Kafka维护的zookeeper配置信息包括:一个CSV格式的zookeeper连接串、最大会话超时时间、连接最大超时时间以及一个zookeeper follower被允许落后于leader的最大时间间隔,默认是2秒
2. ZKGroupDirs class: 名字中的group是指kafka的消费组的,因为Kafka中的consumer都属于一个consumer group。在这个类中定义了3个方法分别返回消费者的根路径,消费者组的路径以及消费者组的id的路径
3. ZKGroupTopicDirs class: 该类继承了ZKGroupDirs类,并提供了2个新的方法用于计算消费者组的位移和拥有者信息。如下图所示:
ZKUtils.scala中还定义了一个ZKStringSerializer object用于序列化/反序列化zookeeper中保存的字节数组。提供的两个方法也很直观:serialize方法将字符串转化成字节数组;deserialize方法将字节数组转换成字符串。
好了, 就差最后一个object没说了。ZkUtils object首先定义了很多常量,都是Kafka不同组件使用的Zookeeper上路径,比如Consumer的根路径是/consumers等。值得注意的是,目前kafka还不支持我们定制这些路径的值。这个object定义了很多方法,虽然很直观,但还是值得我们简单地浏览一遍:
1. getTopicPath: 获取topic的zk路径
2. getTopicPartitionsPath: 获取topic分区的zk路径
3. getTopicConfigPath: 获取topic config的zk路径。这个路径是在0.8.1引入的,主要是在创建或修改topic分区赋值时会更新该路径下的zk信息
4. getDeleteTopicPath: 获取已删除topic的zk路径
5. readDataMaybeNull: 返回给定/controller路径下的(controller名,状态)元组,如果无法找到那个zk节点直接返回(None,空Stat)
6. getController: 调用readDataMaybeNull方法获取controller名称,如果为空直接抛出异常,否则返回一个integer类型的controller id(通过调用KafkaController.parseControllerId方法)
7. getTopicPartitionPath: 返回/brokers/topics/<my-topic>/partitions/<my-partition-id>这样形式的zk路径
8. getTopicPartitionLeaderAndIsrPath: 返回/brokers/topics/<my-topic>/partitions/<my-partition-id>/state这样形式的zk节点
9. getChildren: 返回给定path路径下的所有子路径名
10. getSortedBrokerList: 为/borkers/ids下所有broker按照broker id排序之后做成一个列表返回
11. getChildrenParentMayNotExist: 获取给定path的所有子目录名,如果path代表的节点不存在返回Nil
12. getBrokerInfo: 读取/brokers/ids/<给定broker id>节点的数据,如果存在则调用Broker.createBroker创建一个broker实例返回,否则返回None
13. getAllBrokerInCluster: 获取/brokers/ids下的broker列表并排序,遍历该列表顺序地为每个非None的broker创建一个Broker对象,最后封装到一个Seq中返回
14. getLeaderAndIsrForPartition: 为指定的topic及其partition查询出leader node和所有isr以及epoch信息,然后提取出leader和isr信息封装为一个LeaderAndIsr对象返回——LeaderAndIsr是个case class封装了leader信息及其isr列表信息
15. makeSurePersistentPathExists: 确保给定的路径在zookeeper中存在,如果不存在创建该path
16. setupCommandPaths: 调用makeSurePersistentPathExists确保类开头定义的所有路径都已经存在
17. getLeaderForPartition: 获取某个topic的某个partition的leader id。例如在下图中,该方法应该返回0
18. getEpochForPartition: 读取某个topic某个分区下的epoch信息。如果还是上图的话应该返回leader_epoch的值,即20
19. getInSyncReplicasForPartition: 读取某个topic某个分区下的所有isr列表,如果还是上图的话,应该返回isr的值,也是0——笔者的Kafka是个单节点的集群,因此并不能看出太大的区别
20. getReplicasForPartition: 读取某个topic某个分区下的一组副本,如果是下图的话topic名称是log-topic,分区号是0的话,应该返回[0]——如果是生产环境应该是一组已分配的副本
21. registerBrokerInZk: 为给定的broker id在zookeeper上创建一个临时节点
22. getConsumerPartitionOwnerPath: 返回诸如/consumers/console-consumer-33497/owners/log-topic/partitionId这样形式的zk路径
23. leaderAndIsrZkData: 将给定的LeaderAndIsr对象和epoch编码为json格式的字符串
24. replicaAssignmentZkData: 将一组replica编码成json格式的字符串: "version" : 1, "partitions":{...}
25. createParentPath: 创建父路径代表的持久化节点
26. createEphemeralPath: 根据给定数据和路径创建临时节点
27. createEphemeralPathExpectConflict: 顾名思义,创建一个临时节点,如果已经存在抛出异常
28. createEphemeralPathExpectConflictHandleZKBug: 更加严谨的一个方法用于创建zk临时节点——主要是处理了Zookeeper会话超时的bug
29. createPersistentPath: 级联创建一个持久化节点
30. createSequentialPersistentPath: 创建一个顺序持久节点(persistent sequential)
31. updatePersistentPath: 更新一个持久节点的值。必要时候创建其父路径,但不会抛出节点已存在的异常
32. conditionalUpdatePersistentPath: 如果给定的path和version都没有问题的话更新节点数据,返回(true, 新版本),否则返回(false, -1)。另外如果捕获了失去连接的异常(比如:ConnectionLossException),zkClient会自动地重试,但有可能上一次更新操作已经成功,因此更新过的版本号与期望版本号不再匹配从而导致该方法失败,因此该方法需要处理这种情况的发生,具体做法就是再提供一个optional函数做进一步的检查
33. conditionalUpdatePersistentPathIfExists: 也是先判断条件然后再决定是否进行更新操作。成功的话返回(true,新版本),否则返回(false, -1)。另外如果path不存在直接抛出异常结束
34. updateEphemeralPath: 更新一个持久化节点的值,必要的时候创建其父路径,但不会抛出NodeExistsException
35. deletePath: 删除给定的path节点,返回true表示成功;如果节点不存在,直接返回false
36. deletePathRecursive: 已递归方式删除给定的path
37. maybeDeletePath: 根据给定的zookeeper客户端连接串创建一个zk client连接,设置会话超时和连接超时都是30秒,然后递归地删除给定的path,之后关闭zkClient对象。如果出现任何异常都不做任何处理,直接吞掉
38. readData: 读取path节点的数据,返回(数据,状态信息)元组
39. pathExists: 检查给定的path是否存在
40. getCluster: 遍历/brokers/ids下面的所有broker,创建Broker对象之后加入到一个Cluster对象实例(Cluster保存的是当前所有可用的broker),然后返回cluster
41. getPartitionLeaderAndIsrForTopics: 给定一组TopicAndPartition对象(TopicAndPartition就是一个topic加上一个分区信息),为每一个查询出对应与这个topic这个分区的LeaderIsrAndControllerEpoch并封装到一个HashMap中返回——简单来说就是就是获取某个topic某个分区的leader信息、isr信息、leaderEpoch信息以及controllerEpoch信息
42. getReplicaAssignmentForTopics: 获取一组topic的所有分区对应的副本broker号
43. getPartitionAssignmentForTopics: 返回HashMap[topic名称, Map[该topic下每一个分区号,一组副本]]这样形式的map
44. getPartitionsForTopics: 返回Map[topic名称,该topic下一组partition]这样形式的map
45. getPartitionsBeingReassigned: 读取所有topic及其分区对应的所有新的副本列表
46. parsePartitionReassignmentDataWithoutDedup: 根据给定的json字符串创建一个元组序列,每个元组都是(TopicAndPartition, Seq[Int])格式的,指定了某个topic的某个分区对应的replica号。其实就是给定一个json字符串,里面指定了哪些replica号是属于哪个topic的哪个partition的,然后提取出来做了一个Seq保存。该方法还有一个变体就是返回一个Map,总之就是保存的数据结构不同罢了
47. parseTopicsData: 从给定的json字符串中提取出topic信息封装到一个List中返回
48. getPartitionReassignmentZkData: 生成{"version" : 1, "partitions" : {"topic" -> ***, "partition" -> ***, "replicas" : {**, **}}}这样形式的json字符串
49. updatePartitionReassignmentData: 调用getPartitionReassignmentZkData方法生成json字符串,然后调用updatePersistentPath方法更新zookeeper
50. getPartitionsUndergoingPreferredReplicaElection: 读取/admin/preferred_replica_election下的所有信息,返回一组TopicAndPartition
51. deletePartition: 删除/brokers/ids/brokerId的节点,并删除/borkers/topics/brokerId的节点
52. getConsumersInGroup: 获取/consumers/group/ids下所有节点名称
53. getConsumersPerTopic: 获取每个topic的所有consumser
54. getBrokerInfo: 根据broker id获取Broker信息
55. getAllTopics: 获取所有的topic封装到一个Seq中
56. getAllPartitions: 获取所有topic的所有partition,扁平化到一个Set中,每个都是TopicAndPartition对象

相关文章:

Oracle的分页查询

为什么80%的码农都做不了架构师&#xff1f;>>> 因为Oracle不像MySQL一样有limit函数来实现分页查找&#xff0c;oracle要实现分页查询可使用关键字rownum来处理。使用rownum有以下几点需要注意&#xff1a; 1、ROWNUM存在使用规则&#xff0c;在单个子查询中&…

微软成功抵御峰值高达 2.4Tbps 的 DDoS 攻击

整理 | 祝涛 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;微软表示&#xff0c;他们成功抵御了一场发生于8月份的2.4Tbps分布式拒绝服务&#xff08;DDoS&#xff09;攻击&#xff0c;这次攻击超过了去年针对亚马逊Web服务的2.3Tbps最大攻击。这场攻击持续…

百度吴甜:首席AI架构师培养计划持续为行业输送高端复合型AI人才

CSDN 导语&#xff1a; 随着 AI 技术的发展&#xff0c;关注 AI 的开发者与日俱增&#xff1a;据 CSDN 发布的《中国 AI 应用开发者报告》显示&#xff0c;在 CSDN 的注册开发者中&#xff0c;689 万开发者有阅读、撰写和研究 AI 技术行为&#xff0c;其中精准聚焦 AI 学习和应…

Htaccess文件是什么以及Windows下自由创建.htaccess文件的N种方法

.htaccess是什么 概述来说&#xff0c;htaccess文件是Apache服务器中的一个配置文件&#xff0c;它负责相关目录下的网页配置。 通过htaccess文件&#xff0c;可以帮我们实现&#xff1a;网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访…

Linux grep,egrep及相应的正则表达式用法详解

linux在进行文本处理过程中的文本搜索工具称为正则表达式。文本搜索工具有grep、egrep、fgrep,egrep为正则表达式的扩展正则表达式&#xff0c;fgrep用于搜索文本字符串&#xff0c;与 grep 和 egrep 命令不同&#xff0c;因为它搜索字符串而不是搜索匹配表达式的模式。grep的含…

Java GC 日志解析

JVM 在Java应用程序优化中是不可缺少的一大重项&#xff0c;如何合理配置Java参数&#xff0c;如果验证配置参数的有效性&#xff0c;从GC日志中可以获得很重要的提示&#xff0c;以下是笔者对GC垃圾收集器默认开启的组合日志的部分的解析&#xff0c;希望能帮到想学习的同学O(…

MySQL 备份和恢复策略

在数据库表丢失或损坏的情况下&#xff0c;备份你的数据库是很重要的。如果发生系统崩溃&#xff0c;你肯定想能够将你的表尽可能丢失最少的数据恢复到崩溃发生时的状态。本文主要对MyISAM表做备份恢复。 备份策略一&#xff1a;直接拷贝数据库文件&#xff08;不推荐&#xff…

zookeeper学习记录

2019独角兽企业重金招聘Python工程师标准>>> 背景 前段时间看了S4流计算引擎&#xff0c;里面使用到了zookeeper进行集群管理&#xff0c;所以也就花了点时间研究了下zookeeper&#xff0c;不求看懂所有源码&#xff0c;但求了解其实现机制和原理&#xff0c;清楚其…

Ubuntu的apt-get使用国内的源

1、复制原文件备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 2、打开清华大学TUNA官网发布的Ubuntu 镜像使用帮助。 3、复制下面框中的内容&#xff0c;打开自己的Ubuntu系统。 4、 将框中的内容替换掉原来的所有内容 sudo gedit /etc/apt/sources.list 5、 进…

51单片机实现对24C02进行页写、顺序读取并显示验证

源&#xff1a;51单片机实现对24C02进行页写、顺序读取并显示验证 //************************************************************************************* //**程序名称&#xff1a;51单片机实现对24C02进行页写、顺序读取并显示验证 //**编写人&#xff1a;**** //**修…

配置MySQL主从复制

MySQL支持单向、异步复制&#xff0c;复制过程中一个服务器充当主服务器&#xff0c;而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件&#xff0c;并维护日志文件的一个索引以跟踪日志循环。当一个从服务器连接到主服务器时&#xff0c;它通知主服务器从…

PHP 单元测试

本文首发于 https://jaychen.cc/article/34作者 Jaychen朋友&#xff0c;你听说过安。。。不是&#xff0c;写过单元测试吗。 单元测试是开发过程中必不可少的一环&#xff0c;一个项目有良好的单元测试代码&#xff0c;重构的勇气都大很多。这次写一篇小文来介绍一下 PHP 的单…

CI框架如何删除地址栏的 index.php

默认 CI 框架显示地址是 http://localhost/ci/index.php/test/ 去掉index.php这样会更好些。1.修改Http.conf的 LoadModule rewrite_module modules/mod_rewrite.so 去掉注释2.ci根目录增加.htaccess文件 <IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /ci#Remov…

网站安全配置(Nginx)防止网站被攻击(包括使用了CDN加速之后的配置)

2019独角兽企业重金招聘Python工程师标准>>> 网站被攻击是一个永恒不变的话题&#xff0c;网站攻击的方式也是一个永恒不变的老套路。找几百个电脑&#xff08;肉鸡&#xff09;&#xff0c;控制这些电脑同时访问你的网站&#xff0c;超过你网站的最大承载能力&…

除了 AI,这些技术为 IIoT 插上飞向“4.0”的翅膀

“中国制造2025、德国工业4.0、美国先进制造”——在21世纪的工业领域&#xff0c;“制造强国”开启新一轮角逐。尽管实现路径各有侧重&#xff0c;但题中之义均是通过互联网和智能技术实现企业生产和管理的降本增效。正因此&#xff0c;IIoT被视为助推智能制造转型升级的“催化…

[20171225]查看并行执行计划注意的问题.txt

[20171225]查看并行执行计划注意的问题.txt--//如果使用dbms_xplan.display_cursor查看并行执行计划注意一些问题,通过例子说明:1.环境:SCOTTbook> &r/ver1PORT_STRING VERSION BANNER------------------------------ -------------- ------…

expires与etag控制页面缓存的优先级

expires指令控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息&#xff0c;启动控制页面缓存的作用time:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。time值还控制"Cache-Control"的值&#xff1a;负数表示no-cac…

API 大赛决赛名单出炉,速来围观!

创新云转型&#xff0c;智慧云服务2021年移动云API应用创新开发大赛正在火热进行中各个赛道激烈PK优秀开发者同台切磋彰显实力&#xff01;10月14日&#xff0c;2021年移动云API应用创新开发大赛复赛在中移软件园双创路演大厅圆满举办。本次复赛分为移动赛道和企业赛道分别进行…

将日期yyyy-MM-dd转为数字大写的形式

/*** 将日期转大写* 例如&#xff1a;2013-05-13转为 二0一三年五月十三日* param date* return */public static String getDxDate(String date){String dateArr[] date.split("-");String year dateArr[0];String month dateArr[1];String day dateArr[2];Str…

DevExpress v17.2新版亮点—WPF篇(四)

2019独角兽企业重金招聘Python工程师标准>>> DevExpress年终击穿底价&#xff0c;单套授权低至67折&#xff01;仅剩最后6天&#xff01;查看详情>>> 用户界面套包DevExpress v17.2终于正式发布&#xff0c;本站将以连载的形式为大家介绍各版本新增内容。本…

CI框架验证码CAPTCHA 辅助函数的使用

使用CAPTCHA 辅助函数很方便生成验证码&#xff0c;但是图片是存储在文件夹下&#xff0c;不是输出流&#xff0c;感觉不够完美&#xff0c;可以拿来用用。 说明&#xff1a;产生4位的随机数&#xff0c;CI根目录下建立captcha文件夹。 <?php $this->load->helper(ca…

GitLab 上市,市值高达 149 亿美元!GitHub 的头号劲敌来了

整理 | 祝涛 出品 | CSDN当地时间周四&#xff0c;知名代码和资源托管服务平台 GitLab&#xff08;股票代码GTLB&#xff09;完成了IPO&#xff08;首次公开募股&#xff09;&#xff0c;在纳斯达克成功上市。GitLab在本次 IPO 中筹集了约 6.5 亿美元。GitLab此前曾计划I…

将ubuntu系统设置静态ip及ssh

2019独角兽企业重金招聘Python工程师标准>>> sudo vim /etc/network/interfaces 输入以下&#xff1a;auto lo iface lo inet loopback auto eno1 iface eno1 inet static address 192.168.1.197 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameserver 192.168…

ECMAScript 5 —— 单体内置对象之Math对象

ECMAScript 还为保存数学公式和信息提供了一个公共位置&#xff0c;即 Math 对象。与我们在 JavaScript 直接编写的计算功能相比&#xff0c;Math 对象提供的计算功能执行起来要快得多。Math 对象中还提供了辅助完成这些计算的属性和方法。 一. Math 对象的属性 Math 对象包含的…

织梦内容管理系统修改

1.如何去掉互动中心 修改根目录下templates——default——index.htm文件&#xff0c;删除以下内容 <div id"rightAD1" style:margin:10px auto"></div> <div class"usercenter">.....到</div> <!-- /usercenter --&…

斯坦福大学 AI100 报告发布:AI 发展速度惊人,但风险也正走进现实

‍‍作者 | 阳光来源 | 学术头条语言处理、计算机视觉和模式识别的巨大进步&#xff0c;意味着人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;每天都在与人们的生活进行交互&#xff0c;从帮助人们选择电影&#xff0c;到帮助人们解决医疗诊断难题方面…

linux===Ubuntu 上安装 Node.js

https://www.cnblogs.com/andfly/p/6681487.html转载于:https://www.cnblogs.com/botoo/p/8118903.html

非计算机专业的学生,从事编程工作的上升壁垒是什么?

很多同学自己的专业并不是计算机&#xff0c;但是看到如今IT行业发展的这么好&#xff0c;也想转行学习编码。但是自己非科班出身&#xff0c;又到了快毕业的年纪&#xff0c;开始学习编程来得及吗&#xff1f;这些年来&#xff0c;很多培训机构都借鉴了少儿编程培训的经验&…

HTTP头信息中的参数Etag

服务器如果是集群&#xff0c;不同服务器返回的 Http Header 中的 Etag 参数不一样。如果是图片是程序生成的&#xff0c;我们可以用 no-cache 这些 header 来控制&#xff0c;但如果这些图片是 apache 或 nginx 等呢&#xff1f;下面开始介绍 Etag&#xff1a;Etag在HTTP1.1中…

利用JS使用POST方式提交请求的方法

2019独角兽企业重金招聘Python工程师标准>>> function post(url, params) {var temp document.createElement("form");temp.action url;temp.method "post";temp.style.display "none";for (var x in params) {var opt document…