成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java9模塊化學(xué)習(xí)筆記一之快速入門

cjie / 718人閱讀

摘要:如果你想查看運(yùn)行時(shí)模塊的加載過程輸出結(jié)果表示為模塊,由于我限制了不再往下輸出了,而我們模塊又沒有別的額外依賴,所以僅有這行輸出。

jdk9模塊快速入門

列出自帶模塊:java --list-modules
mac多版本jdk共存:http://adolphor.com/blog/2016...
模塊規(guī)則示意圖:

incubator modules:孵化模塊 以jdk.incubator開頭,比如jdk.incubator.httpclient(jdk11之后這是正式的模塊了:[java.net.http][1],具體參考:http://openjdk.java.net/jeps/...

module descriptor:模塊描述文件 module-info.java 例如java.prefs的模塊描述文件內(nèi)容:

module java.prefs{
    requires java.xml;
    exports java.util.prefs;
}

requires代表依賴的模塊,只有依賴的模塊存在才能通過編譯并運(yùn)行.需要注意的是,所有模塊均自動(dòng)隱式依賴java.base模塊,不需要顯示聲明
exports指出需要暴露的包,如果某個(gè)包沒有被exports,那么其他模塊是無法訪問的。

兩個(gè)名詞:Readability,Accessibility

Readability:指的是必須exports的包才可被其他模塊訪問
Accessibility:指的是即使是exports的包,其中的類的可訪問下也要基于java的訪問修飾符,僅有public修飾的才可被其他模塊訪問

Implied Readability(隱式Readability, requires transitive):
Readability默認(rèn)情況下是不會(huì)被傳遞的, 比如Maven中,我們知道依賴可以被傳遞,但是module的requires不會(huì)被傳遞,比如: 下圖中java.desktop無法訪問java.xml模塊中exports的包,雖然它引用了java.prefs模塊

但是如果你將requires改成requires transitive的話,那么傳遞性依賴就可以生效了。
有個(gè)時(shí)候我們定義API模塊時(shí)經(jīng)常忘記哪些該requires transitive,這時(shí)該怎么辦呢? 模塊編譯時(shí)使用-Xlint:exports選項(xiàng),它會(huì)檢測(cè)出這些問題并warn。
Aggregate Module(聚合模塊)
由于requires transitive的存在,就可以支持聚合模塊。有些聚合模塊可以沒有任何代碼,就一個(gè)module-info.java描述文件,比如java.se, java.se.ee模塊
不建議直接引用java.se模塊,因?yàn)樗拖喈?dāng)于java9以前版本的rt.jar的內(nèi)容。

Qualified Exports(有限制的exports)
比如我只想exports某個(gè)包給部分模塊,而不是所有模塊

exports com.sun.xml.internal.stream.writers to java.xml.ws,java.sql;

Qualified Exports不建議普通模塊使用,java platform使用它主要是為了減少內(nèi)部重復(fù)代碼,一般用它暴露internal內(nèi)部使用的一些類給部分模塊。

module path
module path類似于classpath,只不過它只包括module
module resolution支持定義模塊依賴圖,根據(jù)root module去查詢。

在modular jdk中以非模塊化方式開發(fā)
在java9中也是允許你以非模塊化方式開發(fā)和運(yùn)行應(yīng)用的(也就是說,模塊化開發(fā)是可選的),如果你的應(yīng)用中沒有module-info.java,那么這就是一個(gè)unnamed module. java9對(duì)于unnamed module的處理方式就是所有的jdk模塊均直接可用(模塊圖中是以java.se模塊作為root模塊的,也意味著多帶帶處于java.se.ee下的一些包,比如JAXB API是無法訪問到的)。
但是需要注意的是,在java8以及之前的版本中,我們可以訪問jdk中的一些不推薦訪問的內(nèi)部類,比如com.sun.image.codec.jpeg,但在java9模塊化之后被強(qiáng)封裝了,所以在java9中無法使用這些內(nèi)部類,也就是說無法通過編譯,但是java9為了保持兼容性,允許之前引用這些內(nèi)部類的已有的jar或已編譯的類正確運(yùn)行。換言之,就是java9不允許源碼中引用這些類,無法通過編譯,但是之前版本中引用這些類的已編譯class文件是允許正常運(yùn)行的。

模塊結(jié)構(gòu)
MacBook-Pro:easytext-singlemodule tjw$ tree
.
├── README.md
├── out
│   └── easytext
│       ├── javamodularity
│       │   └── easytext
│       │       └── Main.class
│       └── module-info.class
├── run.sh
└── src
    └── easytext
        ├── javamodularity
        │   └── easytext
        │       └── Main.java
        └── module-info.java

其中區(qū)別于傳統(tǒng)src目錄,模塊src目錄下首先是模塊目錄easytext,這名字與module-info.java里的保持一致,模塊目錄下包含源碼及module-info.java模塊描述文件。src/easytext是源碼目錄, javamodularity/easytext是包

編譯文件run.sh內(nèi)容:

mkdir -p out

javac -d out --module-source-path src -m easytext
java --module-path out -m easytext/javamodularity.easytext.Main

打包成jar

jar -cfe out/easytext.jar javamodularity.easytext.Main -C out/easytext .

-cf不用說了,-e指定入口類,-C指定需要打包進(jìn)jar的文件路徑
運(yùn)行模塊jar:

java --module-path out -m easytext

請(qǐng)注意,這與直接運(yùn)行模塊目錄的區(qū)別:java --module-path out -m easytext/javamodularity.easytext.Main, 運(yùn)行模塊jar由于我們打包時(shí)通過-e選項(xiàng)指定了入口類,這時(shí)-m只需要指定模塊名即可運(yùn)行。

如果你想查看運(yùn)行時(shí)模塊的加載過程:java --show-module-resolution --limit-modules java.base --module-path out -m easytext
輸出結(jié)果: 表示easytext為root模塊,由于我限制了java.base不再往下輸出了,而我們模塊又沒有別的額外依賴,所以僅有這行輸出。

root easytext file:///Users/tjw/learn/java-9-moodularity-examples/chapter3/easytext-singlemodule/out/easytext.jar

假如我去掉--limit-modules限制,運(yùn)行,則輸出如下:java --show-module-resolution --module-path out -m easytext

root easytext file:///Users/tjw/learn/java-9-moodularity-examples/chapter3/easytext-singlemodule/out/easytext.jar
java.base binds jdk.localedata jrt:/jdk.localedata
java.base binds jdk.charsets jrt:/jdk.charsets
java.base binds jdk.jlink jrt:/jdk.jlink
java.base binds jdk.jartool jrt:/jdk.jartool
java.base binds jdk.jdeps jrt:/jdk.jdeps
java.base binds jdk.compiler jrt:/jdk.compiler
java.base binds jdk.javadoc jrt:/jdk.javadoc
java.base binds jdk.packager jrt:/jdk.packager
java.base binds java.desktop jrt:/java.desktop
java.base binds jdk.crypto.cryptoki jrt:/jdk.crypto.cryptoki
java.base binds java.naming jrt:/java.naming
java.base binds jdk.crypto.ec jrt:/jdk.crypto.ec
java.base binds java.xml.crypto jrt:/java.xml.crypto
java.base binds java.security.jgss jrt:/java.security.jgss
java.base binds java.security.sasl jrt:/java.security.sasl
java.base binds jdk.deploy jrt:/jdk.deploy
java.base binds java.smartcardio jrt:/java.smartcardio
java.base binds jdk.security.jgss jrt:/jdk.security.jgss
java.base binds java.logging jrt:/java.logging
java.base binds jdk.security.auth jrt:/jdk.security.auth
java.base binds java.management jrt:/java.management
java.base binds jdk.zipfs jrt:/jdk.zipfs
jdk.security.auth requires java.security.jgss jrt:/java.security.jgss
jdk.security.auth requires java.naming jrt:/java.naming
jdk.security.jgss requires java.security.jgss jrt:/java.security.jgss
jdk.security.jgss requires java.security.sasl jrt:/java.security.sasl
jdk.security.jgss requires java.logging jrt:/java.logging
jdk.deploy requires jdk.unsupported jrt:/jdk.unsupported
jdk.deploy requires java.desktop jrt:/java.desktop
jdk.deploy requires java.naming jrt:/java.naming
jdk.deploy requires java.scripting jrt:/java.scripting
jdk.deploy requires java.prefs jrt:/java.prefs
jdk.deploy requires java.logging jrt:/java.logging
jdk.deploy requires java.rmi jrt:/java.rmi
jdk.deploy requires java.xml jrt:/java.xml
jdk.deploy requires java.management jrt:/java.management
java.security.sasl requires java.logging jrt:/java.logging
java.security.jgss requires java.naming jrt:/java.naming
java.xml.crypto requires java.logging jrt:/java.logging
java.xml.crypto requires java.xml jrt:/java.xml
java.naming requires java.security.sasl jrt:/java.security.sasl
jdk.crypto.cryptoki requires jdk.crypto.ec jrt:/jdk.crypto.ec
java.desktop requires java.datatransfer jrt:/java.datatransfer
java.desktop requires java.xml jrt:/java.xml
java.desktop requires java.prefs jrt:/java.prefs
jdk.packager requires java.logging jrt:/java.logging
jdk.packager requires java.desktop jrt:/java.desktop
jdk.packager requires java.xml jrt:/java.xml
jdk.packager requires jdk.jlink jrt:/jdk.jlink
jdk.javadoc requires jdk.compiler jrt:/jdk.compiler
jdk.javadoc requires java.xml jrt:/java.xml
jdk.javadoc requires java.compiler jrt:/java.compiler
jdk.compiler requires java.compiler jrt:/java.compiler
jdk.jdeps requires jdk.compiler jrt:/jdk.compiler
jdk.jdeps requires java.compiler jrt:/java.compiler
jdk.jlink requires jdk.internal.opt jrt:/jdk.internal.opt
jdk.jlink requires jdk.jdeps jrt:/jdk.jdeps
java.prefs requires java.xml jrt:/java.xml
java.rmi requires java.logging jrt:/java.logging
java.management binds java.management.rmi jrt:/java.management.rmi
java.management binds jdk.management.cmm jrt:/jdk.management.cmm
java.management binds jdk.management.jfr jrt:/jdk.management.jfr
java.management binds jdk.management jrt:/jdk.management
java.management binds jdk.internal.vm.compiler.management jrt:/jdk.internal.vm.compiler.management
java.scripting binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn
java.naming binds jdk.naming.dns jrt:/jdk.naming.dns
java.naming binds jdk.naming.rmi jrt:/jdk.naming.rmi
java.datatransfer binds java.desktop jrt:/java.desktop
java.compiler binds jdk.compiler jrt:/jdk.compiler
java.compiler binds jdk.javadoc jrt:/jdk.javadoc
jdk.naming.rmi requires java.rmi jrt:/java.rmi
jdk.naming.rmi requires java.naming jrt:/java.naming
jdk.naming.dns requires java.naming jrt:/java.naming
jdk.scripting.nashorn requires java.logging jrt:/java.logging
jdk.scripting.nashorn requires java.scripting jrt:/java.scripting
jdk.scripting.nashorn requires jdk.dynalink jrt:/jdk.dynalink
jdk.internal.vm.compiler.management requires jdk.internal.vm.ci jrt:/jdk.internal.vm.ci
jdk.internal.vm.compiler.management requires jdk.internal.vm.compiler jrt:/jdk.internal.vm.compiler
jdk.internal.vm.compiler.management requires jdk.management jrt:/jdk.management
jdk.internal.vm.compiler.management requires java.management jrt:/java.management
jdk.management requires java.management jrt:/java.management
jdk.management.jfr requires jdk.jfr jrt:/jdk.jfr
jdk.management.jfr requires java.management jrt:/java.management
jdk.management.jfr requires jdk.management jrt:/jdk.management
jdk.management.cmm requires jdk.management jrt:/jdk.management
jdk.management.cmm requires java.management jrt:/java.management
java.management.rmi requires java.management jrt:/java.management
java.management.rmi requires java.naming jrt:/java.naming
java.management.rmi requires java.rmi jrt:/java.rmi
jdk.dynalink requires java.logging jrt:/java.logging
jdk.internal.vm.compiler requires jdk.internal.vm.ci jrt:/jdk.internal.vm.ci
jdk.internal.vm.compiler requires jdk.unsupported jrt:/jdk.unsupported
jdk.internal.vm.compiler requires java.instrument jrt:/java.instrument
jdk.internal.vm.compiler requires jdk.management jrt:/jdk.management
jdk.internal.vm.compiler requires java.management jrt:/java.management
jdk.internal.vm.ci binds jdk.internal.vm.compiler jrt:/jdk.internal.vm.compiler
jdk.dynalink binds jdk.scripting.nashorn jrt:/jdk.scripting.nashorn

模塊路徑
模塊路徑格式支持三種:大目錄下面有多個(gè)模塊的情形,比如上述的out目錄;模塊目錄本身;模塊jar
模塊路徑分隔符,遵循系統(tǒng)的Path.sep;比如mac/Linux下是 : ,windows下是 ;
--module-path 可以簡(jiǎn)寫為 -p 如 java -p

Linking Modules

jlink工具允許你創(chuàng)建一個(gè)運(yùn)行時(shí)鏡像runtime image,包含java應(yīng)用允許所需的最小集合。而不是像之前那樣需要打包整個(gè)jre.

    $JAVA_HOME/bin/jlink --module-path out/:$JAVA_HOME/jmods 
        --add-modules easytext 
        --launcher easy=easytext 
        --output easytext-image

需要注意的是,默認(rèn)情況下jlink沒有被添加到PATH中,需要你手動(dòng)添加一下

跟javac和java命令不同,jlink需要指定jdk平臺(tái)的模塊路徑$JAVA_HOME/jmods
--add-modules 指定easytext為root模塊
--launcher指定啟動(dòng)的入口為easytext模塊,easy是生成的啟動(dòng)文件名
--output 指定生成的鏡像路徑

最終生成的鏡像文件內(nèi)容:

easytext-image/
├── bin/
│   ├── easy
│   ├── java
│   └── keytool
├── conf
│   └── security
│       └── policy
│           ├── limited
│           └── unlimited
├── include
│   └── darwin
├── legal
│   └── java.base
└── lib
    ├── jli
    ├── security
    └── server

試了下,打包成壓縮文件后,只有12M大小:

-rw-r--r--  1 tjw  staff    12M  6 29 13:32 easy.tar.gz
查看已有模塊描述

查看已有模塊描述有兩種方式:
一、直接看module-info.java
二、使用命令 java --describe-module javafx.controls

模塊對(duì)于GUI應(yīng)用的問題:

注意:Jdk11已經(jīng)將javafx從平臺(tái)模塊中移除

module easytext.gui {

   exports javamodularity.easytext.gui to javafx.graphics;

   requires javafx.graphics;
   requires javafx.controls;
   requires easytext.analysis;
}

exports javamodularity.easytext.gui to javafx.graphics;是必須的,因?yàn)間ui應(yīng)用中Application會(huì)反射訪問具體的實(shí)現(xiàn),那么這就意味著javafx.graphics.Application的運(yùn)行時(shí)需要能夠訪問我們的應(yīng)用模塊的Application實(shí)現(xiàn)。

思考一個(gè)問題:如何確保模塊之間的解耦,通過定義一個(gè)接口模塊可以分離實(shí)現(xiàn),但是如何確保自動(dòng)加載哪個(gè)實(shí)現(xiàn)呢?

Services

services的設(shè)計(jì)有點(diǎn)類似于ioc,概念上分為服務(wù)提供者和服務(wù)消費(fèi)者。
主要入口類就是java.util.ServiceLoader,這個(gè)類在jdk6的時(shí)候就已經(jīng)存在,不過在jdk9進(jìn)行了改造以支持模塊化,jdk9之前ServiceLoader主要是用來使jdk更加插件化,一些框架比如dubbo也會(huì)使用ServiceLoader來做插件化工作。 jdk9之前services的提供是在jar包下的META-INF/services目錄下的一個(gè)文本文件,文件名為服務(wù)接口的全限定類名,如:com.test.HelloWorld,文件內(nèi)容也為服務(wù)實(shí)現(xiàn)的全限定類名com.test.HelloWorldImpl。比如dubbo的filter

jdk9改造后使得ServiceLoader支持模塊化service加載,已達(dá)到模塊間面向接口,使實(shí)現(xiàn)解耦的目的。注意:服務(wù)提供模塊可以不用exports服務(wù)實(shí)現(xiàn)。
步驟:
0、服務(wù)接口模塊定義
如模塊easytext.analysis.api
1、提供模塊描述中使用provides

module easytext.analysis.coleman {
   requires easytext.analysis.api;

   provides javamodularity.easytext.analysis.api.Analyzer with javamodularity.easytext.analysis.coleman.Coleman;
}

2、消費(fèi)模塊描述中使用uses

module easytext.cli {
   requires easytext.analysis.api;

   uses javamodularity.easytext.analysis.api.Analyzer;
}

3、消費(fèi)模塊代碼中使用ServiceLoader類加載

      Iterable analyzers = ServiceLoader.load(Analyzer.class); //其實(shí)ServiceLoader.load返回的是一個(gè)ServiceLoader實(shí)例,只不過它實(shí)現(xiàn)了Iterable接口

      for (Analyzer analyzer: analyzers) { 
        System.out.println(analyzer.getName() + ": " + analyzer.analyze(sentences));
      }
Services生命周期

ServiceLoader.load是懶加載的
ServiceLoader.load每調(diào)用一次都會(huì)返回一個(gè)ServiceLoader實(shí)例,獲取的服務(wù)實(shí)例也是新的,跟Spring等容器不同,它不存在單例模式。這就需要注意,千萬不要通過服務(wù)實(shí)例來共享狀態(tài)。
服務(wù)實(shí)現(xiàn)類要么提供無參構(gòu)造器,要么提供public static provider()方法,返回實(shí)例。

public static ExampleProviderMethod provider() {
    return new ExampleProviderMethod("Analyzer created by static method");
}
結(jié)合java8接口靜態(tài)方法實(shí)現(xiàn)service工廠模式:
public interface Analyzer {

   String getName();

   double analyze(List> text);

   static Iterable getAnalyzers() {
     return ServiceLoader.load(Analyzer.class); // <1>
   }

}
module easytext.analysis.api {
   exports javamodularity.easytext.analysis.api;

   uses javamodularity.easytext.analysis.api.Analyzer;
}

好處:ServiceLoader的調(diào)用及模塊uses聲明都統(tǒng)一在api模塊中定義。

Service Type及延遲初始化再談

問題: 上面所述的獲取服務(wù)接口實(shí)現(xiàn)的方式只能遍歷Itreable,而遍歷后所有的實(shí)現(xiàn)都會(huì)被初始化。兩個(gè)問題:1、我只關(guān)心某一個(gè)實(shí)現(xiàn),如何標(biāo)識(shí)獲取;2、我只想獲取某一個(gè)特定實(shí)現(xiàn),但我不想在遍歷中初始化其他實(shí)例;
問題1:我只關(guān)心某一個(gè)實(shí)現(xiàn),如何標(biāo)識(shí)獲取
方案1:在服務(wù)接口中添加標(biāo)識(shí)方法,比如getName,然后消費(fèi)者遍歷時(shí)通過getName的值來判斷。這樣很多場(chǎng)景下是可行的。但是也有些場(chǎng)景需要通過別的方式來標(biāo)識(shí),比如是否實(shí)現(xiàn)某個(gè)抽象類,是否被某個(gè)注解標(biāo)注,這種情況下就需要下面的方案2。
方案2: Java9對(duì)ServiceLoader API進(jìn)行了強(qiáng)化,提供ServiceLoader.Provider stream. ServiceLoader.Provider可以在不實(shí)例化實(shí)現(xiàn)之前對(duì)實(shí)現(xiàn)類進(jìn)行反射檢索。
比如下面的就是通過檢索被@Fast注解標(biāo)注的實(shí)現(xiàn)。

public class Main {
  public static void main(String args[]) {
    ServiceLoader analyzers =
      ServiceLoader.load(Analyzer.class);

    analyzers.stream()
      .filter(provider -> isFast(provider.type()))
      .map(ServiceLoader.Provider::get) 
      .forEach(analyzer -> System.out.println(analyzer.getName()));
  }

  private static boolean isFast(Class clazz) {
    return clazz.isAnnotationPresent(Fast.class)
      && clazz.getAnnotation(Fast.class).value() == true;

  }
}

注意上述代碼中的provider.type(),它返回的是實(shí)現(xiàn)類的Class對(duì)象,這里我們要注意,我們的實(shí)現(xiàn)類是沒有被exports的,但通過provider.type()是可以獲取到。但是我們可以調(diào)用provider.type().newInstance()嗎?不可以,因?yàn)樗匀蛔袷啬K的封裝約定。如果強(qiáng)行調(diào)用會(huì)報(bào)IllegalAccessError異常。

Service Moudle Resolution And Linking

對(duì)于Service,模塊解析方式和之前的相同:從root模塊開始,解析requires,然后解析uses,然后會(huì)把uses對(duì)應(yīng)的provides模塊都解析到resolved module sets中。
**但是對(duì)于jlink鏡像打包而言,它不會(huì)把Service的provides模塊打包進(jìn)去(一個(gè)直接的原因就是java.base中使用了大量的uses),
所以使用jlink打包時(shí)需要注意通過--add-modules添加provides。** 當(dāng)然如果你不知道有哪些provids模塊,可以通過jlink選項(xiàng) --suggest-providers 接口名查看

$JAVA_HOME/bin/jlink --module-path mods/:$JAVA_HOME/jmods --add-modules main--suggest-providers javamodularity.easytext.analysis.api.Analyzer

建議的提供方:
  provider.factory.example provides javamodularity.easytext.analysis.api.Analyzer used by main
  provider.method.example provides javamodularity.easytext.analysis.api.Analyzer used by main

不過如果provide模塊也uses別的模塊,那么也需要照樣分析,并根據(jù)需要--add-modules添加進(jìn)來。

不過還有個(gè)替代方式,添加--bind-services選項(xiàng),添加后jlink會(huì)解析uses及provides,但不推薦使用,因?yàn)閖ava.base也使用了大量uses,會(huì)導(dǎo)致打包后鏡像很大

源碼見書籍源碼:https://github.com/java9-modu...

主要參考書籍:《Java 9 Modularity Patterns and Practices for Developing Maintainable Applications》

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71416.html

相關(guān)文章

  • Java9塊化學(xué)習(xí)筆記三之遷移到Java9

    摘要:命令行參數(shù)文件鑒于遷移到后可能需要很長(zhǎng)的命令行參數(shù),有些會(huì)限制命令行長(zhǎng)度,支持定義一個(gè)命令行參數(shù)文件。已有三分庫可以自動(dòng)轉(zhuǎn)成模塊,只要在啟動(dòng)時(shí)將放在指定路徑中,便會(huì)自動(dòng)變成。 java[c]命令行參數(shù)文件 鑒于遷移到j(luò)ava9后可能需要很長(zhǎng)的命令行參數(shù),有些os會(huì)限制命令行長(zhǎng)度,java9支持定義一個(gè)命令行參數(shù)文件。使用方式: java @arguments.txt arguments...

    NeverSayNever 評(píng)論0 收藏0
  • Java9塊化學(xué)習(xí)筆記二之模塊設(shè)計(jì)模式

    摘要:但是模塊化當(dāng)中,無法掃描只有模塊中可以使用有兩種解決方案定義一個(gè)專門的資源模塊,并使用提供的接口,實(shí)現(xiàn)它,并將這個(gè)實(shí)現(xiàn)注冊(cè)為服務(wù)。有兩種方式使用或包名,包名模塊名使用運(yùn)行時(shí)動(dòng)態(tài)。 模塊設(shè)計(jì)的原則: 1、防止出現(xiàn)編譯時(shí)循環(huán)依賴(主要是編譯器不支持),但運(yùn)行時(shí)是允許循環(huán)依賴的,比如GUI應(yīng)用2、明確模塊的邊界 幾種模塊設(shè)計(jì): API模塊,聚合模塊(比如java.base) 可選依賴 兩種方...

    李文鵬 評(píng)論0 收藏0
  • Python爬蟲學(xué)習(xí)路線

    摘要:以下這些項(xiàng)目,你拿來學(xué)習(xí)學(xué)習(xí)練練手。當(dāng)你每個(gè)步驟都能做到很優(yōu)秀的時(shí)候,你應(yīng)該考慮如何組合這四個(gè)步驟,使你的爬蟲達(dá)到效率最高,也就是所謂的爬蟲策略問題,爬蟲策略學(xué)習(xí)不是一朝一夕的事情,建議多看看一些比較優(yōu)秀的爬蟲的設(shè)計(jì)方案,比如說。 (一)如何學(xué)習(xí)Python 學(xué)習(xí)Python大致可以分為以下幾個(gè)階段: 1.剛上手的時(shí)候肯定是先過一遍Python最基本的知識(shí),比如說:變量、數(shù)據(jù)結(jié)構(gòu)、語法...

    liaoyg8023 評(píng)論0 收藏0
  • Java9特性預(yù)覽Jigsaw:塊化系統(tǒng)快速入門指南

    摘要:例子中的文件路徑使用斜杠,路徑分隔符是冒號(hào)。到目前為止的示例中,已編譯的模塊的內(nèi)容在文件系統(tǒng)上以分散的文件的形式存儲(chǔ)。當(dāng)用于分發(fā)和部署時(shí)通常更方便的方式是將一個(gè)模塊打包成一個(gè)模塊化的。在這個(gè)例子中,模塊打包時(shí)表明了它的版本是。 本文檔提供了幾個(gè)簡(jiǎn)單的例子,讓開發(fā)人員開始使用模塊。 例子中的文件路徑使用斜杠,路徑分隔符是冒號(hào)。使用微軟Windows開發(fā)的人員應(yīng)該使用文件路徑以反斜杠和一個(gè)...

    dack 評(píng)論0 收藏0
  • 零基礎(chǔ)如何學(xué)爬蟲技術(shù)

    摘要:楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),。本文來源知乎作者路人甲鏈接楚江數(shù)據(jù)提供網(wǎng)站數(shù)據(jù)采集和爬蟲軟件定制開發(fā)服務(wù),服務(wù)范圍涵蓋社交網(wǎng)絡(luò)電子商務(wù)分類信息學(xué)術(shù)研究等。 楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),http://www.chujiangdata.com。 第一:Python爬蟲學(xué)習(xí)系列教程(來源于某博主:htt...

    KunMinX 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<