1. 程式人生 > >Android-框架-Dagger2-Dagger2從入門到放棄再到恍然大悟

Android-框架-Dagger2-Dagger2從入門到放棄再到恍然大悟

現在Dagger2在專案裡用的越來越多了,最近花了些時間學習了一下Dagger2,這篇文章主要幫助理解Dagger2的注入實現過程,如有錯誤,還請指正!

什麼是Dagger2

Dagger2是Dagger的升級版,是一個依賴注入框架,現在由Google接手維護。 恩,這裡有個關鍵字依賴注入,因此我們得先知道什麼是依賴注入,才能更好的理解Dagger2。

依賴注入是面向物件程式設計的一種設計模式,其目的是為了降低程式耦合,這個耦合就是類之間的依賴引起的。

舉個例子:我們在寫面向物件程式時,往往會用到組合,即在一個類中引用另一個類,從而可以呼叫引用的類的方法完成某些功能,就像下面這樣.

public class ClassA {
    ...
    ClassB b;
    ...
    public ClassA() {
        b = new ClassB();
    }

    public void do() {
        ...
        b.doSomething();
        ...
    }
}

這個時候就產生了依賴問題,ClassA依賴於ClassB,必須藉助ClassB的方法,才能完成一些功能。這樣看好像並沒有什麼問題,但是我們在ClassA的構造方法裡面直接建立了ClassB的例項,問題就出現在這,在ClassA裡直接建立ClassB例項,違背了單一職責原則,ClassB例項的建立不應由ClassA來完成;其次耦合度增加,擴充套件性差,如果我們想在例項化ClassB的時候傳入引數,那麼不得不改動ClassA的構造方法,不符合開閉原則。

因此我們需要一種注入方式,將依賴注入到宿主類(或者叫目標類)中,從而解決上面所述的問題。依賴注入有一下幾種方式:

通過介面注入

interface ClassBInterface {
      void setB(ClassB b);
  }

public class ClassA implements ClassBInterface {
      ClassB classB;

      @override
      void setB(ClassB b) {
          classB = b;
      }
}

通過set方法注入

public class ClassA {
      ClassB classB;

      public void setClassB(ClassB b) {
          classB = b;
      }
}

通過構造方法注入

public class ClassA {
      ClassB classB;

      public void ClassA(ClassB b) {
          classB = b;
      }
}

通過Java註解

public class ClassA {
      // 此時並不會完成注入,還需要依賴注入框架的支援,如RoboGuice,Dagger2
      @inject ClassB classB;

      ...
      public ClassA() {}
}

在Dagger2中用的就是最後一種注入方式,通過註解的方式,將依賴注入到宿主類中。

如何引入Dagger2

配置apt外掛(在build.gradle(Project:xxx)中新增如下程式碼)

dependencies {
      classpath 'com.android.tools.build:gradle:2.1.0'
      // 新增apt外掛
      classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

}

新增依賴(在build.gradle(Module:app)中新增如下程式碼)

 apply plugin: 'com.android.application'
  // 新增如下程式碼,應用apt外掛
  apply plugin: 'com.neenbedankt.android-apt'
  ...
  dependencies {
      ...
      compile 'com.google.dagger:dagger:2.4'
      apt 'com.google.dagger:dagger-compiler:2.4'
      // java註解
      compile 'org.glassfish:javax.annotation:10.0-b28'
      ...
  }

使用Dagger2

下面用一個栗子來說明,如何使用Dagger2,需要說明的是,這個栗子是基於mvp模式的,所以如果還不瞭解mvp的話,可以先去了解mvp,再繼續看下面的內容。

在mvp中,最常見的一種依賴關係,就是Activity持有presenter的引用,並在Activity中例項化這個presenter,即Activity依賴presenter,presenter又需要依賴View介面,從而更新UI,就像下面這樣:

public class MainActivity extends AppCompatActivity implements MainContract.View {
    private MainPresenter mainPresenter;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 例項化presenter 將view傳遞給presenter
        mainPresenter = new MainPresenter(this);
        // 呼叫Presenter方法載入資料
         mainPresenter.loadData();

         ...
    }
}

public class MainPresenter {
    // MainContract是個介面,View是他的內部介面,這裡看做View介面即可
    private MainContract.View mView;

    MainPresenter(MainContract.View view) {
        mView = view;
    }

    public void loadData() {
        // 呼叫model層方法,載入資料
        ...
        // 回撥方法成功時
        mView.updateUI();
    }
}

這樣Activity與presenter僅僅耦合在了一起,當需要改變presenter的構造方式時,需要修改這裡的程式碼。如果用依賴注入的話,是這樣的:

public class MainActivity extends AppCompatActivity implements MainContract.View {
    @Inject
    MainPresenter mainPresenter;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);
        //呼叫Presenter方法載入資料
         mainPresenter.loadData();

         ...
    }
}

public class MainPresenter {
    //MainContract是個介面,View是他的內部介面,這裡看做View介面即可
    private MainContract.View mView;

    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }    
    public void loadData() {
        //呼叫model層方法,載入資料
        ...
        //回撥方法成功時
        mView.updateUI();
    }
}

@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainView provideMainView() {
        return mView;
    }
}

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

額,貌似變得更復雜了,還不如不用Dagger2呢。不過仔細想想也是可以理解的,直接組合方式雖然簡單,但是具有耦合性,為了解決這種耦合,可能就會多產生一些輔助類,讓這種直接的依賴關係,變為間接,降低耦合。跟大多數設計模式一樣,為了達到高內聚低耦合,往往會有很多介面與類,Daager2也是如此,雖然看似複雜了些,不過這在軟體工程中是值得的。下面,就來分析下上面程式碼是什麼意思。

我們先看MainActivity裡的程式碼,之前是直接宣告MainPresenter,現在在宣告的基礎上加了一個註解@Inject,表明MainPresenter是需要注入到MainActivity中,即MainActivity依賴於MainPresenter,這裡要注意的是,使用@Inject時,不能用private修飾符修飾類的成員屬性。

然後我們在MainPresenter的建構函式上同樣加了@Inject註解。這樣MainActivity裡的mainPresenter與他的建構函式建立了某種聯絡。這種聯絡我們可以這樣理解,當看到某個類被@Inject標記時,就會到他的構造方法中,如果這個構造方法也被@Inject標記的話,就會自動初始化這個類,從而完成依賴注入。

然後,他們之間並不會憑空建立起聯絡,因此我們想到,肯定需要一個橋樑,將他們連線起來,也就是下面要介紹的Component。

Component是一個介面或者抽象類,用@Component註解標註(這裡先不管括號裡的modules),我們在這個介面中定義了一個inject()方法,引數是Mainactivity。然後rebuild一下專案,會生成一個以Dagger為字首的Component類,這裡是DaggerMainComponent,然後在MainActivity裡完成下面程式碼.

DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);

此時Component就將@Inject註解的mainPresenter與其建構函式聯絡了起來。此時,看到這裡,如果是初學者的話,一定會非常迷惑,究竟是怎麼建立起聯絡的,例項化過程在哪?別急,後面會講解這個過程原理的。

此時我們已經完成了presenter的注入過程,但是我們發現還有一個MainModule類,這個類是做什麼的?MainModlue是一個註解類,用@Module註解標註,主要用來提供依賴。等等,剛才通過@Inject就可以完成依賴,為什麼這裡還要用到Module類來提供依賴?之所以有Module類主要是為了提供那些沒有建構函式的類的依賴,這些類無法用@Inject標註,比如第三方類庫,系統類,以及上面示例的View介面。

我們在MainModule類裡聲明瞭MainContract.View成員屬性,在構造方法裡將外界傳進來的view賦值給mView,並通過一個@Provides標註的以provide開頭的方法,將這個view返回,這個以provide開頭的方法就是提供依賴的,我們可以建立多個方法來提供不同的依賴。那麼這個類究竟是怎麼作用的?可以想到上面提到的@Component註解括號裡的東西了。就是下面這個

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

所以Module要發揮作用,還是要依靠於Component類,一個Component類可以包含多個Module類,用來提供依賴。我們接著看下面這段程式碼:

DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);

這裡通過new MainModule(this)將view傳遞到MainModule裡,然後MainModule裡的provideMainView()方法返回這個View,當去例項化MainPresenter時,發現建構函式有個引數,此時會在Module裡查詢提供這個依賴的方法,將該View傳遞進去,這樣就完成了presenter裡View的注入。

我們來重新理一遍上面的注入過程,首先弄清楚以下幾個概念:

@Inject 帶有此註解的屬性或構造方法將參與到依賴注入中,Dagger2會例項化有此註解的類

@Module 帶有此註解的類,用來提供依賴,裡面定義一些用@Provides註解的以provide開頭的方法,這些方法就是所提供的依賴,Dagger2會在該類中尋找例項化某個類所需要的依賴。

@Component 用來將@Inject和@Module聯絡起來的橋樑,從@Module中獲取依賴並將依賴注入給@Inject

接著我們重新回顧一下上面的注入過程:首先MainActivity需要依賴MainPresenter,因此,我們在裡面用@Inject對MainPresenter進行標註,表明這是要注入的類。然後,我們對MainPresenter的建構函式也添加註解@Inject,此時建構函式裡有一個引數MainContract.View,因為MainPresenter需要依賴MainContract.View,所以我們定義了一個類,叫做MainModule,提供一個方法provideMainView,用來提供這個依賴,這個MainView是通過MainModule的建構函式注入進來的,接著我們需要定義Component介面類,並將Module包含進來,即

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

同時裡面聲明瞭一個inject方法,方法引數為ManActivity,用來獲取MainActivity例項,以初始化在裡面宣告的MainPresenter

DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);

此時,注入過程就完成了,或許到此時,還是會有一些疑惑,因為我們看不到例項化的過程在哪裡,為什麼要這樣去寫程式碼,所以下面,就基於這個例項,分析Dagger2內部究竟做了什麼。

Dagger2注入原理

Dagger2與其他依賴注入框架不同,它是通過apt外掛在編譯階段生成相應的注入程式碼,下面我們就具體看看Dagger2生成了哪些注入程式碼?

我們先看MainPresenter這個類,在這個類中我們對構造方法用了@Inject標註,然後Rebuild Project,Dagger2會在/app/build/generated/apt/debug/目錄下生成一個對應的工廠類MainPresenter_Factory,我們看下面具體程式碼(為了方便理解,我把MainPresenter也貼了出來)

public class MainPresenter {
    MainContract.View mView;
    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }
 }


public final class MainPresenter_Factory implements Factory<MainPresenter> {
  private final Provider<MainContract.View> viewProvider;

  public MainPresenter_Factory(Provider<MainContract.View> viewProvider) {
    assert viewProvider != null;
    this.viewProvider = viewProvider;
  }

  @Override
  public MainPresenter get() {
    return new MainPresenter(viewProvider.get());
  }

  public static Factory<MainPresenter> create(Provider<MainContract.View> viewProvider) {
    return new MainPresenter_Factory(viewProvider);
  }
}
對比MainPresenter,我們發現在MainPre_Factory裡也生成了對應的程式碼。首先是viewProvide,這是一個Provider型別,泛型引數就是我們的MainContract.View,接著通過構造方法,對viewProvider進行例項化。其實這裡有個疑惑,上面的成員屬性為什麼不直接是MainContract.View,而是Provider型別?看到provider我們應該想到這個MainContract.View是一個依賴,而依賴的提供者是MainModule,因此這個viewProvider一定是由MainModul提供的。我們接著看下面的get()方法,看到這個方法,我想我們有點恍然大悟的感覺,原來MainPresenter的例項化就在這裡,建構函式裡的引數就是我們依賴的MainContract.View,它是由viewProvider通過get()提供。接著是一個create()方法,並且有一個引數viewProvider,用來建立這個MainPresenter_Factory類。

上面我們得出,viewProvider是由MainModule提供的,所以我們接著看MainModule所對應的注入類。

@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainContract.View provideMainView() {
        return mView;
   }   
}


public final class MainModule_ProvideMainViewFactory implements Factory<MainContract.View> {
  private final MainModule module;

  public MainModule_ProvideMainViewFactory(MainModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public MainContract.View get() {
    return Preconditions.checkNotNull(
        module.provideMainView(), "Cannot return null from a [email protected] @Provides method");
  }

  public static Factory<MainContract.View> create(MainModule module) {
    return new MainModule_ProvideMainViewFactory(module);
  }
}
看到上面的類名,我們發現了一種對應關係,在MainModule中定義的@Provides修飾的方法會對應的生成一個工廠類,這裡是MainModule_ProvideMainViewFactory。我們看到這個類裡有一個get()方法,其中呼叫了MainModule裡的provideMainView()方法來返回我們所需要的依賴MainContract.View。還記得在MainPresenter_Factory裡的get()方法中,例項化MainPresenter時候的引數viewProvider.get()嗎?到這裡我們就明白了,原來那個viewProvider就是生成的MainModule_ProvideMainViewFactory,然後呼叫了其get()方法,將我們需要的MainContract.View注入到MainPresenter裡。

看到這裡我們應該明白了MainPresenter的例項化過程。MainPresenter會對應的有一個工廠類,在這個類的get()方法中進行MainPresenter建立,而MainPresenter所需要的View依賴,是由MainModule裡定義的以provide開頭的方法所對應的工廠類提供的。

雖然我們明白了例項化的建立過程,但是此時還是有點疑惑,MainPresenter_Factory的建立是由create()完成的,那麼crate是在哪呼叫的,此時建立的MainPresenter例項是怎麼跟@Inject註解的MainPresenter關聯起來的,我想你已經知道了答案,沒錯就是Component。前面說過Component是連線@Module和@Inject的橋樑,所以上面的疑惑就要到編譯後Component所對應的類中尋找答案。

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

public final class DaggerMainComponent implements MainComponent {
  private Provider<MainContract.View> provideMainViewProvider;

  private Provider<MainPresenter> mainPresenterProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

  private DaggerMainComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);

    this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
  }

  @Override
  public void inject(MainActivity activity) {
    mainActivityMembersInjector.injectMembers(activity);
  }

  public static final class Builder {
    private MainModule mainModule;

    private Builder() {}

    public MainComponent build() {
      if (mainModule == null) {
        throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainComponent(this);
    }

    public Builder mainModule(MainModule mainModule) {
      this.mainModule = Preconditions.checkNotNull(mainModule);
      return this;
    }
  }
}
從上面程式碼看到定義的MainComponent會生成一個對應的DaggerMainComponent,並且實現了MainComponent裡的方法。我們看到程式碼中又出現了Provide型別的成員屬性,前面說過這個Provide型別就是所提供的依賴,我們在看它們是在哪例項化的。我們看到有一個initialize()方法
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {

    this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);

    this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
}
看到這估計就明白了剛才的疑惑。首先建立了MainModule_ProvideMainViewFactory例項,用來提供MainContract.View依賴。這裡可能有個小疑惑,create()方法返回的是Factory型別,而provideMainViewProvider是個Provider型別,其實看原始碼就明白了,Factory繼承自Provider。
public interface Factory<T> extends Provider<T> {
}

然後將provideMainViewProvider傳遞到MainPresenter_Factory裡,即就是前面講到的viewProvider。接著將這個mainPresenterProvider又傳遞到MainActivity_MembersInjector中進行例項化,我們看到這個類前面是MainActivity開頭,因此可以想到是MainActivity對應得注入類,我們後面再分析這個類。

接著是我們在MainComponent裡定義的Inject方法的實現,這裡呼叫了mainActivityMembersInjector.injectMembers(activity)方法,將我們的MainActivity注入到該類中。

接著就是Builder內部類,用來建立我們的module以及自身例項。所以在DaggerMainComponent裡主要用來初始化依賴,而真正的將這些依賴於Inject關聯起來的就是剛才的MainActivity_MembersInjector類,我們看看這個類裡做了什麼。

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<MainPresenter> mainPresenterProvider;

  public MainActivity_MembersInjector(Provider<MainPresenter> mainPresenterProvider) {
    assert mainPresenterProvider != null;
    this.mainPresenterProvider = mainPresenterProvider;
  }

  public static MembersInjector<MainActivity> create(
      Provider<MainPresenter> mainPresenterProvider) {
    return new MainActivity_MembersInjector(mainPresenterProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mainPresenter = mainPresenterProvider.get();
  }

  public static void injectMainPresenter(
      MainActivity instance, Provider<MainPresenter> mainPresenterProvider) {
    instance.mainPresenter = mainPresenterProvider.get();
  }
}
這個類的關鍵就是injectMembers()方法,還記得這個方法在哪呼叫嗎?我想你肯定記得,就在剛才提到的DaggerMainComponent類中的inject()方法裡,所以這裡的instance例項是由DaggerMainComponent提供的,然後我們看到了最關鍵的一句程式碼
instance.mainPresenter = mainPresenterProvider.get();

看到這,我想應該一切都明白了,將mainPresenterProvider中建立好的MainPresenter例項賦值給instance(MainActivity)的成員mainPresenter,這樣我們用@Inject標註的mainPresenter就得到了例項化,接著就可以在程式碼中使用了。

到這裡,就分析完了Dagger2的注入過程,如果不去看這些生成的類,就很難理解整個過程究竟是怎麼發生的,從而導致還是不知道怎麼去使用這個依賴注入框架。所以重點去理解這個內部實現原理是非常重要的,剛開始學的時候也是一臉懵逼,總搞不太清之間的關係,不知道究竟怎麼寫,弄懂了整個來龍去脈後,發現就知道怎麼去運用了。

關於Dagger2的其他使用就不多講了,可以看其他的優秀部落格,我會再後面附上鍊接,方便學習。Dagger2就是一個依賴注入工具,至於怎麼使用完全在個人,所以不必糾結到底怎麼去寫才是正確的,只要弄懂原理,靈活運用,能夠做到儘可能解耦,適合自己的業務就是最好的寫法。

感謝:

作者:littleKang

連結:http://www.jianshu.com/p/39d1df6c877d

來源:簡書

著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關推薦

Android外掛化:入門放棄

 本文根據包建強在2016GMTC全球移動開發大會上的演講整理而成。 首先自我介紹一下,我叫包建強,是這個分場的主持人。我去年寫了一本書,叫《App研發錄》,相信有很多從事技術的朋友看過或買過。 引言 先簡單介紹一下Android外掛化。很早之前已經有公司在研究這

【轉】Android外掛化:入門放棄

本文根據包建強在2016GMTC全球移動開發大會上的演講整理而成。 首先自我介紹一下,我叫包建強,是這個分場的主持人。我去年寫了一本書,叫《App研發錄》,相信有很多從事技術的朋友看過或買過。 引言 先簡單介紹一下Android外掛化。很早之前已經有公司在研究這項技

[Android-ARCore開發]ARCore入門放棄2-Demo介紹和擴充套件

昨天只是簡單運行了官方的Demo,今天抽時間看了下文件和程式碼,大概瞭解一下原理。Demo功能很簡單,開啟之後自動檢測平面,手指觸控平面會在觸控位置放置一個機器人。檢測平面成功後如下面截圖所示,可以看到

Android進階——MVP入門到進階

1.定義 MVP的全稱為Model-View-Presenter,即模型-檢視-協調器(主持者) Model:處理資料和業務邏輯等,如:資料庫的操作,資料的請求,資料運算,JavaBean; View:顯示介面,展示結果等,一切與介面相關的,如:XML檔案,Activity,Fragment,D

萬物皆可聯網——《Android物聯網開發入門到實戰》

    最近國內挺流行“抵制iPhone”的么蛾子,我都忍不住想說“國產手機”小米的硬體是Qualcomm的,軟體系統是Android的,只是在國內組裝罷了。     Qualcomm是世界分佈最廣

Android studio NDK開發 入門到實踐二

這一節開始將,怎麼將公司扔給你的c程式碼封裝成android的so庫呢. 1.給自己的c程式碼新增log c程式碼中的log,在ndk開發中,他是不能直接列印到我們android studio中. https://www.cnblogs.com/0616--ataozhij

Java程式設計師必備後臺前端框架--Layui【入門到實戰】(一)

layui入門使用及圖示、按鈕的使用 作者 : Stanley 羅昊 【轉載請註明出處和署名,謝謝!】 【程式設計工具:IDEA】 下載Layui與檔案分析 下載直接去官網下載即可 檔案分析 下載完成後,解壓會得到一個資料夾,內部有一些檔案是可以直接刪除的,比如文件與示例,更新日誌之類的,我們僅僅只要上面那

Java程式設計師必備後臺前端框架--Layui【入門到實戰】(二)

layui使用 導航選單、選項卡 作者 : Stanley 羅昊 【轉載請註明出處和署名,謝謝!】 【程式設計工具:IDEA】 導航選單 在layui官網中示例中,我們可以找到關於導航的例子:  我們點選檢視程式碼,將其程式碼複製到自己的編輯器上; 1 <fieldset class="

Android-框架-Dagger2-Dagger2入門放棄恍然大悟

現在Dagger2在專案裡用的越來越多了,最近花了些時間學習了一下Dagger2,這篇文章主要幫助理解Dagger2的注入實現過程,如有錯誤,還請指正! 什麼是Dagger2 Dagger2是Dagger的升級版,是一個依賴注入框架,現在由Google接手維護。 恩

Python爬蟲入門放棄(十一)之 Scrapy框架整體的一個了解

object 定義 roc encoding eth obi pipe pos 等等 這裏是通過爬取伯樂在線的全部文章為例子,讓自己先對scrapy進行一個整理的理解 該例子中的詳細代碼會放到我的github地址:https://github.com/pythonsite/

Python爬蟲入門放棄(十三)之 Scrapy框架的命令行詳解

directory xpath idf 成了 spider i386 名稱 4.2 不同的 這篇文章主要是對的scrapy命令行使用的一個介紹 創建爬蟲項目 scrapy startproject 項目名例子如下: localhost:spider zhaofan$ sc

Python爬蟲入門放棄 之 Scrapy框架中Download Middleware用法

sta 頻繁 space raw 處理 們的 img ear 法則 這篇文章中寫了常用的下載中間件的用法和例子。Downloader Middleware處理的過程主要在調度器發送requests請求的時候以及網頁將response結果返回給spiders的時候,所以從

scrapy框架爬蟲爬取糗事百科 之 Python爬蟲入門放棄第不知道多少天(1)

Scrapy框架安裝及使用 1. windows 10 下安裝 Scrapy 框架:   前提:安裝了python-pip    1. windows下按住win+R 輸入cmd   2. 在cmd 下 輸入       pip install scrapy       pip inst

CYQ.Data 入門放棄ORM系列:開篇:自動化框架程式設計思維

前言: 隨著CYQ.Data 開始迴歸免費使用之後,發現使用者的情緒越來越激動,為了保持這持續的激動性,讓我有了開源的念頭。 同時,由於框架經過這5-6年來的不斷演進,以前發的早期教程已經太落後了,包括使用方式,及相關介紹,都容易引人誤解。 為此,我打算重新寫個系列來介紹最新的版本,讓大夥從傳統的ORM

周威學Go入門放棄第十四篇(beego框架入門篇)

下載框架包(本人mac)  go get github.com/astaxie/beego package main import ( "errors" "fmt" "github.com/astaxie/beego/orm" _ "github.com/go

支援向量機(SVM)入門放棄到掌握

前言 朋友,你通過各種不同的途經初次接觸支援向量機(SVM)的時候,是不是會覺得這個東西耳熟能詳,感覺大家都會,卻唯獨自己很難理解? 每一次你的老闆或者同仁讓你講解SVM的時候,你覺得你看過這麼多資料,使用過這麼多次,講解應該沒有問題,但偏偏在分享的時候結結巴巴,漏洞百出? 每一

Java入門放棄(十四)集合框架之TreeMap原始碼

我們經常需要對一些集合按照指定的規則進行排序,比如學生按照學號排序,或者按照成績排序,集合裡面有專門排序的集合,如TreeMap。TreeMap裡面是使用的紅黑樹結構。 構造方法 private final Comparator<? su

TP3.2.3入門放棄-TP框架的使用

一、Thinkphp框架的使用-引用框架注意:框架的公共入口檔案ThinkPHP.php是不能直接執行的,該檔案只能在專案入口檔案中呼叫那個才能正常執行。 1、我們新手要做的就是新建一個寫一個php

Android開發入門放棄(8)使用ListView顯示一個簡單的列表

本篇部落格簡單介紹一下Android開發中ListView的使用,並顯示一個簡單列表,點選列表中的某一項時,會顯示出該項的名稱。在Android中,顯示一個列表是比較容易的,我總結了下,只需三步 一個待顯示的資料列表,可以是簡單型別,也可以是自定義型別, 一

PHP入門到接到外包合同,放棄

        15年7月,我自學兩個月PHP後進入鳥窩(公司),接受作為程式設計師的第一份工作。那時候真是一頭純純的菜鳥,我甚至連ls命令都不知道。         我的第一個專案是為一個正在執行的網站,寫一套相應的介面, 供App前端呼叫。專案很小,程式碼量也小,現在看來是很簡單的工作。而當時我在閱讀原始