1. 程式人生 > >關於 Container ,Injection

關於 Container ,Injection

細粒度 jai 浪費 com -c cal name 創建 集中式

1.容器的歷史

容器概念始於 1979 年提出的 UNIX chroot,它是一個 UNIX 操作系統的系統調用,將一個進程及其子進程的根目錄改變到文件系統中的一個新位置,讓這些進程只能訪問到這個新的位置,從而達到了進程隔離的目的。

2000 年的時候 FreeBSD 開發了一個類似於 chroot 的容器技術 Jails,這是最早期,也是功能最多的容器技術。Jails 英譯過來是監獄的意思,這個“監獄”(用沙盒更為準確)包含了文件系統、用戶、網絡、進程等的隔離。

2001 Linux 也發布自己的容器技術 Linux VServer,2004 Solaris 也發布了 Solaris Containers,兩者都將資源進行劃分,形成一個個 zones,又叫做虛擬服務器。

2005 年推出 OpenVZ,它通過對 Linux 內核進行補丁來提供虛擬化的支持,每個 OpenVZ 容器完整支持了文件系統、用戶及用戶組、進程、網絡、設備和 IPC 對象的隔離。

2007 年 Google 實現了 Control Groups( cgroups ),並加入到 Linux 內核中,這是劃時代的,為後期容器的資源配額提供了技術保障。

2008 年基於 cgroups 和 linux namespace 推出了第一個最為完善的 Linux 容器 LXC。

2013 年推出到現在為止最為流行和使用最廣泛的容器 Docker,相比其他早期的容器技術,Docker 引入了一整套容器管理的生態系統,包括分層的鏡像模型,容器註冊庫,友好的 Rest API。

2014 年 CoreOS 也推出了一個類似於 Docker 的容器 Rocket,CoreOS 一個更加輕量級的 Linux 操作系統,在安全性上比 Docker 更嚴格。

2016 年微軟也在 Windows 上提供了容器的支持,Docker 可以以原生方式運行在 Windows 上,而不是需要使用 Linux 虛擬機。

基本上到這個時間節點,容器技術就已經很成熟了,再往後就是容器雲的發展,由此也衍生出多種容器雲的平臺管理技術,其中以 kubernetes 最為出眾,有了這樣一些細粒度的容器集群管理技術,也為微服務的發展奠定了基石。因此,對於未來來說,應用的微服務化是一個較大的趨勢。

為什麽需要容器

其一,這是技術演進的一種創新結果,其二,這是人們追求高效生產活動的一種工具。

隨著軟件開發的發展,相比於早期的集中式應用部署方式,現在的應用基本都是采用分布式的部署方式,一個應用可能包含多種服務或多個模塊,因此多種服務可能部署在多種環境中,如虛擬服務器、公有雲、私有雲等,由於多種服務之間存在一些依賴關系,所以可能存在應用在運行過程中的動態遷移問題,那這時如何保證不同服務在不同環境中都能平滑的適配,不需要根據環境的不同而去進行相應的定制,就顯得尤為重要。

就像貨物的運輸問題一樣,如何將不同的貨物放在不同的運輸機器上,減少因貨物的不同而頻繁進行貨物的裝載和卸載,浪費大量的人力物力。

為此人們發明了集裝箱,將貨物根據尺寸形狀等的不同,用不同規格的集裝箱裝載,然後再放到運輸機上運輸,由於集裝箱密封,只有貨物到達目的地才需拆封,在運輸過程能夠再不同運輸機上平滑過渡,所以避免了資源的浪費。

Injection

javava EE CDI主要使用@Inject批註,以便將托管bean的依賴註入執行到其他容器托管資源。

構造函數依賴註入

構造函數依賴註入
公共類SomeBean {
  
  私人最終服務;

  @註入
  public SomeBean(服務服務){
    this.service = service;
  }

}

當CDI容器實例化SomeBean類型的bean時,它將查找默認(無參數)構造函數並使用它來創建bean實例。這個規則的例外是當我們有另一個用@Inject註釋的構造函數時如果是這種情況,容器將使用帶註釋的構造函數,並將註入作為構造函數參數傳遞的依賴項。

在上面的示例中,它將獲取一個Service實例並註入SomeBean帶註釋的構造函數。

註意:請記住,它可能只存在一個單一的與@Inject註釋構造函數

場依賴註入

場依賴註入
公共類SomeBean {
  
  @註入
  私人服務;

}

在這種情況下,當容器初始化類型為SomeBean的bean時,它會將正確的Service bean註入到字段中,即使它是私有的,也不需要任何setter方法。

Initializer方法依賴註入

Initializer方法依賴註入
公共類SomeBean {
  
  私人服務;
  
  @註入
  public void setService(服務服務){
    this.service = service;
  }

}

在這種情況下,當容器初始化SomeBean類型的bean時,它將調用所有使用@Inject註釋的方法,並將依賴項註入方法參數。

@Any資格賽

為了提供完全松散耦合的應用程序,我們通常將接口註入托管資源。如果我們為給定的接口提供多個bean實現怎麽辦?我們可以使用@Any限定符以及CDI 實例接口將它們全部註入到托管bean中

@Any資格賽
公共類SomeBean {
  
  @註入
  public void listServiceImplementations
      @Any Instance <Service> serviceList){

    for(服務服務:serviceList){
      System.out.printlnservice.getClass()另一方面,getCanonicalName());
    }

  }
}

@Any預選賽指示,該註射點可以通過任何可用的依賴性得到滿足的容器,因此容器註入他們。如果我們有多個接口實現並且我們只註入一個 - 沒有任何消除歧義 - 容器會抱怨並且無法初始化組件。我們將在其他教程中看到依賴消歧。

註入生產者方法

生產者方法參數也可以由CDI容器註入。請參閱Java EE CDI Producer方法教程

CDI代理

本教程將不完整,我們也沒有涵蓋CDI代理機制。當我們註入被以不同於一個範圍內創建一個托管bean @Dependent -到另一個托管的資源- CDI容器也沒有註入直接引用註入豆。

對於CDI bean範圍,請參閱Java EE CDI bean範圍

為什麽CDI使用代理?因為如果註入直接bean引用,就會產生線程安全或對托管bean的並發訪問等問題。

想象一下,會話範圍的bean被註入到應用程序範圍的bean中。由於應用程序作用域bean在所有客戶端之間共享,如果多個客戶端同時訪問應用程序作用域bean,則存在一個客戶端訪問另一個客戶端直接引用的會話作用域bean的高風險。

要解決此問題,CDI會創建代理並將代理註入註入點。然後,代理將處理對註入的bean的調用,並將調用轉發給正確的bean實例。

CDI創建的代理擴展了註入bean的類。想象一下以下場景:

應用程序和會話範圍的bean
@SessionScoped
公共課堂服務{

  public void doWork(){
    System.out.println “工作......”);
  }

}


@ApplicationScoped
公共類SomeBean {
  
  @註入
  私人服務;
  
  public void test(){
    service.doWork();
  }

}

CDI會將會話作用域bean的代理註入到應用程序作用域bean中。對會話範圍bean的每次調用都將通過代理,代理又將調用重定向到正確的會話bean實例:屬於當前HTTP請求會話的實例。

CDI通過擴展bean類並覆蓋所有非私有方法來創建代理。代理的代表性說明可能如下:

說明性的CDI代理
公共類服務$ Proxy $ _ $$ _ WeldClientProxy
  擴展服務{

  @覆蓋
  public void doWork(){
    Service instance = // ...解析bean實例
    instance.doWork();
  }

}

關於 Container ,Injection