玩轉VSCode-完整構建VSCode開發調試環境

隨着VSCode的不斷完善和強大,是時候將部分開發遷移到VS Code中了。

目前使用VS2019開發.NET Core應用,一直有一個想法,在VS Code中復刻VS的開發環境,同時遷移到VS Code。

那麼現在就開始吧。

首先,安裝最新版的VS Code:,安裝完成后可能會提示升級,升級即可,升級后的版本信息:

版本: 1.40.1 (system setup)
提交: 8795a9889db74563ddd43eb0a897a2384129a619
日期: 2019-11-13T16:49:35.976Z
Electron: 6.1.2
Chrome: 76.0.3809.146
Node.js: 12.4.0
V8: 7.6.303.31-electron.0
OS: Windows_NT x64 10.0.16299

接下來的操作分為幾個步驟:

1. 安裝各種強大VS Code插件

2. 創建.NET Core解決方案和工程

3. 調試運行

好的,那我們開始吧。

一、安裝各種強大的VS Code插件

1. C# extension for Visual Studio Code

這個插件最重要的功能:

  • Lightweight development tools for .
  • Great C# editing support, including Syntax Highlighting, IntelliSense, Go to Definition, Find All References, etc.
  • Debugging support for .NET Core (CoreCLR). NOTE: Mono debugging is not supported. Desktop CLR debugging has .
  • Support for project.json and csproj projects on Windows, macOS and Linux.

2. C# Extensions

這個插件最有用的功能是可以右鍵新建C#類和C#接口,同時支持各種code snippets,例如 ctor 、prop等,具體功能特性,可以查看插件的說明。

 3. Auto-Using for C#

這個插件自動添加using引用。

4. vscode-solution-explorer

這個插件給VS Code增加了解決方案tab, 支持新建解決方案、新建工程、添加引用、Nuget包,這個插件非常有用

Adds a Solution Explorer panel where you can find a Visual Studio Solution File Explorer.

  • Can load any .sln version

  • Supports csproj, vcxproj, fsproj and vbproj (from vs2017 and before)

  • Supports dotnet core projects

  • You can create, delete, rename or move project folders and files.

  • You can create, delete, rename or move solution, solution folders and projects.

  • You can add or remove packages and references when the project is of kind CPS (dotnet core).

 

5. Code Runner(韓俊老師出品,必屬精品)

Run code snippet or code file for multiple languages: C, C++, Java, JavaScript, PHP, Python, Perl, Perl 6, Ruby, Go, Lua, Groovy, PowerShell, BAT/CMD, BASH/SH, F# Script, F# (.NET Core), C# Script, C# (.NET Core), VBScript, TypeScript, CoffeeScript, Scala, Swift, Julia, Crystal, OCaml Script, R, AppleScript, Elixir, Visual Basic .NET, Clojure, Haxe, Objective-C, Rust, Racket, Scheme, AutoHotkey, AutoIt, Kotlin, Dart, Free Pascal, Haskell, Nim, D, Lisp, Kit, and custom command

即選中一段代碼,直接run

6. vscode-icons

通過這個插件,給各個文件和文件夾一個你更熟悉的圖標

7. Visual Studio IntelliCode

VS代碼智能提示,根據上下文語境,自動推薦你下一步用到的代碼,後台基於AI的

8. NuGet Package Manager

Nuget包管理,快速查詢定位Nuget包,並安裝。不過嘗試了一下午自定義Nuget源,沒搞定,估計是URL不對

9. Docker

10. Kubernetes

其他的還需要配置GitHub、TFS類似的源代碼管理,TFS搞了兩個插件,都不好使,後續搞定后再更新一次。

 

二、創建.NET Core解決方案和工程

此時,VS Code的環境基本配置差不多了,接下來有兩種模式,創建解決方案和工程。

1. 通過vscode-solution-explorer

解決方案有了,很熟悉的感覺。

我們可以繼續創建工程:右鍵sln,Add new project:

此時會彈出工程模板,此時我們選擇ASP.NET Core Web API工程

選擇C#

然後繼續輸入工程名稱:例如 TestWebApi

熟悉的感覺來了。此時就可以開始coding了。

以上是我們通過vscode-solution-explorer新建解決方案和工程。同時我們可以通過命令行來搞定。

2. 通過Dotnet CLI命令行

新建sln:

dotnet "new" "sln" "-n" "EricTest" "-o" "e:\Work\ServiceDependency"

新建ASP.NET Core WebAPI工程

dotnet "new" "webapi" "-lang" "C#" "-n" "TestWebApi" "-o" "TestWebApi"

將TestWebApi工程添加到解決方案EricTest

dotnet "sln" "e:\Work\ServiceDependency\EricTest.sln" "add" "e:\Work\ServiceDependency\TestWebApi\TestWebApi.csproj"

三、調試運行

在Debug選項卡中新增調試配置,重點設置要調試的program

保存后,啟動調試:

 

程序中增加斷點,然後

輸入URL:https://localhost:5001/WeatherForecast

 既可以調試了。

 

以上是今天集中配置VS Code開發調試環境的總結,分享給大家。

 

周國慶

2019//11/16

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

快速搭建Jenkins集群

關於Jenkins集群

在Jenkins上同時執行多個任務時,單機性能可能達到瓶頸,使用Jenkins集群可以有效的解決此問題,讓多台機器同時處理這些任務可以將壓力分散,對單機版Jenkins的單點故障的隱患也有分散作用,今天就來實戰快速搭建Jenkins集群,Jenkins版本是2.190.2;

如何做到快速搭建集群

通過Docker可以省去大部分準備工作,您只需在Linux電腦上安裝docker,在輔以少量命令和操作即可完成集群搭建;

環境信息

本次實戰的環境一共要用三台電腦,它們的設置都是一樣的,如下:

  1. 操作系統:CentOS Linux release 7.6.1810
  2. 防火牆關閉
  3. docker:1.13.1

三台電腦的信息如下:
| 主機名 | IP地址 | 作用 |
|–|–|–|
| master | 192.168.133.131 | Jenkins集群的master節點,提供web服務 |
| agent1 | 192.168.133.132 | Jenkins集群的一號工作接節點,標籤是maven |
| agent2 | 192.168.133.133 | Jenkins集群的二號工作接節點,標籤是gradle |

建議agent2節點的內存大於4G,因為下一篇的實戰操作會用agent2編譯構建spring-framework,對內存的需求略大;

準備工作

  1. 後面的所有操作都是root賬號;
  2. 在每台電腦上創建文件夾/usr/local/jenkins

    創建Jenkins的master

  3. 登錄master機器,執行以下命令:
docker run \
  -u root \
  -idt \
  --name master \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /usr/local/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkinsci/blueocean:1.19.0
  1. 執行docker logs master,會在控制台显示jenkins的登錄秘鑰,如下圖紅框所示:
  2. 瀏覽器輸入地址: ,显示Jenkins登錄頁面,如下圖所示,在紅框位置輸入剛才複製的登錄秘鑰即可登錄:
  3. 選擇安裝推薦的插件
  4. 靜候插件在線安裝完成:
  5. 接下來是創建管理員和使用實例url的操作,這裏就不多說了,您按實際情況自行斟酌;

    至此,Jenkins的master已經搭建好,接下來將agent1和agent2作為工作節點加入集群;

    加入agent1

  6. 在Jenkins網頁上新增節點,操作如下圖,先進入節點管理頁面:
  7. 如下圖,新增一個節點,名為agent1
  8. 接下來的節點詳情信息如下圖,注意四個紅框中的內容要和圖中保持一致:
  9. 保存成功後會显示機器列表,如下圖,圖標上的紅叉表示機器不在線(此時agent1還沒有接入),點擊紅框:
  10. 如下圖所示,紅框中的命令就是agent1的啟動命令,執行該命令的機器會以agent1的身份加入集群:
  11. 注意上圖紅框中的agent.jar是個名為agent.jar的文件的下載鏈接,將此文件下載到agent1電腦的/usr/local/jenkins目錄下;
  12. ssh登錄agent1電腦,執行以下命令,即可將agent1加入Jenkins集群:
docker run \
  -u root \
  -idt \
  --name agent \
  -v /usr/local/jenkins:/usr/local/jenkins \
  bolingcavalry/openjdk-with-sshpass:8u232 \
  java -jar /usr/local/jenkins/agent.jar \
  -jnlpUrl http://192.168.133.131:8080/computer/agent1/slave-agent.jnlp \
  -secret 44c3e8d1531754b8655b53294bbde6dd99b3aaa91a250092d0d3425534ae1058 \
  -workDir "/usr/local/jenkins"

上述命令中的後半部分,即java -jar ……就是前面圖片紅框中的agent1啟動命令,唯一要改變的是將agent.jar改成絕對路徑/usr/local/jenkins/agent.jar

  1. 上述命令的鏡像是bolingcavalry/openjdk-with-sshpass:8u232,其Dockerfile內容如下,可見非常簡單,就是OpenJDK鏡像裏面安裝了sshpass,這樣的容器可以在執行ssh命令時帶上遠程機器的密碼,而不用等待用戶輸入密碼,這樣便於shell腳本執行ssh命令:
FROM openjdk:8u232

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --assume-yes sshpass
  1. 去Jenkins的網頁上查看節點列表,如下圖,可見agent1已經成功加入:

    加入agent2

    agent2加入集群的方式和agent1大部分是一樣的,只有以下兩點要注意:

  2. 在Jenkins頁面上創建節點,名稱是agent2
  3. agent2的標籤是gradle,如下圖紅框所示:
  4. 此時agent2也加入成功:

    至此,Jenkins集群搭建完成,這兩個節點帶有不同的標籤,下一篇文章中,我們在這個集群環境創建pipeline任務,並通過標籤被分配到不同的節點上,實現多節點并行執行;

    歡迎關注公眾號:程序員欣宸

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

微信作弊,為3款小遊戲引擎開掛增速,將給小遊戲帶來怎樣的利好?

11月14日小遊戲開發圈子,有一條重磅新聞:“微信小遊戲聯合遊戲引擎廠商,推出引擎插件功能,可為小遊戲提升0.5~2秒的啟動時間”。

引擎插件是個什麼東西?

昨天有不少人在問曉衡:“引擎插件到底是個什麼東西?”、“又要讓我學習新東西嗎?”、“引擎插件是怎麼加速的,不太明白?” …

曉衡也在第一時間,將文檔通讀了一遍,並用自己的小遊戲工程做了測試,對微信小遊戲引擎插件算是有了一個簡單的認識,看下圖:

普通模式,每一個使用遊戲引擎開發的小遊戲,都需要下載遊戲引擎代碼模塊。

引擎插件模式,僅第一個遊戲需要下載引擎代碼,其它使用同類引擎的遊戲,可共享之前 A 遊戲下載過的遊戲引擎代碼,從而加速遊戲的啟動時間。

從事小遊戲開發和運營的夥伴應該都很了解,H5、小遊戲注重啟動加載速度,它對新用戶的體驗和流失都至關重要。

啟動概況分析

估計有人會覺得引擎插件就加快了0.5~2秒有什麼用?眨個眼的時間而已。

其實對使用 Cocos Creator 開發的休閑類的小遊戲來說,目前的微信小遊戲啟動速度已經很不錯了,首包含引擎的話,iOS 在4 ~ 6秒啟動,Android 大多可以在6~8秒左右打開首屏,並不像微信吹噓的1秒啟動,估計只有 引擎和資源全放子包的遊戲可以做到!

下面我將自己個人開發的一款微信小遊戲,在微信公測的前後两天做了一個數據統計,想窺視一下啟動性能對留存的影響,下圖是曉衡的遊戲在8月7日 ~ 8月9日時的活躍情況:

遊戲是在8月7日的晚上10:00點打開的微信公測,微信平台在24小時內持續導入5184的用戶,當天遊戲啟動8121次。不過圖片上的數據比較尷尬,公測一過就沒幾個玩家了,但它不是我們要講的重點,我們是用這個時間節點、用戶數量,來看微信小遊戲的啟動性能表現。

iOS啟動概況

Android啟動概況

從圖中看,8月7日這天 iOS 的總啟動時間比 Android 快 3.88 秒,Android 的用戶流失比 iOS 要多 12.55%,這裏重點也不是說 iOS 和 Android 系統那個好,而是看遊戲的啟動時間對首屏打開留存的影響。

這是另一個朋友的遊戲《周車勞盾》在9月14日微信公測4800+用戶,遊戲啟動7000+次,下面是它在9月13~9月15日的啟動概況:

《周車勞盾》的 iOS 首屏打開留存率由於用戶數太少,不太好與 Android 對比,並且朋友說當時遊戲沒有做分包優化。在9月14日公測當天,由於新用戶多,iOS、Android 的啟動速度都不快,在 10 秒左右。從中也可以看出微信小遊戲用戶,以及微信導量用戶,以 Android 屬性為主。

啟動流失分析

下圖是曉衡的遊戲在8月8日公測時的 Android 手機用戶流失分佈情況,統計一共有 893 名流失用戶:

從前面的啟動概況看到,小遊戲啟動進入首屏是在8.38s,我們以9秒為分界線,將上圖分成左右兩部分:

  • 右邊標註綠色線框,是已經進入遊戲后流失的人數,這部分的優化需要美術和策劃同學的幫助。
  • 左邊紅色線框中的用戶,是在遊戲啟動過程中流失掉的共計679人佔76%,而且前4秒流失的最多共543占 60%,如果不計算已經打開首屏的更是高達80%,因此前幾秒它才是我們關心的重點。

曉衡根據平常使用微信的習慣,模擬分析一下前8秒的用戶是大概會是什麼情況走失的,需要注意的一個前題是,這些用戶都是微信導量進入的,絕大多是手滑不小心點到廣告,並不是目標用戶。

  • 第1秒:1秒流失用戶,手滑的機率最大,似乎經過專業訓練,眼、腦、手的速度都非常的快,遊戲是什麼都沒看清就閃人了;
  • 第2秒:2秒流失用戶,與1秒戶大概差不多,只是動作稍慢而已,此時遊戲圖標已經進入視覺系統,但估計比較模糊,瞬間閃人;
  • 第3秒:3秒流失用戶,不僅遊戲圖標已經從視覺系統進入大腦,遊戲名字估計也是能看清楚,但是沒有任何感覺,同樣是條件反射,快速點擊關閉;
  • 第4秒:4秒流失用戶,已經是把遊戲圖標、名字已經完全進入大腦神經迴路,給他反饋的信號是沒有愛,甚至是反感,迅速閃人了。第4秒很關鍵,因為用戶已經有了思考!
  • 第5~6秒:5~6秒流失用戶,認真看完遊戲圖標、名字,以及加載進度,經過大腦綜合反饋,這個遊戲不值得等待,88了!
  • 第7~8秒:7~8秒流失用戶,估計是盯到了遊戲的加載進度,在100%或某個数字上停止下一瞬間,實在是不耐煩了,什麼個鬼遊戲,半天進不去,走了!

以上分析是曉衡的個人YY,僅供參考,這裏要說的是前 3 秒流失的用戶大多是條件反射,很難轉化。當用戶將遊戲圖標、遊戲名稱看清了后,大腦產生了思考,再離開的這對我們來說還有機會爭取,讓他們早點看到遊戲首屏,已經花了這5、6秒了,體驗一下再走!

提升遊戲0.5 ~ 2秒的啟動速度是非常具有價值的,而且小遊戲絕大多數又是 Android 用戶,特別是對需要買量的遊戲來說,時間就是金錢,毫秒必爭。

引擎插件帶來的好處

下面我們再來看看,引擎插件具體在那些場景下會帶來比較明顯的性能提供,盡可能充分利用這個機制呢?

微信公測

對於個人開發者,使用微信公測功能免費送5000流量,一定要利用好這個機會。將首包資源做到盡量小巧,引擎裁剪、圖片壓縮一定要做足,同時盡量選擇使用量較多的引擎版本號(目前曉衡了解到的,使用較多 Cocos Creator 引擎版本號分佈在:2.0.8 ~ 2.0.10、2.1.3、2.2.0,不過還是要以微信或 Cocos 官方統計為準),這樣容易蹭上已經下載過的遊戲引擎,這對大多數遊戲來說都是適用的。

中重度遊戲

中重度遊戲,通常會依賴較多的引擎模塊,比如 RPG 遊戲中的:地圖、角色動畫,會使用TileMap、Spine、DragonBones、Animation 等模塊,還有一些遊戲會使用到物理引擎模塊、碰撞模塊等,完整引擎模塊高達 1.6M。

隨着微信引擎插件的廣泛普及,以後構建遊戲完全時可以將引擎裁剪到最精簡狀態,大概在550K左右。甚至可以想像到,以後小遊戲平台完全不用上傳引擎代碼,構建時只用配置上使用的什麼引擎,引擎版本號即可。

中重度遊戲利用引擎插件同樣可以快速進入首屏,首包僅保留炫麗的動效和初始界面,用分治的方式動態下載遊戲當前必要的內容,儘快讓用戶參与到遊戲中去。還有隨着 5G 的到來,中重度遊戲的遊戲資源下載劣勢也會得到改善,對小遊戲更是一件好事。

遊戲矩陣

單款小遊戲一般是很難有收益的,甚至是虧本買賣。微信平台,一個小遊戲可以支持10個遊戲的跳轉,目前絕大多數遊戲商廠,都會在小遊戲中集成其它遊戲的入口加大流量,優質的遊戲還會出售遊戲跳轉坑位,有的還價格不菲。個人開發者也意識到了遊戲間跳轉帶來的爆光機會,不少開發者會在微信公眾時,組織邀請好友建立鏈接。

如果是自家開發的休閑小遊戲,利用引擎插件的啟動增速,再配合上自定義的啟動背景(頭條支持),讓玩家感受不出是在不同遊戲中切換,在矩陣中瞬間穿梭,這也將極大增加遊戲的曝光率,降低流失。

小結

劉潤老師說的好:“一切的商業價值,要看是否讓用戶獲益”。

微信引擎插件不僅讓普通用戶能獲得更好的遊戲體驗,也能讓遊戲開發商能中從獲益。點開即玩的小遊戲,縮短了遊戲產品呈現在用戶手中的時間,極大優化了產品的傳遞價值。

曉衡是一個搬運工,傳遞有價值的遊戲開發技術,如果覺得本文對你有用,感謝來看個再看或傳遞給朋友。感謝您的閱讀,願我們在前進的道路上“砥礪前行,共同成長!”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

賓士傳將開發四款純電動車

世界級車商賓士(Mercedes-Benz)被報導正在開發全新的電動車平台,並將以此平台為基礎,推出四款純電動汽車。

ETToday引述外媒《Car Magazine》的報導,表示賓士正以MRA平台為基礎開發一款名為「EVA」的電動車平台,可供後續開發C-Class到S-Class尺碼的各式車款,最高能搭載400公斤的電池組。而在動力方面,後驅車型可能搭載一具402匹馬力的電動馬達,四驅車行可能還會再加上一具120匹馬力或者201匹馬力的馬達。主動懸載、扭力分配、動能回收等功能也將面面俱到。

該報導表示,賓士官方並未證實這項消息,但將在2018年推出C-Class與E-Class之間的電動轎車,並以此為基礎再行打造一款休旅車。此後還有S-Class和GLS等級的電動車款會問世。《Car Magazine》表示,賓士目標為每年銷售2萬輛電動車,入門車款售價為7萬英鎊起跳。

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

2016年將推出的那些新能源汽車政策

2016年新能源汽車仍將高速增長,但還存在很多不確定因素,互聯網企業造車、電池企業准入、低速電動車企業能否借機“轉正”等懸念是否能揭曉?2016年,中國還將推出哪些新能源汽車政策?讓我們先來預測一下。

《電動汽車動力蓄電池回收利用技術政策》

狀態:徵求意見

預發佈時間:2016年初

2015年9月11日,國家發展改革委環資司、工業和資訊化部裝備司聯合發佈《電動汽車動力蓄電池回收利用技術政策》(徵求意見稿)。根據徵求意見稿要求,國家將推動建立統一的動力蓄電池產品編碼制度。動力蓄電池生產企業應對所生產(或進口)的所有動力蓄電池產 品進行編碼,並建立追溯系統追蹤動力蓄電池流向。編碼應與電池產品及整車具有惟一對應性,編碼應標識在動力蓄電池產品顯著位置,且具有較高的牢固性。
 

《乘用車企業平均燃料消耗量管理辦法(草稿)》

狀態:草稿階段

預發佈時間:2016年

據悉,《乘用車企業平均燃料消耗量管理辦法(草稿)》已經制定完成,即將徵求意見。草案中最重要的內容是企業 平均燃料消耗量積分轉結及交易制度,不達標企業將有巨額罰款。根據草稿,乘用車企業平均燃料消耗量不達標罰款納入預算內,作為汽車行業節能管理專項資金, 其中40%用於汽車節能管理,60%用於支援企業為改善燃料經濟性而進行的產品研發。

《電動汽車充電介面及通信協定5項國家標準》

實施時間:2016年1月1日

2015年12月28日,質檢總局、國家標準委聯合國家能源局、工信部、科技部在京發佈新修訂的電動汽車 充電介面及通信協定5項國家標準。在交流充電部分,禁止採用存在安全隱患的直通電纜加普通家用插頭的連接方式;針對大於16安培的充電方式強制要求在車輛 插座和供電插座安裝電子鎖和溫度感測器,防止帶電拉弧及過熱引起的設備損壞和火災等事故……

《低速電動汽車管理辦法》

狀態:未發佈

預發佈時間:2016年

工信部、發改委、公安部、環境部等部門已經對低速電動汽車進行調研,統一的“低速電動汽車管理辦法”有望出 台。據瞭解,在山東,僅德州一個地級市,低速電動汽車的年產量超過10萬輛,低速電動車製造行業和配套產業直接為德州市貢獻超過50億元的GDP,提供了 一大批工作崗位。全國低速電動汽車主要分佈于山東、河北、河南等省,湖北、四川、湖南、安徽、江西、山西等省份隨著市場的發展產銷量也在不斷攀升。

《私人用戶居住地充電基礎設施建設管理示範文本(操作指南)》

狀態:徵求意見

預發佈時間:2016年

2015年10月12日,國家能源局在江蘇常州舉辦了“電動汽車充電基礎設施促進聯盟成立暨建設經驗交流現場 會”,會上發佈了《私人用戶居住地充電基礎設施建設管理示範文本(操作指南)》(徵求意見稿)。該意見稿對具備固定車位和不具備固定車位的私人用戶需準備 的材料及建設流程做出了詳細規定,此外對配電容量不足情況、消防驗收方面也有具體要求,具體細節還需進一步調研討論。

《關於“十三五”新能源汽車充電設施獎勵政策及加強新能源汽車推廣應用的通知(徵求意見稿)》

狀態:徵求意見

預發佈時間:2016年上半年

12月15日,財政部、科技部、工業和資訊化部、發展改革委、國家能源局聯合發佈《關於“十三五”新能源汽車 充電設施獎勵政策及加強新能源汽車推廣應用的通知(徵求意見稿)》。徵求意見稿明確了拿到獎勵的門檻,例如:大氣污染治理重點區域和重點省市(包括北京、 上海、天津、河北、山西、江蘇、浙江、山東、廣東、海南),2016~2020年度新能源汽車(標準車,下同)推廣數量分別不低於3萬輛、3.5萬輛、 4.3萬輛、5.5萬輛、7萬輛,且推廣的新能源汽車數量占本地區新增及更新的汽車總量比例不低於3%、4%、5%、8%、10%。此外,還明確了新能源標準車折算關係,例如純電動乘用車(續駛里程(參配、圖片、詢價) ≥150km)與標準車折算比例為1:1等。
 

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

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

.NET Core 3.0 單元測試與 Asp.Net Core 3.0 集成測試

單元測試與集成測試

測試必要性說明

相信大家在看到單元測試與集成測試這個標題時,會有很多感慨,我們無數次的在實踐中提到要做單元測試、集成測試,但是大多數項目都沒有做或者僅建了項目文件。這裡有客觀原因,已經接近交付日期了,我們沒時間做白盒測試了。也有主觀原因,面對業務複雜的代碼我們不知道如何入手做單元測試,不如就留給黑盒測試吧。但是,當我們的代碼無法進行單元測試的時候,往往就是代碼開始散發出壞味道的時候。長此以往,將欠下技術債務。在實踐過程中,技術債務常常會存在,關鍵在於何時償還,如何償還。

上圖說明了隨着時間的推移開發/維護難度的變化。

測試框架選擇

在 .NET Core 中,提供了 xUnit 、NUnit 、 MSTest 三種單元測試框架。

MSTest UNnit xUnit 說明 提示
[TestMethod] [Test] [Fact] 標記一個測試方法
[TestClass] [TestFixture] n/a 標記一個 Class 為測試類,xUnit 不需要標記特性,它將查找程序集下所有 Public 的類
[ExpectedException] [ExpectedException] Assert.Throws 或者 Record.Exception xUnit 去掉了 ExpectedException 特性,支持 Assert.Throws
[TestInitialize] [SetUp] Constructor 我們認為使用 [SetUp] 通常來說不好。但是,你可以實現一個無參構造器直接替換 [SetUp]。 有時我們會在多個測試方法中用到相同的變量,熟悉重構的我們會提取公共變量,並在構造器中初始化。但是,這裏我要強調的是:在測試中,不要提取公共變量,這會破壞每個測試用例的隔離性以及單一職責原則。
[TestCleanup] [TearDown] IDisposable.Dispose 我們認為使用 [TearDown] 通常來說不好。但是你可以實現 IDisposable.Dispose 以替換。 [TearDown] 和 [SetUp] 通常成對出現,在 [SetUp] 中初始化一些變量,則在 [TearDown] 中銷毀這些變量。
[ClassInitialize] [TestFixtureSetUp] IClassFixture< T > 共用前置類 這裏 IClassFixture< T > 替換了 IUseFixture< T > ,
[ClassCleanup] [TestFixtureTearDown] IClassFixture< T > 共用後置類 同上
[Ignore] [Ignore] [Fact(Skip=”reason”)] 在 [Fact] 特性中設置 Skip 參數以臨時跳過測試
[Timeout] [Timeout] [Fact(Timeout=n)] 在 [Fact] 特性中設置一個 Timeout 參數,當允許時間太長時引起測試失敗。注意,xUnit 的單位時毫秒。
[DataSource] n/a [Theory], [XxxData] Theory(數據驅動測試),表示執行相同代碼,但具有不同輸入參數的測試套件 這個特性可以幫助我們少寫很多代碼。

以上寫了 MSTest 、UNnit 、 xUnit 的特性以及比較,可以看出 xUnit 在使用上相對其它兩個框架來說提供更多的便利性。但是這裏最終實現還是看個人習慣以選擇。

單元測試

  1. 新建單元測試項目

  2. 新建 Class

  3. 添加測試方法

            /// <summary>
            /// 添加地址
            /// </summary>
            /// <returns></returns>
            [Fact]
            public async Task Add_Address_ReturnZero()
            {
                DbContextOptions<AddressContext> options = new DbContextOptionsBuilder<AddressContext>().UseInMemoryDatabase("Add_Address_Database").Options;
                var addressContext = new AddressContext(options);
    
                var createAddress = new AddressCreateDto
                {
                    City = "昆明",
                    County = "五華區",
                    Province = "雲南省"
                };
                var stubAddressRepository = new Mock<IRepository<Domain.Address>>();
                var stubProvinceRepository = new Mock<IRepository<Province>>();
                var addressUnitOfWork = new AddressUnitOfWork<AddressContext>(addressContext);
    
                var stubAddressService = new AddressServiceImpl.AddressServiceImpl(stubAddressRepository.Object, stubProvinceRepository.Object, addressUnitOfWork);
                await stubAddressService.CreateAddressAsync(createAddress);
                int addressAmountActual = await addressContext.Addresses.CountAsync();
                Assert.Equal(1, addressAmountActual);
            }
    • 測試方法的名字包含了測試目的、測試場景以及預期行為。
    • UseInMemoryDatabase 指明使用內存數據庫。
    • 創建 createAddress 對象。
    • 創建 Stub 。在單元測試中常常會提到幾個概念 Stub , Mock 和 Fake ,那麼在應用中我們該如何選擇呢?
      • Fake – Fake 通常被用於描述 Mock 或 Stub ,如何判斷它是 Stub 還是 Mock 依賴於使用上下文,換句話說,Fake 即是 Stub 也是 Mock 。
      • Stub – Stub 是系統中現有依賴項的可控替代品。通過使用 Stub ,你可以不用處理依賴直接測試你的代碼。默認情況下, 偽造對象以stub 開頭。
      • Mock – Mock 對象是系統中的偽造對象,它決定單元測試是否通過或失敗。Mock 會以 Fake 開頭,直到被斷言為止。
    • Moq4 ,使用 Moq4 模擬我們在項目中依賴對象。
  4. 打開視圖 -> 測試資源管理器。

  5. 點擊運行,得到測試結果。

  6. 至此,一個單元測試結束。

集成測試

集成測試確保應用的組件功能在包含應用的基礎支持下是正確的,例如:數據庫、文件系統、網絡等。

  1. 新建集成測試項目。

  2. 添加工具類 Utilities 。

    using System.Collections.Generic;
    using AddressEFRepository;
    
    namespace Address.IntegrationTest
    {
        public static class Utilities
        {
            public static void InitializeDbForTests(AddressContext db)
            {
                List<Domain.Address> addresses = GetSeedingAddresses();
                db.Addresses.AddRange(addresses);
                db.SaveChanges();
            }
    
            public static void ReinitializeDbForTests(AddressContext db)
            {
                db.Addresses.RemoveRange(db.Addresses);
                InitializeDbForTests(db);
            }
    
            public static List<Domain.Address> GetSeedingAddresses()
            {
                return new List<Domain.Address>
                {
                    new Domain.Address
                    {
                        City = "貴陽",
                        County = "測試縣",
                        Province = "貴州省"
                    },
                    new Domain.Address
                    {
                        City = "昆明市",
                        County = "武定縣",
                        Province = "雲南省"
                    },
                    new Domain.Address
                    {
                        City = "昆明市",
                        County = "五華區",
                        Province = "雲南省"
                    }
                };
            }
        }
    }
  3. 添加 CustomWebApplicationFactory 類,

     using System;
     using System.IO;
     using System.Linq;
     using AddressEFRepository;
     using Microsoft.AspNetCore.Hosting;
     using Microsoft.AspNetCore.Mvc.Testing;
     using Microsoft.EntityFrameworkCore;
     using Microsoft.Extensions.Configuration;
     using Microsoft.Extensions.DependencyInjection;
     using Microsoft.Extensions.Logging;
    
     namespace Address.IntegrationTest
     {
         public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
         {
             protected override void ConfigureWebHost(IWebHostBuilder builder)
             {
                 string projectDir = Directory.GetCurrentDirectory();
                 string configPath = Path.Combine(projectDir, "appsettings.json");
                 builder.ConfigureAppConfiguration((context, conf) =>
                 {
                     conf.AddJsonFile(configPath);
                 });
    
                 builder.ConfigureServices(services =>
                 {
                     ServiceDescriptor descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AddressContext>));
    
                     if (descriptor != null)
                     {
                         services.Remove(descriptor);
                     }
    
                     services.AddDbContextPool<AddressContext>((options, context) =>
                     {
                         //var configuration = options.GetRequiredService<IConfiguration>();
                         //string connectionString = configuration.GetConnectionString("TestAddressDb");
                         //context.UseMySql(connectionString);
                         context.UseInMemoryDatabase("InMemoryDbForTesting");
    
                     });
    
                     // Build the service provider.
                     ServiceProvider sp = services.BuildServiceProvider();
                     // Create a scope to obtain a reference to the database
                     // context (ApplicationDbContext).
                     using IServiceScope scope = sp.CreateScope();
                     IServiceProvider scopedServices = scope.ServiceProvider;
                     var db = scopedServices.GetRequiredService<AddressContext>();
                     var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
    
                     // Ensure the database is created.
                     db.Database.EnsureCreated();
    
                     try
                     {
                         // Seed the database with test data.
                         Utilities.ReinitializeDbForTests(db);
                     }
                     catch (Exception ex)
                     {
                         logger.LogError(ex, "An error occurred seeding the " + "database with test messages. Error: {Message}", ex.Message);
                     }
                 });
             }
         }
     }
    • 這裏為什麼要添加 CustomWebApplicationFactory 呢?
      WebApplicationFactory 是用於在內存中引導應用程序進行端到端功能測試的工廠。通過引入自定義 CustomWebApplicationFactory 類重寫 ConfigureWebHost 方法,我們可以重寫我們在 StartUp 中定義的內容,換句話說我們可以在測試環境中使用正式環境的配置,同時可以重寫,例如:數據庫配置,數據初始化等等。
    • 如何準備測試數據?
      我們可以使用數據種子的方式加入數據,數據種子可以針對每個集成測試做數據準備。
    • 除了內存數據庫,還可以使用其他數據庫進行測試嗎?
      可以。
  4. 添加集成測試 AddressControllerIntegrationTest 類。

     using System.Collections.Generic;
     using System.Linq;
     using System.Net.Http;
     using System.Threading.Tasks;
     using Address.Api;
     using Microsoft.AspNetCore.Mvc.Testing;
     using Newtonsoft.Json;
     using Xunit;
    
     namespace Address.IntegrationTest
     {
         public class AddressControllerIntegrationTest : IClassFixture<CustomWebApplicationFactory<Startup>>
         {
             public AddressControllerIntegrationTest(CustomWebApplicationFactory<Startup> factory)
             {
                 _client = factory.CreateClient(new WebApplicationFactoryClientOptions
                 {
                     AllowAutoRedirect = false
                 });
             }
    
             private readonly HttpClient _client;
    
             [Fact]
             public async Task Get_AllAddressAndRetrieveAddress()
             {
                 const string allAddressUri = "/api/Address/GetAll";
                 HttpResponseMessage allAddressesHttpResponse = await _client.GetAsync(allAddressUri);
    
                 allAddressesHttpResponse.EnsureSuccessStatusCode();
    
                 string allAddressStringResponse = await allAddressesHttpResponse.Content.ReadAsStringAsync();
                 var addresses = JsonConvert.DeserializeObject<IList<AddressDto.AddressDto>>(allAddressStringResponse);
                 Assert.Equal(3, addresses.Count);
    
                 AddressDto.AddressDto address = addresses.First();
                 string retrieveUri = $"/api/Address/Retrieve?id={address.ID}";
                 HttpResponseMessage addressHttpResponse = await _client.GetAsync(retrieveUri);
    
                 // Must be successful.
                 addressHttpResponse.EnsureSuccessStatusCode();
    
                 // Deserialize and examine results.
                 string addressStringResponse = await addressHttpResponse.Content.ReadAsStringAsync();
                 var addressResult = JsonConvert.DeserializeObject<AddressDto.AddressDto>(addressStringResponse);
                 Assert.Equal(address.ID, addressResult.ID);
                 Assert.Equal(address.Province, addressResult.Province);
                 Assert.Equal(address.City, addressResult.City);
                 Assert.Equal(address.County, addressResult.County);
             }
         }
     }
  5. 在測試資源管理器中運行集成測試方法。

  6. 結果。

  7. 至此,集成測試完成。需要注意的是,集成測試往往耗時比較多,所以建議能使用單元測試時就不要使用集成測試。

總結:當我們寫單元測試時,一般不會同時存在 Stub 和 Mock 兩種模擬對象,當同時出現這兩種對象時,表明單元測試寫的不合理,或者業務寫的太過龐大,同時,我們可以通過單元測試驅動業務代碼重構。當需要重構時,我們應盡量完成重構,不要留下欠下過多技術債務。集成測試有自身的複雜度存在,我們不要節約時間而打破單一職責原則,否則會引發不可預期後果。為了應對業務修改,我們應該在業務修改以後,進行回歸測試,回歸測試主要關注被修改的業務部分,同時測試用例如果有沒要可以重寫,運行整個和修改業務有關的測試用例集。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

variable precision SWAR算法

      計算二進制形式中1的數量這種問題,在各種刷題網站上比較常見,以往都是選擇最笨的遍歷方法“矇混”過關。在了解Redis的過程中接觸到了variable precision SWAR算法(以下簡稱VP-SWAR算法),算法異常簡潔,是目前已知的同類方法中最快的。但如果對於位運算不是很熟悉的話,卻不一定容易理解,所以有必要記錄一下。

      下面先看看VP-SWAR算法的完整實現,然後再逐行解釋。

  public int vpSWAR(int i){
    i = (i & 0x55555555) + ((i>>1) & 0x55555555);
    i = (i & 0x33333333) + ((i>>2) & 0x33333333);
    i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F);
    i = (i * 0x01010101) >> 24;
    return i;
  }

      VP-SWAR算法分為四步,第一步

i = (i & 0x55555555) + ((i>>1) & 0x55555555);

      第一步的作用是計算每兩位為一組的二進制形式包含1的個數。要理解這句話,我們需要從二進制的角度看看到底發生了什麼。首先, 0x55555555 的二進製表示為 0101 0101 0101 0101 0101 0101 0101 0101 ,這個数字的規律是基數位為1,偶數位為0。為簡單起見,我們只考慮兩位,總共有四種情況,即:

 

i b i & b 結果
00 01 00
01 01 01
10 01 00
11 01 01

       觀察發現, i & (0b01) 是i的基數位對應b的1位,i的偶數位對應着b的0位, i & (0b01) 的結果會將I的偶數位置為0,而基數位保持不變,得到的結果就是i的基數位包含1的個數。 (i >> 1) & 0x55555555 先將i右移一位,也就是將i的基數位對應b的0位,i的偶數位對應着b的1位,然後再與 0x55555555 按位與,計算出來的是i的偶數位包含1的個數。兩個計算結果相加就得到i每兩位為一組中包含的1的數量,我們最後需要的就是這每兩位一組的和。

      第二步是在第一步的基礎上,計算每四位為一組包含1的個數。按照每2位為一組分組用到了 0x55555555 這個數,那麼自然的,按照每4位為一組分組自然就需要 0b0011 這種形式,這就是使用 0x33333333 的原因。理論上, i & (0b0011) 總共有16種情況,但是四位二進制位最多包含4個1,用二進製表示為 0b0100 ,所以經過第一步之後,i最多有5種取值,如下:

i b i & b 結果
0000 0011 0000
0001 0011 0001
0010 0011 0010
0011 0011 0011
0100 0011 0000

 

      觀察發現, i & (0b0011) 得到的是i的低兩位包含的1的個數,  (i >> 2) & 0b0011 )得到的是i的高兩位包含的1的個數,兩個結果相加得到每四位包含的1的個數。注意,這裏並不是說任何數與 0b0011 按位與得到的都是低兩位包含的1的個數,這裏的前提是第一步的計算,因為經過第一步計算之後,每兩位包含多少個1已經記錄了下來,再和 0b0011 按位與才得到正確的結果。例如, 0x0010 & 0x 0011=0x0010 ,但是我們不能說 0x0010 包含兩個1,但是如果 0x0010 是經過第一步的計算得來,那才說明 0x0010 記錄原始數據低兩位有兩個1。

      第三步在第二步基礎上,計算每8位有多少個1,由 0x010x0011 ,很自然想到 0x00001111 ,其對應的32位的十六進制數就是 0x0F0F0F0F

      第四步就很有意思了,它不再是計算每16位包含1的個數,而是直接計算32位包含1的個數。對於32位的數來說,可以將其按每8位一組分為4組,分別用ABCD表示,例如 0x01020304 用這種形式表示為:

 

 

      假設 0x01020304 是經過前三步計算之後得到的結果,那麼要計算其總共包含多少個1,只需計算A+B+C+D。而ABCD表示的是不同的位區間範圍,不能直接相加,該如何快速計算A+B+C+D的值呢?這裏又用到了移位運算,將B、C、D分別左移8位、16位、24位,使其分別與A對齊:

 

       我們發現,將数字i分別左移0位、8位、16位、24位然後相加的結果,就是 i * 0x01010101 ,因為 i + (i << 8) + (i << 16) + (i << 24) = i * (1 + 1 << 8 + 1 << 16 + 1 << 24) = i * 0x01010101 。對於32位数字來說,左移之後超過32位的部分會被捨棄,低位補0,將左移之後得到的四個数字相加,結果的高8位的值就是原32位數包含的1的個數,要得到這個值,只需要將結果右移24位,將值放在低8位即可。

      到這裏,整個算法就結束了,右移的結果就是1的數量。在Redis中,BITCOUNT命令同時使用了查表法和VP-SWAR這兩種方法。當要計算的位數小於128位時,使用查表法,否則使用VP-SWAR算法。其中查表法的做法是,程序先存一個256長度的表,按順序記錄從0-255(即 0b00000000 – 0b11111111) 數中二進制1的個數,然後對於輸入參數每8位查一次表。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

SQlALchemy session詳解

系列文章:

概念

session用於創建程序和數據庫之間的會話,所有對象的載入和保存都需通過session對象 。

通過sessionmaker調用創建一個工廠,並關聯Engine以確保每個session都可以使用該Engine連接資源:

from sqlalchemy.orm import sessionmaker

# 創建session
DbSession = sessionmaker(bind=engine)
session = DbSession()

操作

session的常見操作方法包括:

  1. flush:預提交,提交到數據庫文件,還未寫入數據庫文件中
  2. commit:提交了一個事務,把內存的數據直接寫入數據庫
  3. rollback:回滾
  4. close:關閉

在事務處理時,需注意一下兩點:

  1. 在事務處理過程發生異常時,進行rollback操作,否則會在下次操作時報錯:
Can’t reconnect until invalid transaction is rolled back 
  1. 一般情況下,在一個事務處理完成之後要關閉session,以確保數據操作的準確性。

建議封裝上下文方法:

from contextlib import contextmanager

@contextmanager
def session_maker(session=session):
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

調用:

def update_user():
    with session_maker() as db_session:
        db_session.query(Users).filter_by(name='test2').update({'email': 'test2@qq.com'})

線程安全

session不是線程安全的,並且我們一般session對象都是全局的,那麼在多線程情況下,當多個線程共享一個session時,數據處理就會發生錯誤。

為了保證線程安全,需使用scoped_session方法:

db_session = scoped_session(sessionmaker(bind=engine))

內部原理

session對象包含了三個重要的部分:

  1. 標識映射(Identity Map)
  2. 對象的狀態 / 狀態跟蹤
  3. 事務

標識映射

標識映射是與ORM關聯的集合,通過標識映射保證了數據庫操作的準確性。

具體的實現原理是:維護一個Python字典(IdentityMap),關聯這個Session對象到數據庫ID的映射,當應用程序想要獲取一個session對象時,若該對象不存在,標識映射會加載該對象並緩存,若該對象已存在,則直接獲取。這樣的好處是:

  1. 已經被請求過的session對象緩存下來,不需要連接加載多次,造成額外的開銷;
  2. 避免了數據不一致

狀態跟蹤

一個Session對象從創建到銷毀,依次經歷四種狀態,分別是:

  1. Transient:剛new出來的對象,還不在會話中,也沒有保存到數據庫。
  2. Pending:transient的對象調用add后,就會變成pending狀態,這時會加入sqlalchemy的監管範圍,數據並未更新到數據庫。
  3. Persistent:該狀態表明數據庫里已經記錄了該對象,在兩種情況下對象處於該狀態:一是通過flush()方法刷新pending對象,二是從數據庫query()得到對象。
  4. Detached:在會話中的事務提交之後,所有的對象都將是Detached狀態。

所謂的狀態跟蹤,就是跟蹤以上四個狀態,保證數據的準確性並在合理的時機丟棄對象以保證合理開銷,那麼具體是怎麼實現的呢?

我們可以看到,只有在pending狀態時,對象的內存數據和數據庫中的數據不一致,在Persistent狀態時,內存數據和數據庫數據已經一致,那麼此後任意時刻丟棄該對象數據都是可以的,這時就需要找個合適的時機丟棄對象,過早或過晚都有其缺陷。於是,就讓垃圾回收器來做決定,在內存不夠的時候釋放對象,回收內存。

Session對象採用了弱引用機制,所謂弱引用,就是說,在保存了對象的引用的情況下,對象仍然可能被垃圾回收器回收。在某一時刻通過引用訪問對象時,對象可能存在也可能不存在,如果對象不存在,就重新從數據庫中加載對象。而如果不希望對象被回收,只需要另外保存一個對象的強引用即可 。

session對象包括三個屬性:

  1. new:剛加入會話的對象
  2. dirty:剛被修改的對象
  3. deleted:在會話中被刪除的對象

三個屬性共同的特點就是內存的數據和數據庫數據不一致,也就是對象處於pending狀態,這也就表明了session保存了所有對象處於pending狀態的強引用。

以上。

代碼可參照:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

spring 是如何注入對象的和bean 創建過程分析

文章目錄:

  1. 【本文】spring 是如何注入對象的

首先需要知道一個大致實現

  • 這個注入過程肯定是在 BeanPostProcessor 中實現的

  • spring 是在 beanFactory.getBean 進行 bean 實例化的,即懶加載

  • 根據第二條,也就是說在 getBean 的時候才會去調用所有 BeanPostProcessor

  • 第二篇文章說到,BeanFactory 的 refresh 過程只是註冊 BeanPostProcessor,真正執行在 getBean 方法中

  • MergedBeanDefinitionPostProcessor 也是一種 BeanPostProcessor 它重新弄了個一個生命周期函數,替代了 BeanPostProcessor 默認的生命周期函數,這麼看吧,我貼一小段源碼

    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }

    它允許你在非 BeanFactoryProcess 中去修改 Bean 定義

  • InstantiationAwareBeanPostProcessor 也是一種 BeanPostProcessor 它也重新定義了一個生命周期函數,它允許把屬性值注入到屬性對象中

@Autowired 加載定義的過程

我們先不看 bean 的創建過程,就看 MergedBeanDefinitionPostProcessor 的實現子類,這裏看名字猜測 AutowiredAnnotationBeanPostProcessor 應該就是干這件事的,所以我們接下來可以直接看 AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition 方法的代碼。

順着方法的調用,可以知道在 buildAutowiringMetadata 是真正查找這些註解的地方,最後 checkConfigMembersMember 註冊進了 bean 定義,具體如何查找的讀者自行查看源碼。

這裏只是將 Member 註冊進了 bean 定義,真正實例化在填充 Bean 的過程中,下面說到 bean 的創建過程可以知道是何時注入的。

Bean 的創建過程

前面說到 spring 是在 getBean 的過程中進行 Bean 創建的,創建 bean 分為幾個步驟

  1. 獲取 bean 定義
  2. new Bean()
  3. 執行生命周期函數 (前)
  4. 創建依賴項
  5. 填充 bean
  6. 執行生命周期函數(后)

入口為 BeanFactory.getBean ,BeanFactory 的實現類為 DefaultListableBeanFactory 這些你可以在 BeanFactory 的 refresh 過程中找到

根據源碼,如果 bean 還不存在時,就會執行 bean 的創建流程

獲取 bean 定義在這段源碼中

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

緊跟着,根據 Bean 定義搜索其依賴項,並創建 bean ,可以看出是遞歸創建 bean

String[] dependsOn = mbd.getDependsOn();
for (String dep : dependsOn) {
    getBean(dep);
}

然後就創建 bean 了

if (mbd.isSingleton()) {
    createBean(beanName, mbd, args);
}

// 真正的執行在 doCreateBean 過程中
Object beanInstance = doCreateBean(beanName, mbdToUse, args);

創建 bean 第一步 new Bean

if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}

創建 bean 第二步,執行所有的 processor ,包含 MergedBeanDefinitionPostProcessor ,所以在這一步註冊注入選項

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

創建 bean 第三步,填充 bean ,這裏做的 @Autowired 注入

populateBean(beanName, mbd, instanceWrapper);

最終的處理過程在 AutowiredAnnotationBeanPostProcessor 的 postProcessPropertyValues 函數中

metadata.inject(bean, beanName, pvs);

因為在前面已經獲取過依賴項,並且把其丟進了容器,所以這裡是直接用反射寫進去就可以了

創建 bean 第四步,初始化 bean ,這裡有一個方法注入,方法注入原來發生在初始化 bean 過程中,還有就是生命周期函數執行了,包含 BeanPostProcessor 的前置後置生命周期,初始化方法等

小說明 :AutowiredAnnotationBeanPostProcessor 即是 一個 MergedBeanDefinitionPostProcessor 也是一個 InstantiationAwareBeanPostProcessor

一點小推廣

創作不易,希望可以支持下我的開源軟件,及我的小工具,歡迎來 gitee 點星,fork ,提 bug 。

Excel 通用導入導出,支持 Excel 公式
博客地址:
gitee:

使用模板代碼 ,從數據庫生成代碼 ,及一些項目中經常可以用到的小工具
博客地址:
gitee:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

《中國電動汽車標準化工作線圖》將於近日發佈

1月11日,《中國電動汽車標準化工作路線圖》評審會在北京召開。《路線圖》由中國汽車技術研究中心等單位聯合制定,將於近日發佈。

路線圖的定位

本版路線圖的起止階段為2015年至2025年,通過對2015年至2025年電動汽車及其相關產業的技術發展、產業化和市場化發展的判斷和預測,制定2015年至2025年中國電動汽車標準化工作的具體目標和工作計畫。在對國內外電動汽車標準和法規進行總結和歸納的基礎上,著重分析和研究中國電動汽車在未來的10年中,電動汽車及其相關產業的技術發展、產業化和市場化發展的標準需求,以此作為中國電動汽車快速健康發展的主要技術支撐。路線圖中標準化工作實施期限分為:緊急(2015年1月至2015年12月)、短期(2016年1月至2017年12月)、中期(2018年1月至2020年12月)和長期(2021年1月至2025年12月)共4個階段。由上述內容構成的本路線圖,將成為指導從2015年至2025年中國電動汽車標準化工作的綱領性檔。

路線圖的範圍

a)電動車輛:純電動汽車、混合動力電動汽車(包括插電式和增程式)、燃料電池電動汽車以及電動車輛相關零部件等;

b)基礎設施:充電樁、充電站、換電站和加氫站等;

c)相關產業:電動汽車及電池的運輸、回收利用、教育培訓、搶險救援等。

d) 本路線圖覆蓋基礎設施和相關產業的建設、運營、管理等。

路線圖的目標

路線圖的目標是有目的、有計劃、有步驟地建立起聯繫緊密、相互協調、層次分明、構成合理、相互支持、滿足應用需求的整體性、系統性、開放性的電動汽車標準體系,加速制定一系列由標準體系確定的具體標準,從而降低研究、生產、使用、維護及管理的成本和風險,使標準化工作發揮最佳效益,支撐和引導我國電動汽車產業的技術創新和快速發展,即:

——提出系統、科學的電動汽車標準體系;

——提出未來十年需要制修訂的標準專案;

——提出我國電動汽車標準及體系建設的實施步驟;

——促進科技創新;

——改變能源結構和推動節能減排;

——促進電動汽車大規模產業化;

——滿足科研、產業化、市場化運行和政府管理的需要;

——積極參與國際標準化工作,爭取中國標準走向世界。

路線圖的實施

通過對國內外電動汽車標準化工作的現狀的分析,為了滿足電動汽車產業的發展,未來標準的缺項進行了梳理,路線圖將通過表格和圖形的形式,對標準缺項進行系統的整理,按照時間序列來闡述從2015年1月至2025年12月共11年的標準制定計劃,計畫為4個階段(優先順序),分為緊急(2015年1月至2015年12月)、短期(2106年1月至2017年12月、中期(2018年1月至2020年12月)、長期(2021年1月至2025年12月)。

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!