OSGi使Java代码可以清晰地划分为多个模块,这些模块称为捆绑软件 ,可以访问由每个捆绑软件的类加载器控制的代码和资源。 OSGi 服务提供了一种附加的分离机制:接口的用户不需要依赖于实现类,工厂等。

以下案例研究旨在使OSGi捆绑包和服务的上述优势具体化。 它采用了一个有趣的Java项目vert.x,并展示了如何将其嵌入OSGi并利用OSGi的功能。

免责声明:我不建议更换vert.x容器或其模块系统。 这主要是在OSGi的使用中进行的案例研究,尽管某些发现应该促使对vert.x进行改进,尤其是将其嵌入具有自定义类加载器的应用程序中时。

版本号

vert.x开源项目提供了node.js的JVM替代方案:异步,事件驱动的编程模型,用于以多种语言(包括Java,Groovy,JavaScript和Ruby)编写Web应用程序。

vert.x支持HTTP以及现代协议,例如WebSockets和sockjs (与WebSockets 相比 ,它们在更多的浏览器中工作,并且可以更轻松地穿越防火墙)。
vert.x具有分布式事件总线,允许已知为verticles并称为busmods共享代码库vert.x应用程序之间进行传播JSON消息。 busmod是一种特殊的Verticle,它处理事件总线中的事件。 vert.x舰艇一些busmods,如MongoDB的 “persistor”,用户可以写自己的。

vert.x的线程模型很有趣,因为每个顶点(或busmod)在其生命周期内都绑定到特定线程,因此,顶点代码无需关注线程安全性。 线程池用于在顶点上分派工作,并且每个顶点必须避免阻塞或长时间运行的操作,以免影响服务器吞吐量(vert.x提供了有效地实现长时间运行的操作的单独机制)。 这类似于CICS事务处理器中的准可重入线程模型。 1个

这里特别受关注的是vert.x模块系统,该系统在每个顶点上都有一个类加载器和称为模块的代码库,它们被加载到使用它们的每个顶点的类加载器中。 因此,除了通过事件总线之外,没有其他方法可以在各个顶点之间共享代码。

vert.x具有出色的文档,包括主要手册 , java手册 (以及其他语言的手册), 教程和可运行的代码示例 。

OSGi

如果您还不熟悉OSGi,请阅读我的OSGi简介文章,但现在不要再理会该文章中的链接-您可以随时返回并稍后再做。

将vert.x嵌入OSGi

我通过几个小步骤完成了此操作,下面依次介绍了这些步骤:将vert.x JAR转换为OSGi捆绑包,然后模块化verticle,busmod和事件总线客户端。

将vert.x JAR转换为OSGi捆绑软件

vert.x手册鼓励用户使用vert.x核心JAR将vert.x嵌入其自己的应用程序中,因此将vert.x嵌入OSGi的第一步是将vert.x核心JAR转换为OSGi捆绑包,因此可以将其加载到OSGi运行时中。

我使用了Bundlor工具,尽管其他工具(例如bnd)也可以很好地工作。 Bundlor接受一个模板,然后分析JAR的字节码以生成带有适当OSGi清单标头的新JAR。 请立即参阅SpringSource Bundlor文档以获取有关Bundlor的更多信息,因为在撰写本文时Eclipse Virgo Bundlor文档尚未发布,即使Bundlor项目已转移到Eclipse.org。

vert.x核心JAR的模板如下:

Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.vertx.core
Bundle-Version: 1.0.0.final
Bundle-Name: vert.x Core
Import-Template:org.jboss.netty.*;version="[3.4.2.Final,4.0)",org.codehaus.jackson.*;version="[1.9.4,2.0)",com.hazelcast.*;version="[2.0.2,3.0)";resolution:=optional,groovy.*;resolution:=optional;version=0,org.codehaus.groovy.*;resolution:=optional;version=0,javax.net.ssl;resolution:=optional;version=0,org.apache.log4j;resolution:=optional;version=0,org.slf4j;resolution:=optional;version=0
Export-Template: *;version="1.0.0.final"

(此案例研究的模板和所有其他部分可在github上找到 。)

这是为JAR所依赖的软件包定义有效的版本范围(范围“ 0”表示0或更大的版本范围),这些软件包是可选的还是强制的,以及JAR自己的软件包应为哪个版本出口处。 它还为捆绑软件提供了符号名称 (用于标识捆绑软件),版本和(描述性)名称。 有了这些信息,OSGi然后通过委派包类加载器之间的类加载和资源查找,将包的依赖关系连接在一起。

值得庆幸的网状网络JAR和杰克逊 JSON JAR文件将vert.x核心JAR取决于附带有效的OSGi清单。

为了验证清单是否有效,我尝试在处女座内核中部署vert.x核心软件包。 只需将vert.x核心捆绑包放置在Pickup目录中,并将其依赖项放置在repository / usr目录中,然后启动内核即可。 以下控制台消息显示vert.x核心捆绑包已安装并成功解决:

<hd0001i> Hot deployer processing 'INITIAL' event for file 'vert.x-core-1.0.0.final.jar'.
<de0000i> Installing bundle 'org.vertx.core' version '1.0.0.final'.
<de0001i> Installed bundle 'org.vertx.core' version '1.0.0.final'.
<de0004i> Starting bundle 'org.vertx.core' version '1.0.0.final'.
<de0005i> Started bundle 'org.vertx.core' version '1.0.0.final'.

然后使用处女座外壳,检查线束的接线:

osgi> ss
"Framework is launched."id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.7.1.R37x_v20110808-1106
...
89      ACTIVE      org.vertx.core_1.0.0.final
90      ACTIVE      jackson-core-asl_1.9.4
91      ACTIVE      jackson-mapper-asl_1.9.4
92      ACTIVE      org.jboss.netty_3.4.2.Finalosgi> bundle 89
org.vertx.core_1.0.0.final [89]...Exported packages...org.vertx.java.core; version="1.0.0.final"[exported]org.vertx.java.core.buffer; version="1.0.0.final"[exported]...Imported packagesorg.jboss.netty.util; version="3.4.2.Final"<org.jboss.netty_3.4.2.final [92]>...org.codehaus.jackson.map; version="1.9.4"<jackson-mapper-asl_1.9.4 [91]>...

我还按照以后需要的类似方式将vert.x平台JAR转换为OSGi捆绑软件。

模块化顶点

一个典型的顶点如下所示:

public class ServerExample extends Verticle {public void start() {vertx.createHttpServer().requestHandler(new Handler<httpserverrequest>() {public void handle(HttpServerRequest req) {...}}).listen(8080);}
}

调用start方法时,它将创建一个HTTP服务器,并向该服务器注册一个处理程序,并设置服务器在端口上侦听。 除了处理程序的主体之外,该代码的其余部分都是样板。 因此,我决定将样板分解为一个通用的OSGi捆绑包(org.vertx.osgi),并用包含处理程序和一些等同于样板的声明性元数据的模块化顶包替换该顶标。 常见的OSGi捆绑包使用白板模式来侦听OSGi服务注册表中的特定种类的服务,基于元数据创建样板,并向生成的HTTP服务器注册处理程序。

让我们看一下模块化的vertical bundle。 它的代码包含一个HttpServerRequestHandler类: 2

public final class HttpServerRequestHandler implements Handler<httpserverrequest> {public void handle(HttpServerRequest req) {...}}

它还具有服务属性形式的声明性元数据,该声明性元数据与OSGi服务注册表中的处理程序一起注册。 我可以使用OSGi蓝图服务来执行此操作,尽管我可以使用OSGi声明性服务,甚至可以使用OSGi API以编程方式注册该服务。 蓝图元数据是捆绑软件中的文件blueprint.xml ,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"><service interface="org.vertx.java.core.Handler" ref="handler"><service-properties><entry key="type" value="HttpServerRequestHandler"><entry key="port" value="8090"></service-properties></service><bean class="org.vertx.osgi.sample.basic.HttpServerRequestHandler"id="handler"/></blueprint>

此元数据声明应创建HTTP服务器(通过类型服务属性),向其注册的处理程序以及侦听端口8090的服务器集(通过端口服务属性)。 当org.vertx.osgi捆绑包运行时,这一切都是通过白板模式完成的,如下所示。

请注意,模块化Verticle仅依赖于Handler和HttpServerRequest类,而原始Verticle也依赖于Vertx,HttpServer和Verticle类。 对于那些喜欢单元测试(除了容器内测试)的人来说,这也使事情变得简单得多,因为所需的模拟或存根数量更少。

那么我们现在有什么呢? 将两个包添加到我们先前安装的包中:一个org.vertx.osgi包,它封装了样板代码;一个应用程序包,它代表一个模块化的verticle。 我们还需要一个Blueprint服务实现-从Virgo 3.5开始,Virgo内核内置了一个Blueprint实现。 以下交互图显示了一种可能的事件序列:

在OSGi中,每个捆绑软件都有其自己的生命周期,并且通常设计捆绑软件时,无论它们相对于其他捆绑软件启动的顺序如何,它们都将正确运行。 在上面的示例中,假定的开始顺序为:蓝图服务,org.vertx.osgi包,模块化verticle包。 但是,org.vertx.osgi捆绑包可以在模块化Verticle捆绑包之后开始,并且最终结果将是相同的:将创建服务器,并且在服务器上注册模块化Verticle捆绑包的处理程序,并且服务器设置监听。 如果蓝图服务是在org.vertx.osgi和模块化Verticle捆绑包之后启动的,那么直到蓝图服务启动后,org.vertx.osgi捆绑包才会检测到模块化注册表包的处理程序服务出现在服务注册表中,但是最终结果将再次相同。

github项目包含一些示例模块verticle的源代码: 基本的HTTP垂直版本 (在8090端口上运行)和sockjs verticle (在8091端口上运行)。 org.vertx.osgi捆绑软件需要更多的代码来支持sockjs,而模块化的sockjs verticle除了提供HTTP处理程序外,还需要提供sockjs处理程序。

模块化BusMods

MongoDB持久程序是处理事件总线消息的busmod的典型示例:

public class MongoPersistor extends BusModBase implements Handler<message<jsonobject>> {private String address;private String host;private int port;private String dbName;private Mongo mongo;private DB db;public void start() {super.start();address = getOptionalStringConfig("address", "vertx.mongopersistor");host = getOptionalStringConfig("host", "localhost");port = getOptionalIntConfig("port", 27017);dbName = getOptionalStringConfig("db_name", "default_db");try {mongo = new Mongo(host, port);db = mongo.getDB(dbName);eb.registerHandler(address, this);} catch (UnknownHostException e) {logger.error("Failed to connect to mongo server", e);}}public void stop() {mongo.close();}public void handle(Message<jsonobject> message) {...}}

再次,混合了样板代码(用于注册事件总线处理程序),启动/停止逻辑,配置处理以及事件总线处理程序本身。 我对其他竖版应用了类似的方法,并将样板代码分离到org.vertx.osgi包中,将处理程序和元数据(包括配置)保留在模块化busmod中。 持久性对MongoDB客户端JAR(mongo.jar)的依赖很方便,因为此JAR附带了有效的OSGi清单。

这是blueprint.xml :

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"><service ref="handler" interface="org.vertx.java.core.Handler"><service-properties><entry key="type" value="EventBusHandler"/><entry key="address" value="vertx.mongopersistor"/></service-properties></service><bean id="handler" class="org.vertx.osgi.mod.mongo.MongoPersistor"destroy-method="stop"><argument type="java.lang.String"><value>localhost</value></argument><argument type="int"><value>27017</value></argument><argument type="java.lang.String"><value>default_db</value></argument></bean></blueprint>

请注意,样板配置由处理程序类型和事件总线地址组成。 其他配置(主机,端口和数据库名称)特定于MongoDB持久程序。

这是模块化的MongoDB busmod代码 :

public class MongoPersistor extends BusModBaseimplements Handler<Message<JsonObject>> {private final String host;private final int port;private final String dbName;private final Mongo mongo;private final DB db;public MongoPersistor(String host, int port, String dbName)throws UnknownHostException, MongoException {this.host = host;this.port = port;this.dbName = dbName;this.mongo = new Mongo(host, port);this.db = this.mongo.getDB(dbName);}public void stop() {mongo.close();}public void handle(Message<JsonObject> message) {...}}

该代码仍然扩展了BusModBase,仅仅是因为BusModBase提供了几种方便的辅助方法。 同样,与非模块化等效代码相比,生成的代码更简单,更易于单元测试。

模块化事件总线客户端

最后,我需要一个模块化的Verticle来测试模块化的MongoDB持久性。 这些verticle需要做的就是将适当的消息发布到事件总线。 普通的vert.x垂直版本使用Vertx类获取事件总线,但是我再次使用了Blueprint服务,这一次是在服务注册表中查找事件总线服务,并将其注入到模块化垂直版本中。 我还扩展了org.vertx.osgi捆绑包,以便在服务注册表中发布事件总线服务。

模块化事件总线客户端的blueprint.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"><reference id="eventBus" interface="org.vertx.java.core.eventbus.EventBus"/><bean class="org.vertx.osgi.sample.mongo.MongoClient"><argument ref="eventBus"/><argument type="java.lang.String"><value>vertx.mongopersistor</value></argument></bean></blueprint>

然后, 模块化事件总线客户端代码非常简单:

public final class MongoClient {public MongoClient(EventBus eventBus, String address) {JsonObject msg = ...eventBus.send(address, msg,new Handler<Message<JsonObject>>(){...});}}

旋转一下

1.我已经在git的bundles目录中提供了所有必需的OSGi捆绑包 。 您可以通过克隆git存储库来获取它们:

git clone git://github.com/glyn/vert.x.osgi.git

或通过下载git repo的zip文件 。

2. vert.x需要Java 7 ,因此请设置终端外壳以使用Java7 。确保正确设置了JAVA_HOME环境变量。 (如果现在无法获取Java 7,则将捆绑软件部署到OSGi时会看到一些错误,并且您将无法在步骤8和9中运行示例。)

3.如果您是OSGi用户,只需在您喜欢的OSGi框架或容器中安装并启动捆绑软件,然后跳至步骤8。否则,请按以下方式使用git存储库中的Virgo内核副本。

4.将目录更改为git repo本地副本中的virgo-kernel-…目录。

5.在UNIX上,发出:

bin/startup.sh -clean

或在Windows上,发出:

bin\startup.bat -clean

6.处女座内核应在其拾取目录中启动并部署各种捆绑软件:

  • org.vertx.osgi捆绑包( org.vertx.osgi-0.0.1.jar
  • HTTP示例模块化org.vertx.osgi.sample.basic-1.0.0.jarorg.vertx.osgi.sample.basic-1.0.0.jar
  • SockJS示例模块化verticle( org.vertx.osgi.sample.sockjs-1.0.0.jar
  • MongoDB持久性示例模块化busmod( org.vertx.osgi.mods.mongo-1.0.0.jar

7.如果要查看现在正在运行的捆绑软件,请从另一个终端启动Virgo Shell:

telnet localhost 2501

并使用sslb命令汇总已安装的捆绑软件。 help命令将列出其他可用命令,而disconnect将使您脱离Virgo Shell。 这是ss命令的典型输出:

...
89      ACTIVE      org.vertx.osgi_0.0.1
90      ACTIVE      jackson-core-asl_1.9.4
91      ACTIVE      jackson-mapper-asl_1.9.4
92      ACTIVE      org.jboss.netty_3.4.2.Final
93      ACTIVE      org.vertx.core_1.0.0.final
94      ACTIVE      org.vertx.osgi.mods.mongo_1.0.0
95      ACTIVE      com.mongodb_2.7.2
96      ACTIVE      org.vertx.platform_1.0.0.final
97      ACTIVE      org.vertx.osgi.sample.basic_1.0.0
98      ACTIVE      org.vertx.osgi.sample.sockjs_1.0.0

lb命令(包括更具描述性的Bundle-Name标头):

...89|Active     |    4|vert.x OSGi Integration (0.0.1)90|Active     |    4|Jackson JSON processor (1.9.4)91|Active     |    4|Data mapper for Jackson JSON processor (1.9.4)92|Active     |    4|The Netty Project (3.4.2.Final)93|Active     |    4|vert.x Core (1.0.0.final)94|Active     |    4|MongoDB BusMod (1.0.0)95|Active     |    4|MongoDB (2.7.2)96|Active     |    4|vert.x Platform (1.0.0.final)97|Active     |    4|Sample Basic HTTP Verticle (1.0.0)98|Active     |    4|Sample SockJS Verticle (1.0.0)

8.现在,您可以使用Web浏览器在localhost:8090尝试基本的HTTP示例,该示例应响应“ hello”,或在http:// localhost:8091的SockJS示例应显示一个框,您可以在其中键入一些文本和一个按钮,单击该按钮会弹出一个窗口:

9.如果要尝试(无头的)MongoDB事件总线客户端,请下载MondoDB并在其默认端口上本地启动 ,然后将org.vertx.osgi.sample.mongo-1.0.0.jarbundles目录复制到Virgo的提取目录。 此捆绑包启动后,它将立即向事件总线发送一条消息,并驱动MongoDB持久程序更新数据库。 如果您不想使用MongoDB来检查是否进行了更新,请查看处女座的日志(在serviceability/logs/log.log )以查看一些System.out行,例如以下内容,该行确认发生了某些情况:

System.out Sending message: {action=save, document={x=y}, collection=vertx.osgi}
...
System.out Message sent
...
System.out Message response {_id=95..., status=ok}

OSGi和vert.x模块化

在本案例研究中,各种示例OSGi捆绑包都依赖于并共享vert.x核心捆绑包。 每个捆绑包都加载在其自己的类加载器中,并且OSGi根据OSGi捆绑包的连接方式控制类加载和资源查找的委派。 以相同的方式,写为OSGi包的顶点可以自由地依赖和共享其他OSGi包。

这与vert.x模块系统大不相同,在vert.x模块系统中,一个verticle依赖的任何模块(除了busmod之外)都被加载到与verticle相同的类加载器中。

OSGi模块系统的优点是,每个模块的单个副本安装在系统中,并且对于诸如Virgo shell之类的工具可见并且可以由其管理。 它还使占地面积最小。

vert.x模块系统的优点是,在各个顶点之间不存在模块共享,因此,编写不当的模块不会无意或有意地泄漏独立顶点之间的信息。 此外,每个使用它的垂直模块都有每个(非busmod)模块的单独副本,因此可以编写模块而不必担心线程安全,因为每个副本仅在其垂直线程上执行。 但是,OSGi用户可能很高兴要求可重用的模块具有线程安全性,并谨慎地管理任何可变的静态数据,以避免线程之间的泄漏。  

更换容器?

当我提出将vert.x嵌入OSGi的话题时, vert.x的负责人蒂姆·福克斯(Tim Fox)问我是否正在编写当前容器的替代品,对此我回答“不是真的”。 我之所以这样说,是因为我喜欢vert.x的事件驱动编程模型及其线程模型,它们似乎是“容器”的一部分。 但想更换一对夫妇的vert.x容器方面:模块系统和verticles登记处理的方式。

后来让我吃惊的是,在模块化系统中,“容器”作为整体实体的概念可能有点奇怪,最好考虑多个单独的容器概念,然后以不同的方式组合以适应不同的容器用户。 但是,上面看到的类加载和线程模型之间的微妙交互表明,包含的不同概念可以相互依赖。 我想知道其他人如何看待“容器”的概念吗?

结论

由于OSGi框架是一个相当严格的应用程序,因此vert.x声称它可以嵌入其他应用程序中的说法已得到验证。

vert.x模块系统尽管未在模块之间提供隔离,但确实在应用程序之间(包括垂直模块及其模块)提供了隔离,并且使模块的编写无需关注线程安全。

提出了一个vert.x问题2 ,这应该使vert.x易于使用自定义类加载器嵌入其他环境。

vert.x可以遵循netty,jackson和MongoDB JAR的示例,并在其核心JAR和平台JAR中包含OSGi清单,以避免OSGi用户不得不将这些JAR转换为OSGi捆绑包。 我将这个问题留给其他人提出,因为我无法评估在OSGi中使用vert.x的需求。

在OSGi中运行vert.x可以满足一些出色的vert.x要求,例如如何自动化容器内测试(OSGi有许多解决方案,包括Pax Exam,而Virgo有集成测试框架)以及如何开发verticles并将它们部署到vert .x在IDE的控制下(请参阅Virgo IDE工具指南 )。 处女座还提供了许多附带的好处,包括用于检查和管理束和顶点的管理外壳,复杂的诊断程序以及更多其他功能(有关详细信息,请参阅处女座白皮书 )。

该练习还为处女座带来了一些不错的收益。 修复了370253错误 ,这是在Java 7下运行Virgo的唯一已知问题。Virgo3.5依赖于在此环境中中断的Gemini蓝图,因此引发并修复了错误379384 。 我使用了新的基于Eclipse的Virgo工具来开发各种捆绑软件并在Virgo中运行它们。 结果,我在工具中发现了一些小问题,这些问题将适时解决。

最后,在Virgo内核上运行vert.x是对内核是否适合构建自定义服务器运行时的进一步验证,因为现在除了Tomcat,Jetty以及在内核上运行的一两个自定义服务器之外,我们还具有vert.x。

脚注:

  1. 在IBM的日子里,我曾在CICS开发团队中工作。 SpringSource的一位同事给了我“ CICS做到了!” 我们开始合作后不久就穿了T恤。 旧习难改。
  2. 模块化垂直模块当前需要拦截vert.x的资源查找逻辑,以便可以轻松提供捆绑中的文件。 将此通用代码移至org.vertx.osgi捆绑包会更好,但这需要首先实现vert.x问题161 。

参考: OSGi案例研究:来自Mind the Gap博客的JCG合作伙伴 Glyn Normington 的模块化vert.x。

翻译自: https://www.javacodegeeks.com/2012/07/osgi-case-study-modular-vertx.html

OSGi案例研究:模块化vert.x相关推荐

  1. osgi 模块化_OSGi案例研究:模块化vert.x

    osgi 模块化 OSGi使Java代码可以清晰地划分为多个模块,这些模块称为捆绑软件 ,可以访问由每个捆绑软件的类加载器控制的代码和资源. OSGi 服务提供了一种附加的分离机制:接口的用户无需依赖 ...

  2. 工厂模式个人案例_工厂设计模式案例研究

    工厂模式个人案例 我有一份工作来检查我们的项目代码质量. 如果我在项目中发现任何障碍,必须将其报告给我的团队负责人. 我发现了很多漏洞,我认为可以在博客上进行讨论. 不是嘲笑作者,而是一起学习和改进自 ...

  3. 工厂设计模式案例研究

    我有一份工作来检查我们的项目代码质量. 如果我在项目中发现任何障碍,必须将其报告给我的团队负责人. 我发现了很多漏洞,我认为可以在博客上进行讨论. 不是嘲笑作者,而是一起学习和改进自己. 像这段代码一 ...

  4. 深入理解OSGI:Java模块化之路

    Java可能是近20年来最成功的开发技术,因其具备通用性.高效性.平台移植性和安全性而成为不同硬件平台理想的开发工具.从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Java技术 ...

  5. javascript案例_如何在JavaScript中使用增强现实-一个案例研究

    javascript案例 by Apurav Chauhan 通过Apurav Chauhan 如何在JavaScript中使用增强现实-一个案例研究 (How to use Augmented Re ...

  6. R语言条件Logistic回归模型案例:研究饮酒与胃癌的关系

    R语言条件Logistic回归模型案例:研究饮酒与胃癌的关系 目录 R语言条件Logistic回归模型案例:研究饮酒与胃癌的关系 #样例数据

  7. 独家 | 机器学习真实案例研究:基于文本描述的交易聚类

    作者:Ravindra Reddy Tamma 翻译:方星轩 校对:欧阳锦 本文约2200字,建议阅读5分钟. 本文为大家介绍了在日常的电子交易中对用户的交易信息进行聚类分析和建模,提供了用户分析的思 ...

  8. 独家 | 探索性文本数据分析的新手教程(Amazon案例研究)

    作者:Abhishek Sharma 翻译:李嘉骐 校对:方星轩 本文长度为5500字,建议阅读10+分钟 本文利用Python对Amazon产品的反馈对数据文本进行探索性研究与分析,并给出结论. 标 ...

  9. 独家 | 规范性分析的实用介绍(附R语言案例研究演示代码)

    翻译:张睿毅 校对:吴金笛 本文约4500字,建议阅读15分钟. 本文是作为Analytics Vidhya's Internship Challenge的一部分提交的案例研究. Analytics ...

最新文章

  1. .dat文件还原数据库
  2. 【机器学习】降维代码练习
  3. python propresql mysql_Python中操作mysql的pymysql模块详解
  4. 【工作总结】银行应用系统架构(二)
  5. java socket 握手_TCP建立连接三次握手过程详解(wireshark截图、java socket源码)
  6. PyTorch 入坑五 autograd与逻辑回归
  7. Android7.0以后的ninja编译系统
  8. javascript 学习--javascript高级程序设计
  9. 自动驾驶7-2 最终项目概述 Final Project Overview
  10. 中国神话--学术性研究
  11. sklearn实现决策树
  12. 《黑客帝国》的宗教启示
  13. 去掉 终端里烦人的嘟嘟声
  14. MyEclipse导入项目后报Unknown Faceted Project Problem (Java Version Mismatch)的解决方法
  15. raid5阵列两块硬盘掉线如何恢复阵列中的数据库
  16. 砥砺前行20载,他见证了中国制造信息化的成长
  17. 【全栈计划 —— 编程语言之C#】 C# 实现双人飞行棋小游戏
  18. Arduino与Proteus仿真实例-AT24C256串行(I2C)EEPROM数据存取驱动仿真
  19. Java+MySQL基于ssm的图书馆图书借阅管理系统
  20. 平凡的世界-少安少平

热门文章

  1. git rebase命令(转)
  2. 转:在eclipse中搭建maven工程(第二种方法)
  3. tomcat(13)Host和Engine容器
  4. AQS的细节--自用,非正常教程
  5. 构建器设计模式_创新设计模式:构建器模式
  6. 网络研讨室_网络研讨会:Java 9的第一印象–构建可伸缩企业应用程序的新方法...
  7. 交流伺服系统设计指南_交流设计
  8. java创建一个不可变对象_使用不可变对象创建值对象
  9. .jdeveloper_在JDeveloper 12.1.3中为WebSocket使用Java API
  10. java identity_仔细研究Java Identity API