【Java】ServiceLoader源码分析

松饼人 2019-05-15 20:01:00 阅读数:14 评论数:0 收藏数:0

ServiceLoader主要的功能是用来完成对SPI的provider的加载。

先看下它的成员:

 1 public final class ServiceLoader<S>
 2     implements Iterable<S> {
 3 
 4     private static final String PREFIX = "META-INF/services/";
 5 
 6     // The class or interface representing the service being loaded
 7     private final Class<S> service;
 8 
 9     // The class loader used to locate, load, and instantiate providers
10     private final ClassLoader loader;
11 
12     // The access control context taken when the ServiceLoader is created
13     private final AccessControlContext acc;
14 
15     // Cached providers, in instantiation order
16     private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
17 
18     // The current lazy-lookup iterator
19     private LazyIterator lookupIterator;
20     
21     ......
22         
23 }

可以看到他首先是实现了Iterable接口,可以迭代。
PREFIX:指明了路径是在"META-INF/services/"下。
service:表示正在加载的服务的类或接口。
loader:使用的类加载器。
acc:创建ServiceLoader时获取的访问控制上下文。
providers :缓存的服务提供集合。
lookupIterator:是其内部使用的迭代器,用于类的懒加载,只有在迭代时加载。

其构造方法是一个private方法,不对外提供,在使用时我们需要调用其静态的load方法,由其自身产生ServiceLoader对象:

1 public static <S> ServiceLoader<S> load(Class<S> service) {
2         ClassLoader cl = Thread.currentThread().getContextClassLoader();
3         return ServiceLoader.load(service, cl);
4 }
5 
6 public static <S> ServiceLoader<S> load(Class<S> service,
7                                             ClassLoader loader) {
8         return new ServiceLoader<>(service, loader);
9 }

可以看到对load方法进行了重载,其中参数service是要加载的类;单参方法没有类加载器,使用的是当前线程的类加载器;最后调用的是双参的load方法;而双参的load方法也很简单,只是直接调用ServiceLoader的构造方法,实例化了一个对象。

 

1 private ServiceLoader(Class<S> svc, ClassLoader cl) {
2         service = Objects.requireNonNull(svc, "Service interface cannot be null");
3         loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
4         acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
5         reload();
6 }

可以看到其构造方法逻辑依旧很简单,首先是判断传入的svc(即传入的service)是否为空,若是为空直接报异常,否则给service 成员赋值:

1 public static <T> T requireNonNull(T obj, String message) {
2         if (obj == null)
3             throw new NullPointerException(message);
4         return obj;
5 }

然后给进行cl的非空判断,给loader 成员赋值;接着给acc 成员赋值,其根据是否设置了安全管理器SecurityManager来赋值;最后调用reload方法。

1 public void reload() {
2         providers.clear();
3         lookupIterator = new LazyIterator(service, loader);
4 }

可以看到reload方法是一个public方法,那么在每次调用reload时就需要将之前加载的清空掉,所以直接使用providers这个map的clear方法清空掉缓存;接着使用刚才赋值后的service和loader产生一个LazyIterator对象赋值给lookupIterator成员。

LazyIterator是ServiceLoader的内部类,其定义如下:

 1 private class LazyIterator
 2         implements Iterator<S> {
 3     Class<S> service;
 4     ClassLoader loader;
 5     Enumeration<URL> configs = null;
 6     Iterator<String> pending = null;
 7     String nextName = null;
 8     
 9     private LazyIterator(Class<S> service, ClassLoader loader) {
10         this.service = service;
11         this.loader = loader;
12     }
13     ......
14 }

这里就可以看到ServiceLoader的实际加载过程就交给了LazyIterator来做,将ServiceLoader的service和loader成员分别赋值给了LazyIterator的service和loader成员。
configs是服务的URL枚举;
pending是保存要加载的服务的名称集合;
nextName是下一个要加载的服务名称;

ServiceLoader实现了Iterable接口,其实现的iterator方法如下:

 1 public Iterator<S> iterator() {
 2     return new Iterator<S>() {
 3         Iterator<Map.Entry<String,S>> knownProviders
 4             = providers.entrySet().iterator();
 5     
 6         public boolean hasNext() {
 7             if (knownProviders.hasNext())
 8                 return true;
 9             return lookupIterator.hasNext();
10         }
11     
12         public S next() {
13             if (knownProviders.hasNext())
14                 return knownProviders.next().getValue();
15             return lookupIterator.next();
16         }
17     
18         public void remove() {
19             throw new UnsupportedOperationException();
20         }
21     
22     };
23 }

可以看到它是直接创建了一个Iterator对象返回;其knownProviders成员直接获取providers的entrySet集合的迭代器;在hasNext和next方法中我们可以看到,它是先通过判断knownProviders里有没有(即providers),若没有再去lookupIterator中找;
前面我们可以看到providers里并没用put任何东西,那么就说明put操作也是在lookupIterator中完成的。

先看到lookupIterator的next方法:

 1 public S next() {
 2    if (acc == null) {
 3         return nextService();
 4     } else {
 5         PrivilegedAction<S> action = new PrivilegedAction<S>() {
 6             public S run() { return nextService(); }
 7         };
 8         return AccessController.doPrivileged(action, acc);
 9     }
10 }

首先根据判断acc是否为空,若为空则说明没有设置安全策略直接调用nextService方法,否则以特权方式调用nextService方法。

 

 1 private S nextService() {
 2     if (!hasNextService())
 3         throw new NoSuchElementException();
 4     String cn = nextName;
 5     nextName = null;
 6     Class<?> c = null;
 7     try {
 8         c = Class.forName(cn, false, loader);
 9     } catch (ClassNotFoundException x) {
10         fail(service,
11              "Provider " + cn + " not found");
12     }
13     if (!service.isAssignableFrom(c)) {
14         fail(service,
15              "Provider " + cn  + " not a subtype");
16     }
17     try {
18         S p = service.cast(c.newInstance());
19         providers.put(cn, p);
20         return p;
21     } catch (Throwable x) {
22         fail(service,
23              "Provider " + cn + " could not be instantiated",
24              x);
25     }
26     throw new Error();          // This cannot happen
27 }

首先根据hasNextService方法判断,若为false直接抛出NoSuchElementException异常,否则继续执行。

hasNextService方法:

 1 private boolean hasNextService() {
 2     if (nextName != null) {
 3         return true;
 4     }
 5     if (configs == null) {
 6         try {
 7             String fullName = PREFIX + service.getName();
 8             if (loader == null)
 9                 configs = ClassLoader.getSystemResources(fullName);
10             else
11                 configs = loader.getResources(fullName);
12         } catch (IOException x) {
13             fail(service, "Error locating configuration files", x);
14         }
15     }
16     while ((pending == null) || !pending.hasNext()) {
17         if (!configs.hasMoreElements()) {
18             return false;
19         }
20         pending = parse(service, configs.nextElement());
21     }
22     nextName = pending.next();
23     return true;
24 }

hasNextService方法首先根据nextName成员是否为空判断,若不为空,则说明已经初始化过了,直接返回true,否则继续执行。接着configs成员是否为空,configs 是一个URL的枚举,若是configs 没有初始化,就需要对configs初始化。
configs初始化逻辑也很简单,首先根据PREFIX前缀加上PREFIX的全名得到完整路径,再根据loader的有无,获取URL的枚举。其中fail方法时ServiceLoader的静态方法,用于异常的处理,后面给出。
在configs初始化完成后,还需要完成pending的初始化或者添加。
可以看到只有当pending为null,或者没有元素时才进行循环。循环时若是configs里没有元素,则直接返回false;否则调用ServiceLoader的parse方法,通过service和URL给pending赋值;

parse方法:

 1 private Iterator<String> parse(Class<?> service, URL u)
 2         throws ServiceConfigurationError {
 3     InputStream in = null;
 4     BufferedReader r = null;
 5     ArrayList<String> names = new ArrayList<>();
 6     try {
 7         in = u.openStream();
 8         r = new BufferedReader(new InputStreamReader(in, "utf-8"));
 9         int lc = 1;
10         while ((lc = parseLine(service, u, r, lc, names)) >= 0);
11     } catch (IOException x) {
12         fail(service, "Error reading configuration file", x);
13     } finally {
14         try {
15             if (r != null) r.close();
16             if (in != null) in.close();
17         } catch (IOException y) {
18             fail(service, "Error closing configuration file", y);
19         }
20     }
21     return names.iterator();
22 }

可以看到parse方法直接通过URL打开输入流,通过parseLine一行一行地读取将结果保存在names数组里。

parseLine方法:

 1 private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
 2                           List<String> names)
 3         throws IOException, ServiceConfigurationError {
 4     String ln = r.readLine();
 5     if (ln == null) {
 6         return -1;
 7     }
 8     int ci = ln.indexOf('#');
 9     if (ci >= 0) ln = ln.substring(0, ci);
10     ln = ln.trim();
11     int n = ln.length();
12     if (n != 0) {
13         if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
14             fail(service, u, lc, "Illegal configuration-file syntax");
15         int cp = ln.codePointAt(0);
16         if (!Character.isJavaIdentifierStart(cp))
17             fail(service, u, lc, "Illegal provider-class name: " + ln);
18         for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
19             cp = ln.codePointAt(i);
20             if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
21                 fail(service, u, lc, "Illegal provider-class name: " + ln);
22         }
23         if (!providers.containsKey(ln) && !names.contains(ln))
24             names.add(ln);
25     }
26     return lc + 1;
27 }

parseLine方法就是读该URL对应地文件地一行,可以看到通过对“#”的位置判断,忽略注释,并且剔除空格,接着是一系列的参数合法检验,然后判断providers和names里是否都没包含这个服务名称,若都没包含names直接add,最后返回下一行的行标;

当parse将所有内容读取完毕,返回names.iterator()赋值给hasNextService中的pending。循环结束,获取pending中的第一个元素赋值给nextName,返回true,hasNextService方法结束。

在nextService方法往下执行时,先用cn保存nextName的值,再让nextName=null,为下一次的遍历做准备;接着通过类加载,加载名为cn的类,再通过该类实例化对象,并用providers缓存起来,最后返回该实例对象。

其中cast方法是判断对象是否合法:

1 public T cast(Object obj) {
2     if (obj != null && !isInstance(obj))
3         throw new ClassCastException(cannotCastMsg(obj));
4     return (T) obj;
5 }

至此ServiceLoader的迭代器的next方法结束。其hasNext方法与其类似,就不详细分析了。

而其remove方法就更直接,直接抛出异常来避免可能出现的危险情况:

1 public void remove() {
2     throw new UnsupportedOperationException();
3 }

 

其中使用到的静态fail方法只是抛出异常:

 1 private static void fail(Class<?> service, String msg, Throwable cause)
 2         throws ServiceConfigurationError {
 3     throw new ServiceConfigurationError(service.getName() + ": " + msg,
 4                                             cause);
 5 }
 6 
 7 private static void fail(Class<?> service, String msg)
 8         throws ServiceConfigurationError {
 9     throw new ServiceConfigurationError(service.getName() + ": " + msg);
10 }
11 
12 private static void fail(Class<?> service, URL u, int line, String msg)
13         throws ServiceConfigurationError {
14     fail(service, u + ":" + line + ": " + msg);
15 }

 

ServiceLoader除了load的两个方法外还有个loadInstalled方法:

1 public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
2     ClassLoader cl = ClassLoader.getSystemClassLoader();
3     ClassLoader prev = null;
4     while (cl != null) {
5         prev = cl;
6         cl = cl.getParent();
7     }
8     return ServiceLoader.load(service, prev);
9 }

该方法与load方法不同在于loadInstalled使用的是扩展类加载器,而load使用的是传入进来的或者是线程的上下文类加载器,其他都一样。

 

ServiceLoader源码分析到此全部结束。

 


版权声明:本文为[松饼人]原创文章
转载请带上:http://copyfuture.com/blogs-details/12d161fa39e8160c6ad820530dd40fdb
或:https://www.cnblogs.com/a526583280/p/10871795.html


  1. 关于坚持和发展中国特色社会主义的几个问题
  2. 7种意式西装穿搭法,散发出优雅男人味!
  3. 日本反对无效!俄军500士兵70辆坦克登岛,北海道在导弹射程内
  4. 乐视控股:韬藴至今未支付收购易到资金,将提起诉讼
  5. 海底捞员工“神”服务背后的“核武器“
  6. Docker 下载镜像
  7. Spotify痛斥苹果:就是个垄断头子
  8. 《机器学习实战》-机器学习基础
  9. 一个曾经带来感动的时代:你还记得你玩过的家用主机吗?
  10. nginx+uwsgi+flask+supervisor 项目部署
  11. javascript ES6 新特性之 let
  12. 喝了一杯果汁,测餐后2小时血糖8.6算高吗?高到多少就算升高了?
  13. 物联网卡在智能家居之中,主要有什么用?
  14. 第3个1亿台冰箱下线,海尔将“世界第一”进化到未来
  15. 只比霸道贵3万,最便宜的陆巡来了,低配53万起,配手动变速箱
  16. xshell连接到服务器代理上网
  17. css炫酷动画收藏
  18. 库里复出26分,勇士力克活塞返西部第一!汤神24分,追梦14+8
  19. 桑切斯效应?德赫亚后,曼联又有两主力索要高薪,不给就离队!
  20. 科学家将液态金属转化为等离子体!
  21. 一分钟充好电是什么概念?菲斯克声称将造1分钟充好电的电动汽车
  22. 每年追《权力的游戏》,都提前一个月做好挨虐准备
  23. 荐读|水不试,不知深浅;人不交,不知好坏。
  24. 签到抽奖功能——常见前端抽奖需求
  25. 人工智能时代:哪些行业迎来重大变革?
  26. 京东财报电话会议实录:刘强东称今年会更关注三四线城市
  27. LOL:不进季后赛的LGD才是真正的LGD!2:1击败OMG让出垫底的位置
  28. 《强奸日》引起众怒 苏格兰议员强烈谴责黄色暴力游戏
  29. 如何写工程代码——重新认识面向对象
  30. Java集合--TreeSet详细解析
  31. 为啥买车的人越来越少?知道原因后,你还敢买车吗
  32. java jdk动态代理模式举例浅析
  33. 【计算机网络】TCP/IP若干问题
  34. RSA2019创新沙盒 | Duality: 基于同态加密的数据分析和隐私保护方案
  35. 核潜艇通讯:决定全球海洋归属权的暗网系统
  36. 迪丽热巴已成立自己的工作室,看到名字后,网友:杨幂没白疼你
  37. 霉变食物不可惜,当心黄曲霉素成肝之殇!
  38. 货架半空四个月,全时便利店终于找到“接盘侠”
  39. 营养师提醒您:糖友别吃汤泡饭
  40. [Swift]LeetCode606. 根据二叉树创建字符串 | Construct String from Binary Tree
  41. 科学家在石墨中观察到“第二类声”,神奇特性再加一?
  42. 揭秘顺治皇帝壮年而毙的背后隐情
  43. 大连工业制造领域开始应用5G技术
  44. 在线制作数据库ER模型
  45. [Cake] 2. dotnet 全局工具 cake
  46. 中国无人机手起刀落,百万美元T72直接被打爆,沙特说“买值了”
  47. “高价回收驾照分”?那驾照分值不值钱,能不能进行买卖?
  48. 爆款20万元日系标杆SUV 动力媲美同级别轿跑
  49. Kubernetes集群搭建之Master配置篇
  50. 写得太好了!做餐饮不是一般人能干的,只要干好的都不是一般人!
  51. 歌名是晴天歌词是雨天,多少年后才懂:周杰伦《晴天》
  52. 宇宙起源:宇宙大爆炸(1)
  53. 联想上演碰瓷闹剧, PPT发布会被网友集体吐槽
  54. 10部结局极具争议的电影,直至今日,人们仍在争论
  55. Android 四大组件之broadcast的理解
  56. Elastic Search 安装和配置
  57. 12点聊电商:淘宝规范商务等行业 对严重违规者立即清退
  58. mysql实现主从备份
  59. “村与村的战斗”?日本战国时代的战争规模真的那么小吗?
  60. 三个关键点,确保以普惠多赢理念助推“一带一路”
  61. 吴京新片正式开拍,继成龙章子怡加盟后,如今又来了一位人气男星
  62. PYPL 二月榜单发布:最受欢迎的编程语言、IDE 和数据库都是哪些
  63. 评论:一个豆瓣差评没什么大不了
  64. 地球是唯一有表面液态水的星球,为啥会有水存在?没水会有啥变化
  65. Python爬虫入门教程 38-100 教育部高校名单数据爬虫 scrapy
  66. #Java干货分享:这五个网站能打通你的任督二脉,让你技术大增
  67. 一个亡国之君,那些击败、戏弄他的人,都被“他的名字”熬死了
  68. 解决下一个500亿快递!未来的千亿快递,需要智慧物流骨干网!
  69. 没想到吧,《绿皮书》的台词居然还能这样读?
  70. 外媒曝《复联4》主演片酬,钢铁侠赚5亿,黑寡妇1.3亿
  71. iate id generator错误
  72. 十年老策划把他想对萌新说的话做成了一款游戏
  73. 比亚迪F3终将被取代,新车型内外更漂亮,1.5L自吸5万将开卖!
  74. 拼多多发布2018扶贫助农年报,农产品销售653亿同比增233%
  75. 啥都涨,粮价不涨?该如何确保粮食安全?
  76. MATLAB 音响系统工具箱
  77. 一个新手程序员 2019 的九大尴尬瞬间
  78. 一季度31省消费支出榜出炉!10省花钱比赚钱“能干”,广东“超车”江苏,辽宁黑龙江名次跌(多图)
  79. 与河南巡抚田文镜斗法,直隶总督李绂却为何输了?
  80. 基于CAS实现单点登录(二)
  81. 魏建军们用实力“打脸”不懂中国汽车工业的人
  82. 前端知识分享.md
  83. 转载,汉语世界上最先进的语言(来自几年前的转发,如今重新转发)
  84. 硝苯地平缓释片、硝苯地平控释片,哪一个好?告诉你答案
  85. Sign Up Account In CloudAMQP
  86. 湖人绿军在总决赛相遇13次,湖人却只赢了4次?只因一人遭8连亚军
  87. 【品金庸】武馋仁“三绝”——洪七公
  88. 张庭背小三骂名委屈20年?林瑞阳前妻疑怒怼:该感谢我静默21年
  89. 揭开趣头条的“土味”流量生意经
  90. 华为有哪些“备胎”?这里有一份中国芯片企业权威榜单
  91. 华为高通就专利和解谈判:或每年支付高通超5亿美元
  92. 程序员:如何正确使用你的黄金时间
  93. python3入门教程之基本数据类型(一)
  94. 这十个人的背后,是2018年游戏业的悲欢离合
  95. "年轻人离开工厂送外卖"不应被误读,也不该有偏见
  96. 刀塔自走棋:野兽流不完全攻略
  97. 无状态点赞 王思聪骂Uzi,直播间惨遭爆破!官博秒回应!
  98. 齐王司马冏为何会兵败身亡?绝不是史书所说的“贪图享乐”
  99. 有些句子真的很美,这就是语言文字的魅力
  100. “团贷网”案:实控人近9亿转移隐匿资金被追缴冻结

  1. Python开发:部分第三方库无法在线安装解决方法(947)
  2. [Swift]LeetCode325. 最大子数组之和为k $ Maximum Size Subarray Sum Equals k(779)
  3. Matlab 2019a 安装包下载以及安装和激活(717)
  4. 仅限Edge和Chrome访问 全新网页端Skype应用上线(685)
  5. 前端笔记之NodeJS(一)初识NodeJS&内置模块&特点(682)
  6. C#读取excel文件提示未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序(663)
  7. 【预警通告】Weblogic反序列化远程代码执行漏洞(640)
  8. Visual Studio 2019 正式发布,重磅更新,支持live share(599)
  9. 【预警通告】Apache Tomcat远程代码执行漏洞CVE-2019-0232(573)
  10. 网上赌博平台维护审核提不了款怎么办?(535)
  11. React 与 React-Native 使用同一个 meteor 后台(525)
  12. Sublime Text3 最新版3207 安装及破解(458)
  13. Visual Studio 2019 正式发布(389)
  14. [翻译] Visual Studio 2019: 极速编码. 智能工作. 创造未来.(388)
  15. 刘强东身边的CXO还有谁“幸存”(373)
  16. 舍命生子产妇吴梦丈夫怒斥:没抢肺源不是精神分裂,网友断章取义(371)
  17. Confluence SSRF及远程代码执行漏洞处置手册(370)
  18. 机器学习 ML.NET 发布 1.0 RC(369)
  19. 阿里巴巴2018年纳税516亿元 同比增40%(368)
  20. K8s集群安装--最新版 Kubernetes 1.14.1(336)
  21. 雷军清华演讲实录:小米9年的创新、变革与未来(332)
  22. 小米手机卖不动了?(327)
  23. F#周报2019年第14期(317)
  24. 积分一样却选手下败将出战国际赛,《最强大脑》云队选手被坑了?(300)
  25. 《最强大脑》要垮?桑洁魏坤琳出轨细节被扒,戚薇才是神助攻(257)
  26. 华电教授孙玉兵被指与昔日同学共同学术造假,多所高校调查(250)
  27. F#周报2019年第15期(249)
  28. 日本明仁天皇退位,日本“平成”年代结束(246)
  29. linux系统安装cdcfordb2udb(241)
  30. Oracle甲骨文大规模裁员,你背离时代就会被淘汰(240)
  31. 他联系叙恐怖分子“卖军火”,称能搞到2000枚导弹,关键时刻中国警察出手(237)
  32. 魔兽世界:8.15搏击俱乐部坐骑获取流程 鳄鱼布鲁斯坐骑(236)
  33. 针对django2.2报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: ill....(235)
  34. 女友被曝插足许志安郑秀文婚姻 知情人透露马国明已下定决心分手(232)
  35. 视觉中国深夜道歉:全面配合监管部门彻底积极整改(228)
  36. 为什么国内汽车用沥青阻尼片,而欧洲主机厂却用树脂?(228)
  37. SQL简介及MySQL的安装目录详解(227)
  38. 谁是苏小明饭局爆粗偷拍者?知情人称另有其人(223)
  39. NodeJs之邮件(email)发送(222)
  40. 迪玛希好惨!昨晚《歌手》为声入人心男团帮帮唱,却再被指控侵权(222)
  41. 市值暴跌90%,世界零售巨头申请破产战胜了所有对手却输时代(221)
  42. 函数防抖,与函数节流(219)
  43. 机器学习基石笔记:01 The Learning Problem(217)
  44. 深度学习python的配置(Windows)(215)
  45. [深度应用]·实战掌握Dlib人脸识别开发教程(213)
  46. 许志安出轨视频系蓄谋偷拍?司机被曝收40万装红外摄像头(210)
  47. Google AI 系统 DeepMind 高中数学考试不及格(210)
  48. 干货!21部漫威电影观影顺序指南,在《复联4》之前赶紧补齐!(208)
  49. 赌命生子九个月后,吴梦离世:前半辈子任性了,我用生命买单(206)
  50. 威廉王子出轨凯特王妃闺蜜? 外媒称婚外情致兄弟反目(203)
  51. spring-cloud-sleuth+zipkin源码探究(203)
  52. WebGL three.js学习笔记 纹理贴图模拟太阳系运转(201)
  53. 新更新kb4493472导致无法正常开机(195)
  54. 杜敬谦死因疑曝光!或因他这一特殊的训练方式,泳迷高呼孙杨退役(190)
  55. 韦杰落网,金诚集团终局(188)
  56. AntDesign Form表单字段校验的三种方式(188)
  57. 华为推出方舟编译器 称可提升安卓系统效率(185)
  58. 山东庆云民企3000亩土地被贱卖 国企接盘拟转性(184)
  59. 《权力的游戏》龙妈有那么多爱她的人,为什么最终会选择琼恩雪诺(182)
  60. 张无忌为什么爱上她?陈钰琪版赵敏终于给答案了(181)
  61. “国防”靠美国? 韩国瑜=马英九2.0? 走着瞧(180)
  62. Python破解Wifi密码思路(180)
  63. 直认与老公感情淡了!27岁TVB上位女星:我们不是好熟(179)
  64. CUBA Studio 8.0 发布,企业级应用开发平台(179)
  65. 张丹峰出轨最新锤来了!毕滢的朋友圈简直刷新下限啊!(177)
  66. Github 上 Star 最多的个人 Spring Boot 开源学习项目(176)
  67. 使用 C 语言实现一个 HTTP GET 连接(175)
  68. 拿着普通员工超300倍的工资裁员800人,这家游戏公司CEO引发员工不满|一周新闻(175)
  69. AntD框架的upload组件上传图片时遇到的一些坑(175)
  70. 币安称 4000 万美元比特币被盗(174)
  71. 不要996!程序员创建955.WLB不加班公司名单,GitHub周榜第二(174)
  72. Weblogic CVE-2019-2647等相关XXE漏洞分析(173)
  73. Codejam Qualification Round 2019(173)
  74. simulink创建简单模型(172)
  75. 《跃迁-成为高手的技术》之联机学习(171)
  76. python爬虫重定向次数过多问题(171)
  77. [NewLife.XCode]高级查询(168)
  78. 强大的jQGrid的傻瓜式使用方法。以及一些注意事项,备有相应的引入文件。(167)
  79. 核心算法缺位,人工智能发展面临“卡脖子”窘境(165)
  80. Algolia使用教程 , 超详细傻子看都会(165)
  81. Delphi 开发微信公众平台 (二) 用户管理(164)
  82. 只需知道电话号码 即可监控任意一部手机,获取位置,太可怕(163)
  83. 范斯晶对祖母的称呼很意外,范志毅很心疼,缺少母爱的孩子不容易(162)
  84. 如何定位前端线上问题(如何排查前端生产问题)(162)
  85. 告诉你去越南芽庄必带回的好东西(161)
  86. 数学家发现完美的乘法(160)
  87. 百度网盘下载神器 PanDownload v2.0.9(破解版、不限速)(159)
  88. 双双出轨!许志安劈腿马国明港姐女友,二人被拍16分钟激吻超20次(159)
  89. 高管被警方带走背后:巧达科技操盘2亿人简历生意(159)
  90. 定义工作,解读自我——IT帮2019年2月线下活动回顾(159)
  91. 吹爆惠英红,《铁探》这位霸道总警司超带感!真乃港剧罕见大女主(156)
  92. vue生成图片验证码(155)
  93. 三国正史第一猛将:一人单挑数千人,不是吕布也不是关羽(154)
  94. 从0到1上线一个微信小程序(154)
  95. FreeSql 如何现实 Sqlite 跨库查询(154)
  96. 向佐的弟弟叫向佑,网友:那郭碧婷生的孩子叫什么?(153)
  97. spring-boot-2.0.3不一样系列之源码篇 - pageHelper分页,绝对有值得你看的地方(153)
  98. [Node.js] 3、搭建hexo博客(152)
  99. java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的(152)
  100. TensorFlow从1到2(十)带注意力机制的神经网络机器翻译(151)

  1. 大数据技术之_24_电影推荐系统项目_07_工具环境搭建(具体实操)
  2. 前端限制显示的文本字数的几种方法——不换行与换行
  3. 【实验吧】该题不简单——writeup
  4. 反向传播算法
  5. =、==、===、equals()的区别
  6. GitHub 推出开发者赞助项目
  7. 剑指Offer的学习笔记(C#篇)-- 从上往下打印二叉树
  8. argparse 在深度学习中的应用
  9. 张云雷复出?西城区文旅局:德云社在辖区内演出未发现违法违规问题
  10. Maven安装与配置
  11. acWing 825. 排队购物
  12. ajax&&jquery
  13. 苏联攻击机的悲壮行动,明知德军战机拦截,仍在无护航状态下出击
  14. 华为的5G技术,源于这种数学方法
  15. 一站式自动化测试平台 http://www.Autotestplat.com
  16. RabbitMQ总结
  17. 第九组 通信3班 063 自反ACL
  18. 短线还有最后一跌?大V们表示:反弹近了!(5月23日)
  19. 第九组 通信3班 063 OSPFv2与OSPFv3综合实验
  20. C# IE选项 - 重置IE
  21. Spring_数据校验和自定义检验规则
  22. 谈谈Java的string为什么是不可变的
  23. OFFICE 365 A1 Plus账号注册
  24. 初学python—做一个数组的增删改查操作
  25. oc工程中oc、swift混编代码打包成静态framework踩坑笔记
  26. 阿里云推“智能秒停系统”:50秒内短信通知 再不怕吃罚单
  27. 今天购买了一个云服务器
  28. 神奇!乌鸦竟然会传达悲观和怀疑情绪 还会对同伴“冷嘲热讽”
  29. 数字IC设计入门必备——VIM自定义模板调用与VCS基本仿真操作示例
  30. 点击事件的坐标计算(client || offset) +(X || Width || Left) 各种排列组合别绕晕
  31. windows下dubbo-admin2.6.x之后版本的安装
  32. linux 之基本命令学习总结
  33. 传祺难续“传奇”?销量暴跌超4成 加价卖车被“断裂门”尽毁
  34. 香港豪门后宫持续曝光:他用选美比赛“选妃”,与几万女星交往
  35. 小窥React360——用React创建360全景VR体验
  36. Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)
  37. .Net Core下使用RabbitMQ比较完备的两种方案(虽然代码有点惨淡,不过我会完善)
  38. “80后”女博士已任团中央书记处书记
  39. 杨元庆:现在是联想的最好时刻 我们四大战役全部打了胜仗
  40. Java开发环境的搭建(JDK和Eclipse的安装)
  41. oracle学习笔记(十四) 数据库对象 索引 视图 序列 同义词
  42. 机构风向标:外资出逃超500亿 美的集团等白马股表现欠佳
  43. 跟踪记录ABAP对外部系统的RFC通信
  44. c++11多线程详解(一)
  45. 小蓝杯,跌破发行价了
  46. [NewLife.XCode]百亿级性能
  47. 33岁何洁商场走穴被曝光,路人镜头下的她与精修图差别好大
  48. 途牛第一季度净亏损2240万美元 同比亏损幅度扩大
  49. 00 | Two Sum
  50. 智能威胁分析之图数据构建
  51. 快速掌握RabbitMQ(二)——四种Exchange介绍及代码演示
  52. Neo4j 第六篇:Cypher语法
  53. Java微信公众平台开发(三)--接收消息的分类及实体的创建
  54. Java8 中的 Optional
  55. 如何显示超大图像(3)
  56. 贵州检察机关依法对袁仁国决定逮捕
  57. 有关xerospolit运行报错问题的有效解决方案
  58. ADO学途 one day
  59. Linux 中 ip netns 命令
  60. Python爬虫之设置selenium webdriver等待
  61. BSOJ1040 -- 【练习题目】美元DOLLARS
  62. 外媒:稀土是中国手中的一张王牌
  63. sql server添加sa用户和密码
  64. 深入理解JVM的类加载
  65. querySelector和getElementById之间的区别
  66. 简说设计模式——观察者模式
  67. 扰动函数和拉链法模拟HashMap的存储结构
  68. 东芝中国:“上海东芝公司”不存在 未停止与华为的合作
  69. 彭于晏马思纯主演张爱玲这部小说,却被说更适合演《骆驼祥子》?
  70. 停止向华为供货?东芝辟谣回应
  71. 云米第一季度净利润5310万元 同比增长68%
  72. 贪吃的古蛙,古生物学家发现亿年前两栖动物之间战争
  73. APICloud发布低代码开发平台 效率提升30%至60%
  74. Golang 读写锁RWMutex 互斥锁Mutex 源码详解
  75. shell初级-----数据呈现方式
  76. 白玉兰入围名单公布!《知否》《都挺好》上榜,还有这部豆瓣3分剧
  77. 深网 | 京东618接入快手、抖音 实现“即看即买”
  78. 解决 APP启动白屏黑屏问题
  79. Spring Cloud Hystrix理解与实践(一):搭建简单监控集群
  80. 浏览器与服务器通信技术——jsonp
  81. 【刷题笔记】LeetCode 606. Construct String from Binary Tree
  82. 央行副行长刘国强:应对汇率波动经验丰富,政策工具储备充足
  83. 部署Azure Log Analytics
  84. 计算机基础--http的基础整理和巩固
  85. 章子怡:女人四十,不止表面风光
  86. 直击|对话杨元庆:希望今年创最好盈利 要震慑住谣言
  87. 微软通过合作为美国270万农村退伍军人提供高速宽带服务
  88. Java进程占用内存过高,排查解决方法
  89. Go语言中使用切片(slice)实现一个Vector容器
  90. 商务部回应美宣布对13个中国企业或个人实施制裁:反对“长臂管辖”
  91. 优酷土豆的Redis服务平台化之路
  92. shell初级-----处理用户输入
  93. 感受lambada之美,推荐收藏,需要时查阅
  94. 美团点评发布2019年第一季度财报,营收192亿元超预期
  95. 任正非:Arm暂停合作对华为没影响
  96. redis和memcached的区别(总结)
  97. Spring Cloud与Duddo比较
  98. File类
  99. 朝鲜最强智能手机!人脸识别、无线充电、画质感人还支持无线耳机
  100. “断供”传闻屡遭反转,谁在制造恐慌?