022.掌握Pod-Pod升級和回滾

一 deploymentPod升級和回滾

1.1 deployment升級


若Pod是通過Deployment創建的,可以在運行時修改Deployment的Pod定義(spec.template)或鏡像名稱,並應用到Deployment對象上,系統即可完成Deployment的自動更新操作。 如果在更新過程中發生了錯誤, 則還可以通過回滾操作恢復Pod的版本。

示例:

  1 [root@uk8s-m-01 study]# vi nginx-deployment.yaml
  2 apiVersion: apps/v1beta1
  3 kind: Deployment
  4 metadata:
  5   name: nginx-deployment
  6 spec:
  7   replicas: 3
  8   template:
  9     metadata:
 10       labels:
 11         app: nginx
 12     spec:
 13       containers:
 14       - name: nginx
 15         image: nginx:1.7.9
 16         ports:
 17         - containerPort: 80
 18 
 19 [root@uk8s-m-01 study]# kubectl create -f nginx-deployment.yaml
 20 [root@uk8s-m-01 study]# kubectl get pods



  1 [root@uk8s-m-01 study]# kubectl get deployment			#查看deployment
  2 [root@uk8s-m-01 study]# kubectl set image deployment/nginx-deployment nginx=nginx:1.8.1	#命令更新
  3 [root@uk8s-m-01 study]# kubectl get pods			        #查看升級后的pod



  1 [root@uk8s-m-01 study]# kubectl edit deployment/nginx-deployment			#直接編輯deployment


  1 [root@uk8s-m-01 study]# kubectl rollout status deployment/nginx-deployment		#查看升級情況


  1 [root@uk8s-m-01 study]# kubectl get pods
  2 [root@uk8s-m-01 study]# kubectl describe pod nginx-deployment-7448597cd5-8sng2 | grep Image



1.2 deployment升級原理

  1 [root@uk8s-m-01 study]# kubectl describe deployments/nginx-deployment		#觀察Deployment的更新過程




初始創建Deployment時,系統創建了一個ReplicaSet(nginx-deployment-5754944d6c),並按用戶的需求創建了3個Pod副本。

當更新Deployment時,系統創建了一個新的ReplicaSet(nginx-deployment-b5f766d54),並將其副本數量擴展到1,然後將舊ReplicaSet縮減為2。

之後,系統繼續按照相同的更新策略對新舊兩個ReplicaSet進行逐個調整。

最後,新的ReplicaSet運行了3個新版本Pod副本,舊的ReplicaSet副本數量則縮減為0。


  1 [root@uk8s-m-01 study]# kubectl get rs			#查看多次升級的結果



注意:在整個升級的過程中,系統會保證至少有兩個Pod可用,並且最多同時運行4個Pod,這是Deployment通過複雜的算法完成的。Deployment需要確保在整個更新過程中只有一定數量的Pod可能處於不可用狀態。在默認情況下,Deployment確保可用的Pod總數至少為所需的副本數量(DESIRED)減1,也就是最多1個不可用(maxUnavailable=1)。

1.3 deployment升級策略


在Deployment的定義中,可以通過spec.strategy指定Pod更新的策略,目前支持兩種策略:Recreate(重建)和RollingUpdate(滾動更新),默認值為RollingUpdate。

  • Recreate:設置spec.strategy.type=Recreate,表示Deployment在更新Pod時,會先殺掉所有正在運行的Pod,然後創建新的Pod。
  • RollingUpdate:設置spec.strategy.type=RollingUpdate,表示Deployment會以滾動更新的方式來逐個更新Pod。同時,可以通過設置spec.strategy.rollingUpdate下的兩個參數(maxUnavailable和maxSurge)來控制滾動更新的過程。


    • spec.strategy.rollingUpdate.maxUnavailable:用於指定Deployment在更新過程中不可用狀態的Pod數量的上限。 該maxUnavailable的數值可以是絕對值(例如5)或Pod期望的副本數的百分比(例如10%),如果被設置為百分比,那麼系統會先以向下取整的方式計算出絕對值(整數)。而當另一個參數maxSurge被設置為0時,maxUnavailable則必須被設置為絕對數值大於0。舉例來說,當maxUnavailable被設置為30%時,舊的ReplicaSet可以在滾動更新開始時立即將副本數縮小到所需副本總數的70%。一旦新的Pod創建並準備好,舊的ReplicaSet會進一步縮容,新的ReplicaSet又繼續擴容。整個過程中系統在任意時刻都可以確保可用狀態的Pod總數至少佔Pod期望副本總數的70%。
    • spec.strategy.rollingUpdate.maxSurge:用於指定在Deployment更新Pod的過程中Pod總數超過Pod期望副本數部分的最大值。該maxSurge的數值可以是絕對值(例如5)或Pod期望副本數的百分比(例

  • 如10%)。如果設置為百分比,那麼系統會先按照向上取整的方式計算出絕對數值(整數)。舉例來說,當maxSurge的值被設置為30%時,新的ReplicaSet可以在滾動更新開始時立即進行副本數擴容,只需要保證新舊ReplicaSet的Pod副本數之和不超過期望副本數的130%即可。一旦舊的Pod被殺掉,新的ReplicaSet就會進一步擴容。在整個過程中系統在任意時刻都能確保新舊ReplicaSet的Pod副本總數之和不超過所需副本數的130%。

1.4 deployment回滾


默認情況下,所有Deployment的發布歷史記錄都被保留在系統中,以便於我們隨時進行回滾(可以配置歷史記錄數量)。

  1 [root@uk8s-m-01 study]# kubectl rollout history deployment/nginx-deployment	#查看部署歷史
  2 [root@uk8s-m-01 study]# kubectl rollout history deployment/nginx-deployment  --revision=3	#查看對應的部署歷史版本
  3 [root@uk8s-m-01 study]# kubectl rollout history deployment/nginx-deployment  --revision=2	#查看對應的部署歷史版本




提示:Deployment的更新操作是在Deployment進行部署(Rollout)時被觸發的,即當且僅當Deployment的Pod模板(即spec.template)被更改時才會創建新的修訂版本,例如更新模板標籤或容器鏡像。其他更新操作(如擴展副本數)將不會觸發Deployment的更新操作,因此將Deployment回滾到之前的版本時,只有Deployment的Pod模板部分會被修改。

  1 [root@uk8s-m-01 study]# kubectl rollout undo deployment/nginx-deployment --to-revision=2	#回滾版本
  2 [root@uk8s-m-01 study]# kubectl describe deployment/nginx-deployment


1.5 暫停和恢復deployment


對於一次複雜的Deployment配置修改,為了避免頻繁觸發Deployment的更新操作,可以先暫停Deployment的更新操作,然後進行

配置修改,再恢復Deployment,一次性觸發完整的更新操作,從而避免不必要的Deployment更新操作了。

  1 [root@uk8s-m-01 study]# kubectl get deployments				#查看deployment
  2 [root@uk8s-m-01 study]# kubectl get rs					#查看rs
  3 [root@uk8s-m-01 study]# kubectl rollout pause deployment/nginx-deployment	#暫停deployment
  4 [root@uk8s-m-01 study]# kubectl set image deployment/nginx-deployment nginx=nginx:1.10.3	#升級操作,但由於暫停deployment,因此不會觸發更新
  5 [root@uk8s-m-01 study]# kubectl rollout history deployment/nginx-deployment	#查看歷史版本
  6 [root@uk8s-m-01 study]# kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
  7 [root@uk8s-m-01 study]# kubectl rollout resume deployment/nginx-deployment	#恢復deployment
  8 [root@uk8s-m-01 study]# kubectl get rs
  9 NAME                          DESIRED   CURRENT   READY   AGE
 10 nginx-deployment-7448597cd5   0         0         0       52m
 11 nginx-deployment-84bc94dcb7   1         1         0       6s
 12 nginx-deployment-b5f766d54    3         3         3       55m




  1 [root@uk8s-m-01 study]# kubectl describe deployment/nginx-deployment
  2 [root@uk8s-m-01 study]# kubectl describe pods nginx-deployment-84bc94dcb7-hqxkk | grep Image
  3     Image:          nginx:1.10.3


二 RC升級和回滾

2.1 RC滾動升級


, Kubernetes提供了kubectl rolling-update命令進行對於RC的滾動升級。該命令創建了一個新的RC,然後自動控制舊的RC中的Pod副本數量逐漸減少到0,同時新的RC中的Pod副本數量從0逐步增加到目標值,來完成Pod的升級。

注意:該方式要求新的RC與舊的RC都在相同的命名空間內。

示例:

  1 [root@uk8s-m-01 study]# vi redis-master-controller-v1.yaml
  2 apiVersion: v1
  3 kind: ReplicationController
  4 metadata:
  5   name: redis-master-v1
  6   labels:
  7     name: redis-master
  8 spec:
  9   replicas: 1
 10   selector:
 11     name: redis-master
 12   template:
 13     metadata:
 14       labels:
 15         name: redis-master
 16     spec:
 17       containers:
 18       - name: master
 19         image: kubeguide/redis-master:1.0
 20         ports:
 21         - containerPort: 6379
 22 
 23 [root@uk8s-m-01 study]# kubectl create -f redis-master-controller-v1.yaml


  1 [root@uk8s-m-01 study]# vi redis-master-controller-v2.yaml		#RC升級配置文件
  2 apiVersion: v1
  3 kind: ReplicationController
  4 metadata:
  5   name: redis-master-v2
  6   labels:
  7     name: redis-master
  8     version: v2
  9 spec:
 10   replicas: 1
 11   selector:
 12     name: redis-master
 13     version: v2
 14   template:
 15     metadata:
 16       labels:
 17         name: redis-master
 18         version: v2
 19     spec:
 20       containers:
 21       - name: master
 22         image: kubeguide/redis-master:2.0
 23         ports:
 24         - containerPort: 6379



注意:使用此方式升級的時候需要注意以下兩點:

  1. RC的名字(name) 不能與舊RC的名字相同。
  2. 在selector中應至少有一個Label與舊RC的Label不同, 以標識其為新RC。如上所示新增了一個名為version的Label,以與舊RC進行區分。

  1 [root@uk8s-m-01 study]# kubectl rolling-update redis-master-v1 -f redis-master-controller-v2.yaml
  2 [root@uk8s-m-01 study]# kubectl rolling-update redis-master-v1 --image=kubeguide/redis-master:2.0	#也可直接命令中升級



kubectl通過新建一個新版本Pod, 停掉一箇舊版本Pod,如此逐步迭代來完成整個RC的更新。

2.2 RC回滾

  1 [root@uk8s-m-01 study]# kubectl rolling-update redis-master-v1 --rollback


提示:RC的滾動升級不具有Deployment在應用版本升級過程中的歷史記錄、新舊版本數量的精細控制等功能,RC將逐漸被RS和Deployment所取代,建議用戶優先考慮使用Deployment完成Pod的部署和升級操作。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

中國:科技部2017年對新能源汽車部署38個重點研究任務

近日,中國科技部發佈關於對國家重點研發計畫高新領域重點專項2017年度專案申報指南建議徵求意見的通知。新能源汽車專項的總體目標是,繼續深化實施新能源汽車「純電驅動」技術轉型戰略;升級新能源汽車動力系統技術平臺;抓住新能源、新材料、資訊化等科技帶來的新能源汽車新一輪技術變革機遇,超前部署研發下一代技術;到2020年,建立起完善的新能源汽車科技創新體系,支撐大規模產業化發展。  
  新能源汽車試點專項按照動力電池與電池管理系統、電機驅動與電力電子、電動汽車智慧化、燃料電池動力系統、插電/增程式混合動力系統和純電動力系統6個創新鏈,共部署38個重點研究任務,專項實施週期為5年。其中,對於插電式混合動力系統的考核標準已經逐步完善,對新型高性價比乘用車混合動力總成開發與整車集成的考核標準為:整車加速時間0-100km/h≤5s,0-50km/h≤2.5s;綜合工況純電續駛里程≥70km;燃油消耗量較第四階段油耗限值降低比例≥40%;整車實現銷售≥5000台。   純電動汽車未來的百公里加速要在6S以內,專項對純電動力系統的其中一項考核標準是,在工況下,最大爬坡度≥30%,純電續駛里程≥300km,0-100km/h加速時間≤6s,30分鐘最高車速≥120km/h;電制動降低電能消耗率≥25%;整車具備安全穩定的轉向功能,並實現小批量試驗運行。   電動汽車目前的關鍵技術在於動力電池,專項對與新能源汽車的動力電池和電池管理系統的考核標準是:提交高比能鋰離子電池的安全風險識別方法與評測報告;建立電池的安全評測體系,形成相關安全標準;電池單體能量密度≥300Wh/kg,迴圈壽命≥1500次,成本≤0.8元/Wh,安全性達到國標要求,年生產能力≥1億瓦時。   文章來源:EV世紀

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

三菱汽車五年內推出電動休旅車

搶攻電動車市場,三菱汽車(Mitsubishi Motors)宣布預計在2020年推出純電動休旅車,且將是全球戰略性車款。

報導指出,三菱的澳洲執行長Osamu Masuko透露了2020年發表純電動休旅車的計畫,但其他細節並未公開。市場猜測,這款車會類似Nissan Juke或Ford EcoSport,為中小型休旅車款,並搭配全時四輪驅動系統與自動駕駛系統。

而特斯拉的400公里續航力儼然成了新一代電動車產品的續航力標準。三菱的純電動休旅車續航力,具三菱汽車內部消息透露,也會超過400公里,可與特斯拉車款一較高下。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

BMW iX3 正式登場,又一款台灣買不到的電動車

搭載第五代 eDrive 技術,續航突破 440 公里的 BMW iX3,今日正式登場,並宣布於明年起在中國、北美和歐洲開賣,台灣消費者幾乎肯定買不到,因為這款車將會在中國製造。

德國汽車大廠 BMW,去年介紹了 iX3 的概念車型後,就受到許多車迷期待,今天終於宣布要在 2020 年正式開賣,先來看看這輛車的規格與性能吧。

BMW iX3 搭載 74 kWh 的新版電池組,根據歐盟標準,滿電里程達到 440 公里,馬達能夠輸出 286 馬力,最大扭力為 400 牛頓米。極速達到每小時 200 公里,零到一百加速時間為 6 秒,能源效率部分,官方並未提供準確數據,只表示會低於 20 kW/100 km,由於 BMW i3 的能源效率約為 15 kW/100 km,因此保守估計 iX3 應該能有差不多的表現。

BMW i3 做為集團最初代的電動車,雖然銷售不算太好,但在品牌效應下,仍然有穩定的市場。iX3 的命名則非常有趣,因為它雖然是集團第二款純電車,但他並不是 i3 的後繼車款,而是新一代的 X3,被定義為首款純電動的 SAV(Sport Activity Vehicle)。

iX3 除了純電版本,還會推出同款的燃油版跟油電板,一車三吃。它所搭載的第五代 eDrive 是 BMW 為了下一個世代的電動車所開發的新動力系統,未來將會使用在 i4 跟 i-NEXT 身上。

無論 BMW 願不願意,iX3 的尺寸和價位都無法避免要跟 Tesla 的 SUV 相比,單純比較性能的話,iX3 跟 Model Y 比較接近,但特斯拉在各方面都小贏一些,價格如果沒意外的話,Model Y 應該會比 iX3 便宜不少,但是考慮到內裝和品牌效應,這兩台車應該會讓不少車主苦惱一番(官方售價尚未公布,推測落在 7 萬美元左右)。

不過台灣車主大概不需要苦惱,因為 ,除非法規鬆綁,否則台灣注定是買不到這台車了。台灣的 BMW 車友如果想要入手新款的 電動車,就要等 2021 年的 i4 了。

▲ 第五代 eDrive 動力元件是 BMW 邁入下一個時代的最重要核心技術。(Source:)

BMW 是少數不打算自行研發電池的傳統車廠,目前 i3 使用的是南韓三星的電池組,而 iX3 將會使用寧德時代的電池組。這家車廠將心力投注在他們的 eDrive 動力系統上,根據目前釋出的訊息來看,BMW 的新款馬達並沒有採用目前常見的永磁同步馬達,而是用他們研發的新系統,將馬達、差速器跟系統電子組件全部整合在一起,變成極為精簡的驅動元件,同時提供優秀的動力表現。

「第五代 eDrive 的驅動元件,重量出力比跟前代相較之下提升了 30%,」BMW 官方發言人表示,不僅效率提升,製作過程中也不再需要使用稀土,未來他們將會大量應用這款驅動元件在各種車型上。

此外,寧德時代提供給 BMW 的方形電池組,採用的是新技術 NMC-811 電池,鎳的比例更高,鈷和錳比例下降,除了成本更低,能量密度也更高。

iX3 另一個隱藏的對手是 Tesla Model Y,由於交車時間尚未明朗,許多車主還在觀望,如果 Model Y 在 2020 年第一季順計出貨,那 BMW iX3 可能會跟 i3 一樣,只能固守基本盤,無法吃下更多電動休旅車的市場。

(合作媒體:。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

推動 FCV 普及!本田、五十鈴傳攜手研發燃料電池卡車

日經新聞 14 日,本田汽車(Honda)將和五十鈴(ISUZU)攜手研發使用氫氣作為燃料的燃料電池卡車,期望藉此推動燃料電池車(FCV)的普及腳步。

據報導,此將是本田首度將 FCV 技術提供給外部企業使用,而五十鈴計畫早期推出使用本田燃料電池系統的卡車車款。除五十鈴之外,本田今後也計畫將燃料電池系統販售給造船公司等外部企業。

FCV 是使用氫氣作為燃料進行行駛的車款,因不會排放二氧化碳,因此被視為「究極的環保車」,不過因供應燃料的氫氣站缺乏、導致 FCV 普及速度牛步,不過若是卡車等商用車的話、因有固定的行駛路徑因此更易於進行氫氣站的整備。

全球 FCV 普及腳步緩慢,根據英國調查公司 IHS Markit 指出,相較於 2018 年電動車市場規模約 140 萬台、FCV 僅約 4,000 台。

豐田於 2014 年 12 月開賣全球首款量產款 FCV「MIRAI」、本田也於 2016 年推出 FCV 車「Clarity」。

南韓媒體中央日報日文版 1 月 14 日報導,根據南韓產業通商資源部指出,2019 年 1-10 月期間全球 FCV 銷售量為 6,126 台,其中南韓現代汽車拿下高達 60%(3,666 台)的銷售市佔率,其次為豐田(2,174 台)和本田(286 台)。

豐田汽車會長內山田竹志於 2019 年 9 月 25 日在東京都內舉行的「氫氣部長級會議」上表示,關於燃料電池車(FCV)「MIRAI」的次代車款,「目前正進行最終研發、目標在 2020 年內開賣」。

日本媒體報導,由約 40 個國家/機關代表者出席、討論氫氣普及對策的「氫氣部長級會議」於 2019 年 9 月 25 日在東京都內舉行,而擔任議長的日本經濟產業大臣菅原一秀提案,將使用燃料電池的車輛、飛機等交通工具的普及數量在今後 10 年間擴增至 1,000 萬台訂為全球目標,而該提案獲得與會各國贊同。

另外,該會議上也同意,計畫在 10 年內將供應燃料的氫氣站數量自現行的數百座擴增至 1 萬座。

(本文內容由 授權使用。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

歐洲可充電公路測試中,預計2018年上市

電動車邊最怕路上沒電,但如果能邊跑邊充電,就不怕沒電的問題,這項殺手級應用聽起來很科幻,但現實世界,可充電公路已進入測試階段,離實際應用應該也不遠了。

將無線充電套件嵌入道路表面上,就成了名符其實的充電道路,美國晶片廠高通近期就在法國測試道路上展示這項技術,稱之為電動車行進間充電(dynamic electric vehicle charging,簡稱DEVC)。

據Economictimes報導,DEVC可對高速行駛之汽車,以最高20kW的功率充電,目前同一條跑道上,DEVC能同時對兩輛電動車進行充電。

歐洲非常重視電動車發展,這項計畫是由歐盟執委會(European Commission)主導,共耗費一千萬美元,來自九個歐盟成員國的25個機構共同參與。報導指出,無線充電電動車預計2017、2018年上市,多數主要車廠正準備制訂全球無線充電標準。

(本文內容由授權使用。圖片出處:wikipedia)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

Jaguar 宣布進軍電動車市場,要來挑戰Tesla

各個車廠看到電動車的趨勢,不願意讓Tesla 再繼續引領風潮,包括Jaguar 也將在2018 年下半年發表電動車車款。

Jaguar 的新電動車概念車I-PACE 將在2018 年下半年推出,將是Jaguar 第一台純電動車。性能方面具備700Nm 高扭力,400PS 馬力與4 秒內完成0~100km/h 加速的超高性能,相信是追求速度和零排放車主的選擇。

Jaguar 決定推出全電動車,意味著要跟Tesla 在SUV 市場短兵相接。由於電動車不用傳統車子的馬達系統,車內空間可以更寬敞讓乘客和駕駛更舒適。

(合作媒體:。圖片出處:Jaguar)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

ES6 Map 原理

ES6的Map的鍵可以是任意的數據結構,並且不重複。

那麼map的底層原理是啥呢?

Map利用鏈表,hash的思想來實現。

首先,Map可以實現刪除,而且刪除的數據可以是中間的值。而鏈表的優勢就是在中間的任意位置添加,刪除元素都非常快,不需要移動其他元素,直接改變指針的指向就可以。。

而在存儲數據很多的情況下,會導致鏈條過長,導致查找效率慢,所以我們可以創建一個桶(存儲對象的容器),根據hash(把散列的值通過算法變成固定的某值)來平局分配數據,防止鏈條過長。

 

 

如下圖:桶裏面有3個位置,每一個位置都是一個對象,通過next屬性指向下一個對象來把沒有關聯的對象聯到一起。

 

 

 

把Map屬性值和屬性名都存到對象的值里。

簡單模擬Map,代碼如下:

function Mymap() {  //構造函數
    this.init();
}
//初始化函數,創建桶(數組),每個位置都是一個對象,每個對象的屬性上設置next屬性,並且初始化為null。 Mymap.prototype.init = function () { this.tong = new Array(8); for (var i = 0; i
< 8; i++) { this.tong[i] = new Object(); this.tong[i].next = null; } }; //添加數據。 Mymap.prototype.set = function (key, value) { var index = this.hash(key); //獲取到當前設置的key設置到那個位置上 var TempBucket = this.tong[index]; //獲取當前位置的對象 while (TempBucket.next) { //遍歷如果當前對象鏈接的下一個不為空 if (TempBucket.next.key == key) { //如果要設置的屬性已經存在,覆蓋其值。 TempBucket.next.value = value; return; //return ,不在繼續遍歷 } else { TempBucket = TempBucket.next; //把指針指向下一個對象。 } } TempBucket.next = { //對象的next是null ,添加對象。 key: key, value: value, next: null } };
//查詢數據 Mymap.prototype.get = function (key) { var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.key == key){ return TempBucket.value; }else{ TempBucket = TempBucket.next; } } return undefined; }
//刪除數據 Mymap.prototype.delete = function(key){ var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.next.key == key){ TempBucket.next = TempBucket.next.next; return true; }else{ TempBucket = TempBucket.next; } } }
//看當前屬性是否存在 Mymap.prototype.has = function(key){ var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.key == key){ return true; }else{ TempBucket = TempBucket.next; } } return false; }
//清空這個map Mymap.prototype.clear = function(){ this.init(); } //使設置的屬性平均分配到每個位置上,使得不會某個鏈條過長。 Mymap.prototype.hash = function (key) { var index = 0; if (typeof key == "string") { for (var i = 0; i < 3; i++) { index = index + isNaN(key.charCodeAt(i)) ? 0 : key.charCodeAt(i); } } else if (typeof key == 'object') { index = 0; } else if (typeof key == 'number') { index = isNaN(key) ? 7 : key; } else { index = 1; } return index % 8; } var map = new Mymap(); //使用構造函數的方式實例化map

map.set('name','zwq');
map.get('name');
map.has('name);

 

 

 

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

面試填坑筆記-從代理模式到SpringAOP的動態代理

代理模式是一種理論上非常簡單,但是各種地方的實現往往卻非常複雜。本文將從代理模式的基本概念出發,探討代理模式在java領域的應用與實現。讀完本文你將get到以下幾點:

  1. 為什麼需要代理模式,它通常用來解決什麼問題,以及代理模式的設計與實現思路
  2. Java領域中代理模式3種不同實現類型(靜態代理,jdk動態代理,cglib)
  3. 代理模式的面試考點

為什麼要使用代理模式

在生活中我們通常是去商場購買東西,而不是去工廠。最主要的原因可能有以下幾種:

  1. 成本太高,去工廠路途遙遠成本太高,並且可能從工廠進貨要辦理一些手續流程;
  2. 工廠不直接賣給你,畢竟可能設計到一些行業機密或者無良廠家有一些不想讓你知道的東西;
  3. 商場能提供一些商品之外的服務,商場里有舒適的溫度,整潔的洗手間,當然還有漂亮的小姐姐。

在面向對象的系統中也有同樣的問題,有些對象由於某種原因,比如對象創建開銷很大,或者某些操作需要安全控制等,直接訪問會給使用者或者系統結構帶來很多麻煩,這時我們就需要考慮使用代理模式。

在應用中我們可能會用代理模式解決以下問題:

  1. 權限控制與日誌, 在客戶端請求接口時我們可能需要在調用之前對權限進行驗證,或者通過記錄接口調用前後時間,統計執行時長,又或者說我們需要記錄用戶的一些操作日誌信息等,我們可以對原接口進行代理,然後根據需求在接口執行前後增加一些特定的操作。
  2. 重量級操作, 比如創建開銷大的對象, 可以先由代理對象扮演對象的替身,在需要的使用再創建對象,然後代理再將請求委託給真實的對象。

什麼是代理模式

代理模式:為其他對象提供一種代理以控制(隔離,使用接口)對這個對象的訪問。類圖如下:

所謂控制,其實使用接口隔離其他對象與這個對象之間的交互;就是為client對象對RealSubject對象的訪問一種隔離,本質上就是CLient→RealSuject的關係變成了Client→Subject, Proxy→RealSubject。 需要注意的時,代理類(Proxy)並不一定要求保持接口的完整的一致性(既也可以完全不需實現Subject接口),只要能夠實現間接控制即可。

代理模式代碼演進

背景:假設已有一個訂單系統,可以保存訂單信息。

需求:打印保存訂單信息消耗時間。

/**
 * 訂單服務
 *
 * @author cruder
 * @date 2019-11-23 15:42
 **/
public class OrderService2 {
    /**
     * 保存訂單接口
     */
    public void saveOrder(String orderInfo) throws InterruptedException {
        // 隨機休眠,模擬訂單保存需要的時間
        Thread.sleep(System.currentTimeMillis() & 100);
        System.out.println("訂單:" + orderInfo + "  保存成功");
    }
}

普通方式實現

直接修改源代碼,這通常也是最簡單和最容易想到的實現。

 /**
  * 保存訂單接口, 直接修改代碼
  */
 public void saveOrder(String orderInfo) throws InterruptedException {
 
     long start = System.currentTimeMillis();
 
     // 隨機休眠,模擬訂單保存需要的時間
     Thread.sleep(System.currentTimeMillis() & 100);
     System.out.println("訂單:" + orderInfo + "  保存成功");
 
     System.out.println("保存訂單用時: " + (System.currentTimeMillis() - start) + "ms");
 }

面向對象設計原則中的“開閉原則”告訴我們,開閉原則規定“軟件中的對象(類,模塊,函數等等)應該對於擴展是開放的,但是對於修改是封閉的”,這意味着一個實體是允許在不改變它的源代碼的前提下變更它的行為。

代理模式實現

/**
 * 1. 定義接口,為了使代理被代理對象看起來一樣。當然這一步完全可以省略
 *
 * @author cruder
 * @date 2019-11-23 15:58
 **/
public interface IOrderService {
    /**
     * 保存訂單接口
     * @param orderInfo 訂單信息
     */
    void saveOrder(String orderInfo) throws InterruptedException;
}
/**
 * 2. 原有訂單服務,也實現這個接口。注意 此步驟也完全可以省略。
 *
 * @author cruder
 * @date 2019-11-23 15:42
 **/
public class OrderService implements IOrderService{
    /**
     * 保存訂單接口
     */
    @Override
    public void saveOrder(String orderInfo) throws InterruptedException {
        // 隨機休眠,模擬訂單保存需要的時間
        Thread.sleep(System.currentTimeMillis() & 100);
        System.out.println("訂單:" + orderInfo + "  保存成功");
    }
}


/**
 * 3. 創建代理類,實現訂單服務接口【這才是代理模式的實現】
 * 
 * @author cruder
 * @date 2019-11-23 16:01
 **/
public class OrderServiceProxy implements IOrderService{
    /**
     * 內部持有真實的訂單服務對象,保存訂單工作實際由它來完成
     */
    private IOrderService orderService;

    @Override
    public void saveOrder(String orderInfo) throws InterruptedException {
        /**
         * 延遲初始化,也可以創建代理對象時就創建,或者作為構造參數傳進來
         * 僅作為代碼實例,不考慮線程安全問題
         */
        if (orderService == null) {
            orderService = new OrderService();
        }

        long start = System.currentTimeMillis();
        orderService.saveOrder(orderInfo);
        System.out.println("保存訂單用時: " + (System.currentTimeMillis() - start) + "ms");
    }
}執行程序

執行程序

代理模式的優缺點

優點: 1、職責清晰。 2、高擴展性。 3、智能化。

缺點:

1、由於在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。 2、實現代理模式需要額外的工作,有些代理模式的實現非常複雜。

Java中代理模式的實現

在java中代理模式可以按照代理類的創建時機分兩類,即靜態代理和動態代理,而動態代理又可以分為jdk動態代理和cglib動態代理。每種實現方式都各有千秋,接下來筆者將回針對不同的實現方式進行演示和剖析。

靜態代理

在上文代理模式代碼演進中就使用了靜態代理模式。所謂靜態代理中的“靜”字,無非就是代理類的創建時機不同罷了。靜態代理需要為每個被代理的對象手動創建一個代理類;而動態代理則時在運行時通過某種機制來動態生成,不需要手動創建代理類。

動態代理 – jdk

jdk動態代理模式是利用java中的反射技術,在運行時動態創建代理類。接下來我們仍藉助上文中的訂單服務的案例,使用jdk動態代理實現。

基於動態jdk涉及到兩個核心的類Proxy類和一個 InvocationHandler接口。

/**
 * 基於JDK技術 動態代理類技術核心 Proxy類和一個 InvocationHandler 接口
 *
 * @author cruder
 * @date 2019-11-23 16:40
 **/
public class ProxyFactory implements InvocationHandler {

    /**
     * 委託對象,既被代理的對象
     */
    private Object target;

    public ProxyFactory (Object target) {
        this.target = target;
    }

    /**
     * 生成代理對象
     * 1. Classloader loader: 制定當前被代理對象使用的累加子啊其,獲取加載器的方法固定
     * 2. Class<?>[] interfaces: 委託類的接口類型,使用泛型方法確認類型
     * 3. InvocationHandler handler: 事件處理,執行委託對象的方法時會觸發事件處理器方法,
     * 會把當前執行的委託對象方法作為參數傳入
     */
    public Object getProxyInstance() {
        Class clazz = target.getClass();

        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        method.invoke(target, args);
        System.out.println("保存訂單用時: " + (System.currentTimeMillis() - start) + "ms");
        return null;
    }
}

/**
 * 通過動態代理方式來保存訂單
 *
 * @author cruder
 * @date 2019-11-23 15:49
 **/
public class Client {
    public static void main(String[] args) throws InterruptedException {
        ProxyFactory proxyFactory= new ProxyFactory (new OrderService());
        IOrderService orderService = (IOrderService) proxyFactory.getProxyInstance();
        orderService.saveOrder(" cruder 新買的花褲衩 ");
    }
}

以上便是jdk動態代理的全部實現,有種只可意會不可言傳的感覺,筆者始終感覺這種實現看起來很彆扭。不過也要強行總結以下,jdk實現動態代理可以分為以下幾個步驟:

  1. 先檢查委託類是否實現了相應接口,保證被訪問方法在接口中也要有定義
  2. 創建一個實現InvocationHandler接口的類
  3. 在類中定義一個被代理對象的成員屬性,為了擴展方便可以直接使用Object類,也可以根據需求定義相應的接口
  4. 在invoke方法中實現對委託對象的調用,根據需求對方法進行增強
  5. 使用Proxy.newProxyInstance(…)方法創建代理對象,並提供要給獲取代理對象的方法

代理類源碼閱讀

上文中基於jdk動態代理的代碼實現中對於可*的產品經理來說已經完全滿足了需求,但是對於具有Geek精神的程序員來說這遠遠不夠,對於這種不知其所以然的東西往往讓人感到不安。接下來我們將通過自定義的一個小工具類將動態生成的代理類保存到本地來一看究竟。

/**
 * 將生成的代理類保存為.class文件的工具類
 *
 * @author cruder
 * @date 2019-08-15 0:27
 */
public class ProxyUtils {
    /**
     * 將代理類保存到指定路徑
     *
     * @param path           保存到的路徑
     * @param proxyClassName 代理類的Class名稱
     * @param interfaces     代理類接口
     * @return
     */
    public static boolean saveProxyClass(String path, String proxyClassName, Class[] interfaces){
        if (proxyClassName == null || path == null) {
            return false;
        }
        // 獲取文件字節碼,然後輸出到目標文件中
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyClassName, interfaces);
        try (FileOutputStream out = new FileOutputStream(path)) {
            out.write(classFile);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

// 此處是重點, 生成的代理類實現了IOrderService,並且繼承了Proxy
public final class $Proxy0 extends Proxy implements IOrderService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void saveOrder(Order var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    
    static {
        try {
           // 通過反射獲取Method對象
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("cn.mycookies.test08proxy.IOrderService").getMethod("saveOrder", Class.forName("cn.mycookies.test08proxy.Order"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

ps: 實習轉正面試中被問到為什麼jdk動態代理被代理的類為什麼要實現接口?

cglib動態代理

對於cglib我想大多數人應該都很陌生,或者是在學習Spring中AOP(面向切面編程)時聽說了它使用jdk和cglib兩種方式實現了動態代理。接下來筆者將針對cglib進行簡要介紹。

cglib動態代理和jdk動態代理類似,也是採用操作字節碼機制,在運行時生成代理類。cglib 動態代理採取的是創建目標類的子類的方式,因為是子類化,我們可以達到近似使用被調用者本身的效果。

字節碼處理機制-指得是ASM來轉換字節碼並生成新的類

注:spring中有完整的cglib相關的依賴,所以以下代碼基於spring官方下載的demo中直接進行編寫的

/**
 * 1. 訂單服務-委託類,不需要再實現接口
 *
 * @author cruder
 * @date 2019-11-23 15:42
 **/
public class OrderService {
    /**
     * 保存訂單接口
     */
    public void saveOrder(String orderInfo) throws InterruptedException {
        // 隨機休眠,模擬訂單保存需要的時間
        Thread.sleep(System.currentTimeMillis() & 100);
        System.out.println("訂單:" + orderInfo + "  保存成功");
    }
}

/**
 * cglib動態代理工廠
 *
 * @author cruder
 * @date 2019-11-23 18:36
 **/
public class ProxyFactory implements MethodInterceptor {

    /**
     * 委託對象, 即被代理對象
      */
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 返回一個代理對象
     * @return
     */
    public Object getProxyInstance(){
        // 1. 創建一個工具類
        Enhancer enhancer = new Enhancer();
        // 2. 設置父類
        enhancer.setSuperclass(target.getClass());
        // 3. 設置回調函數
        enhancer.setCallback(this);
        // 4.創建子類對象,即代理對象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        long start = System.currentTimeMillis();

        Object result = method.invoke(target, args);

        System.out.println("cglib代理:保存訂單用時: " + (System.currentTimeMillis() - start) + "ms");
        return result;
    }
}

​

/**
 * 使用cglib代理類來保存訂單
 *
 * @author cruder
 * @date 2019-11-23 15:49
 **/
public class Client {
    public static void main(String[] args) throws InterruptedException {
        // 1. 創建委託對象
        OrderService orderService = new OrderService();
        // 2. 獲取代理對象
        OrderService orderServiceProxy = (OrderService) new ProxyFactory(orderService).getProxyInstance();
        String saveFileName = "CglibOrderServiceDynamicProxy.class";
        ProxyUtils.saveProxyClass(saveFileName, orderService.getClass().getSimpleName(), new Class[]{IOrderService.class});
        orderServiceProxy.saveOrder(" cruder 新買的花褲衩 ");
    }
}

cglib動態代理實現步驟和jdk及其相似,可以分為以下幾個步驟:

  1. 創建一個實現MethodInterceptor接口的類
  2. 在類中定義一個被代理對象的成員屬性,為了擴展方便可以直接使用Object類,也可以根據需求定義相應的接口
  3. 在invoke方法中實現對委託對象的調用,根據需求對方法進行增強
  4. 使用Enhancer創建生成代理對象,並提供要給獲取代理對象的方法

cglib動態代理生成的代理類和jdk動態代理代碼格式上幾乎沒有什麼區別,唯一的區別在於cglib生成的代理類繼承了僅僅Proxy類,而jdk動態代理生成的代理類繼承了Proxy類的同時也實現了一個接口。代碼如下:

// 生成一個Proxy的子類
public final class OrderService extends Proxy {
    private static Method m1;
    private static Method m2;
    private static Method m0;

    public OrderService(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

jdk動態代理 VS cglib

JDK Proxy 的優勢:

  • 最小化依賴關係,減少依賴意味着簡化開發和維護,JDK 本身的支持,可能比 cglib 更加可靠。
  • 平滑進行 JDK 版本升級,而字節碼類庫通常需要進行更新以保證在新版 Java 上能夠使用。
  • 代碼實現簡單。

cglib 優勢:

  • 有的時候調用目標可能不便實現額外接口,從某種角度看,限定調用者實現接口是有些侵入性的實踐,類似 cglib 動態代理就沒有這種限制。
  • 只操作我們關心的類,而不必為其他相關類增加工作量。

總結

  1. 代理模式: 為其他對象提供一種代理以控制(隔離,使用接口)對這個對象的訪問。
  2. jdk動態代理生成的代理類繼承了Proxy類並實現了被代理的接口;而cglib生成的代理類則僅繼承了Proxy類。
  3. jdk動態代理最大缺點:只能代理接口,既委託類必須實現相應的接口
  4. cglib缺點:由於是通過“子類化”的方式, 所以不能代理final的委託類或者普通委託類的final修飾的方法。

Q&A

  1. 為什麼jdk動態代理只能代理接口?
  2. Spring中AOP的實現採用那種代理方式?
  3. 都說jdk動態代理性能遠比cglib要差,如果是,依據是什麼?

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

.Net Core讀取Json配置文件

前言:在與傳統的asp.net MVC項目相比,.net core項目在項目目錄的文件結構上和功能上與前者都有很大的區別。例如:在.net core中使用Startup.cs取代Global.asax文件用於加載應用程序的配置和各種啟動項。appsettings.json取代web.config文件用於存儲應用程序所需的配置參數等等。。。

OK!步入正題,下面來說一下如何讀取Json配置文件中的參數。

第一種:使用IConfiguration接口

我們先在appsettings.json中配置好數據庫連接字符串,然後讀取它

{
  "Connection": {
    "dbContent": "Data Source=.;Initial Catalog=test;User ID=sa;Password=123456"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

 

 

 在控制器中注入IConfiguration接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace Read.json.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ReadController : Controller
    {
        private IConfiguration _configuration;
        public ReadController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        [HttpPost]
        public async Task<string> ReadJson()
        {
//讀參
string conn = _configuration["Connection:dbContent"]; return ""; } } }

 

 當然也可以讀取數組形式的json,一樣的先在appsettings.json中寫好配置參數,如下:

{
  "Connection": {
    "dbContent": "Data Source=.;Initial Catalog=test;User ID=sa;Password=123456"
  },

  //------------------------
  "Content": [
    {
      "Trade_name": {
        "test1": "小熊餅乾",
        "test2": "旺仔QQ糖",
        "test3": "娃哈哈牛奶"
      }
    }
  ],
  //------------------------

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

比如我們想讀取test1

  string commodity_test1 = _configuration["Content:0:Trade_name:test1"];

 

 第二種:使用IOptions<T>來讀取json配置文件

先把NuGet包導進項目:Microsoft.Extensions.Options.ConfigurationExtensions

 

 

首先在appsettings.json中添加節點如下

{
  "Connection": {
    "dbContent": "Data Source=.;Initial Catalog=test;User ID=sa;Password=123456"
  },

  //------------------------
  "Content": [
    {
      "Trade_name": {
        "test1": "小熊餅乾",
        "test2": "旺仔QQ糖",
        "test3": "娃哈哈牛奶"
      }
    }
  ],
  //------------------------

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",

  //==============================
  "Information": {
    "school": {
      "Introduce": {
        "Name": "實驗小學",
        "Class": "中班",
        "Number": "15人"
      },
      "Region": {
        "Province": "湖北",
        "City": "武漢",
        "Area": "洪山區"
      },
      "Detailed_address": [
        {
          "Address": "佳園路207號"
        }
      ]
    }
  }
  //==============================
}

 

然和再建立一個與這個節點”相同”的類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Read.json
{
    public class Information
    {
        public School school { get; set; }
    }
    public class School
    {
        public Introduce Introduce { get; set; }

        public Region Region { get; set; }

        public List<Detailed_address> data { get; set; }

    }
    public class Introduce
    {
        public string Name { get; set; }
        public string Class { get; set; }
        public string Number { get; set; }
    }

    public class Region
    {
        public string Province { get; set; }
        public string City { get; set; }
        public string Area { get; set; }
    }
    public class Detailed_address
    {
        public string Address { get; set; }
    }
}

 

在Startup中添加如下代碼

            #region 服務註冊,在控制器中通過注入的形式使用
            services.AddOptions();
            services.Configure<Information>(Configuration.GetSection("Information"));
            #endregion

 

 控制器中使用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace Read.json.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ReadController : Controller
    {
        private IConfiguration _configuration;

        readonly Information _Information;

        readonly IOptions<Information> _options;
        public ReadController(IConfiguration configuration,
                              Information Information,
                              IOptions<Information> options)
        {
            _configuration = configuration;
            _Information = Information;
            _options = options;
        }

        [HttpGet]
        public async Task<IActionResult> ReadInformation()
        {
            string Address = _options.Value.school.Region.Province + "-" +
                             _options.Value.school.Region.City + "-" +
                             _options.Value.school.Region.Area + "-" +
                             _options.Value.school.Detailed_address[0].Address + "-" +
                             _options.Value.school.Introduce.Name + "-" +
                             _options.Value.school.Introduce.Class + "-" +
                             _options.Value.school.Introduce.Number;
            return Json(Address);
        }

        [HttpPost]
        public async Task<string> ReadJson()
        {
            string conn = _configuration["Connection:dbContent"];
            string commodity = _configuration["Content:0:Trade_name:test1"];
            return "";
        }

    }
}

 

 

 

 

第三種:這種應該比較常見,任意讀取自定義的json文件

首先建立一個json文件

{
  "system_version": {
    "Edition": ".Net Core 3.0",
    "Project_Name": "Read.json"
  }
}

 

 

 再建一個類,封裝一個方法

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Read.json
{
    public class Json_File
    {
        public IConfigurationRoot Read_Json_File()
        {
            //這句代碼會讀取read_json.json中的內容
            return new ConfigurationBuilder().AddJsonFile("read_json.json")
                                             .Build();

        }

    }
}

 

 

 在控制器中調用:

        [HttpGet]
        public async Task<IActionResult> ReadSystemVersion()
        {
            var configuration = _json_File.Read_Json_File();
            string system = "使用的是" + configuration["system_version:Edition"] + "的版本" + "," +
                            "項目名稱是" + configuration["system_version:Project_Name"];
            return Json(new
            {
                data = system
            });
        }

 

 

 

 

Demo地址:Func<Address,Project> func = (address) => git clone address;
var project = func("https://github.com/Davenever/Read_Json.git");

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享