機油怎麼分好壞?教授親自帶你到歐洲看機油研發過程

實測:在發動機測試實里我們看到各種不同的發動機,所有機油在路試之前都要在這裏分別進行100小時高溫測試、冷機潤滑性能測試、模擬實際使用情況長測,以及整車測試等。在探訪過程中我們還發現了送測的日產雷諾新1。6T機器,整車合作廠家會把最新的發動機送來研發中心,因應發動機的特性開發專用機油並加以改進,所以所謂品牌專用機油和市場上買到的還真是有區別。

說起汽車機油,相信大家都知道每次保養時需要更換,但不同機油之間的差別,好像一般用家不會太在意。比較資深的老司機會知道機油有合成、礦物油之分,也知道機油有不同標號、等級之分,但怎麼選擇一款最適合自己愛車的機油,一款好機油的技術含量有多高,你又知道多少?

在出發前,我們先掃一下盲。

發動機裏面有無數金屬部件在運動,運動過程中會產生摩擦,就好像人的關節一樣,使用了不良或是不合適的機油,發動機就好像得了關節炎一樣,運動不順暢,久而久之,甚至會得大病。

機油具有潤滑、清潔、冷卻、密封、減磨、防鏽 的功能。因此選擇機油是不能馬虎的。

Jacky 此次特意飛往來自法國的品牌—道達爾的集團總部参觀學習,給大家窺探一款優異的機油的研發過程。

什麼?只聽過殼牌、美孚、嘉實多?那你就Out 了!

道達爾是世界第四大石油天然氣公司,業務遍及130多個國家。

在汽車賽事方面,道達爾一直活躍於國內外頂級賽車運動的賽場上,在頂級的賽車運動場上始終能看到道達爾的身影,如一級方程式錦標賽(F1)、世界拉力錦標賽(WRC)、世界耐力錦標賽(WEC)、以及勒芒24小時耐力賽、達喀爾拉力賽(Dakar)。

亞洲勒芒系列賽事(ALMS)、世界房車錦標賽(WTCC)、中國越野拉力賽(CGR)、絲綢之路拉力賽(Silk Way Rally)等其它著名賽事。通過這些頂級賽事,道達爾的產品性能(潤滑油和燃油)在非常嚴苛的環境下都得到了驗證。

到底一款優良的機油是怎樣研發的呢?第一站我們來到了位於里昂近郊的道達爾Soliaze研發中心。

在這裏每年有超過1200種不同特性的潤滑油誕生。

機油研發分為調配、試驗、分析、實測幾個重要步驟:

調配:因應不同的訴求,加入不同的添加劑來達到相應的效果,你所使用的機油和F1車隊使用的機油都是在同一個實驗室由同一幫工程師調配出來的。

試驗:調和好的機油會送到實驗室進行高溫、低溫、各種耐久測試,這裏的溫度控制精度必須達到小數點后2位,因為實驗室屬於整個生產流程的最頂端,不能允許有任何誤差。在這裏我們也看到了標緻和雷諾的廠家機油測試標準,比一般的歐標和美標都要更嚴格一些。

實測:在發動機測試實里我們看到各種不同的發動機,所有機油在路試之前都要在這裏分別進行100小時高溫測試、冷機潤滑性能測試、模擬實際使用情況長測,以及整車測試等。在探訪過程中我們還發現了送測的日產雷諾新1.6T機器,整車合作廠家會把最新的發動機送來研發中心,因應發動機的特性開發專用機油並加以改進,所以所謂品牌專用機油和市場上買到的還真是有區別。

在巴黎車展上,我們看到了道達爾贊助的雷諾F1賽車、標緻3008 DKR 賽車和208WRX 賽車,在208 WRX 的宣傳片上我甚至看到添加道達爾快馳潤滑油的片段,所以我很好奇到底賽用機油跟我們民用機油的相似度有多少。

為此我特意來到了道達爾集團位於巴黎的總公司,和他們的拉力和耐力賽經理聊了一下。

道達爾多年來积極支持各大國際知名賽事,如世界房車錦標賽WTCC、世界耐力錦標賽WEC、世界拉力錦標賽WRC,一級方程式比賽F1等等,併為贊助車隊提供高品質的潤滑油產品和技術支持。

這些參賽車輛在運行過程中擁有非常高的轉速,這樣的環境對賽車發動機及潤滑油都有着嚴苛的考驗,所以賽車用油或多或少都與民用油有所不同,尤其是像F1這樣對速度要求十分高的賽事,所需的機油和民用油差別則更大,但在賽事嚴苛的使用環境中,機油可以得到深度的測試,賽後進行樣本分析,再把數據應用到民用產品當中。

和賽事中純性能取向不同,一款良好的民用機油應該具備以下特性,我們可以拿道達爾快馳9000 5W-40汽車潤滑油舉個例子:

它有哪些特性呢?:

1、全合成產品,性能穩定可本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

都是今年新上市的合資SUV,法系雙雄怎麼選?

6T、1。8T兩套渦輪增壓發動機,與之配合的是一款6速手自一體變速箱,前者最大馬力167匹,峰值扭矩245牛米。後者最大馬力204匹,峰值扭矩280牛米。兩台車型的調校特性取向有着較大差異。科雷傲“自吸+CVT”的搭配很明顯在舒適度和平順性上要比標緻4008“渦輪+手自一體”的搭配要好一些,也許會有人擔心出自日產平台的科雷傲底盤會不會顯得單薄,根據科雷嘉與逍客(同樣出自CMF平台)的差異來看,雷諾在車輛調校上會更加註重底盤的緊繃感,底盤尋跡性和整合性的提升會讓科雷嘉更像一台歐系車,相信與奇駿同平台但不同品

前言

SUV車型的上市永遠不缺乏關注度,伴隨着現在越來越多的人選擇城市SUV,各大車企推出SUV產品的頻率和數量都在增加,除了打價格戰、配置戰之外,某些不甘於平凡的車型玩起了設計與個性的主題,在外觀上做足了功夫。

法系車的存在一直以來都給人以外觀個性設計前衛的印象,在今年兩大法系品牌雷諾和標緻分別推出了旗下定位較為高端的科雷傲和4008,這兩款SUV也是很多對於購車崇尚“不跟隨”觀念的消費者非常關注的對象,那麼,同樣打“個性牌”的兩款SUV會碰撞出怎樣的火花?

外觀:收斂VS誇本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

10萬出頭就能買到這些會自己開尾門的SUV了

68萬點評:北汽幻速S6最吸引人的,就莫過於那原創度極高的外觀了,在模仿化嚴重的汽車市場難能可貴,還是就是它達到2700mm的軸距,接近4。7米長的車身長度,使其擁有很寬敞的乘坐空間,全景影像、併線輔助、車道偏離預警、自動駐車、座椅加熱、這麼豐富的配置居然出現在11萬多的車型上,性價比超高。

不知道你有沒有經歷過這樣的尷尬時刻

雨水天氣開車子出去後車身有可能沾滿泥巴

再去後備拿東西的時候就不願下手了

如果這時候你的車子有電動尾門

你只需輕輕的按一下鑰匙

或者用腳掃一下車底

就很好的解決你搬東西解放不了雙手

或者要打開沾滿灰塵的後備箱的問題了

一般這麼屌的配置在合資SUV上也要20萬以上

現在越來越牛掰的自主品牌車型10幾萬就有所配備了

眾泰T600

指導價:7.98-14.98萬

點評:定位於家用SUV的眾泰T600,可謂是一個“高大全”,高顏值、空間大、配置豐富,推出的運動版車型無論是外觀還是內飾都兼顧着時尚與運動的元素,2.0T的動力雖說不能給你多大的激情但是日常家用已經足夠,加之調校舒適的底盤和實惠的價格讓人很容易接受。

北汽幻速S6

指導價:7.98-11.68萬

點評:北汽幻速S6最吸引人的,就莫過於那原創度極高的外觀了,在模仿化嚴重的汽車市場難能可貴,還是就是它達到2700mm的軸距,接近4.7米長的車身長度,使其擁有很寬敞的乘坐空間,全景影像、併線輔助、車道偏離預警、自動駐車、座椅加熱、這麼豐富的配置居然出現在11萬多的車型上,性價比超高。

東南DX7

指導價:9.69-13.99萬

點評:外觀由著名的賓尼法利納所設計的東南DX7,看上去是給人非常洋氣的感覺,內飾做工用料也是相當的高大上,浮雕式的中控台很有設計感,豐富的配置讓它有着很強的競爭力,後排的空間表現在同級別車型來說非常出色,擴展性好;且車輛整體調校偏向於舒適,有着很好的駕乘感受。

總結:以上三款車型都擁有着高顏值的外觀,還有內飾中控無論是造型設計還是用料,都有着很高的水準,其次配置上非常豐富,空間也足夠寬敞,動力日常足夠,都是性價比很高的車型。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

10萬級顏值數一數二!這款合資三廂車還很好開?

而在SpORT模式下,它的動力輸出變得激進,變速箱的換擋時機更靠後、開起來相當的“沖”。而ECO模式下,變速箱會把發動機的轉速緊緊控制在3000轉以下,動力響應變得遲緩一點。領動的底盤其實還是比較有韌性的,雖然採用后扭力梁式非獨立懸架,但是走爛路時車身沒有太大幅度的彈跳。

主打性價比的韓系車,因為外觀設計常常緊貼着潮流,所以很多85后、90后的朋友,都會更多留意到它們。今天編者就來和大家聊聊,前段時間我試駕過的現代領動!

北京現代 領動

指導價:9.98-15.18萬

首先外觀設計方面,領動是名副其實的目光收割器。中網六邊形的大嘴、流線型的車燈以及車身線條,如果配上檸檬黃、深海藍這兩種車身顏色,是相當前衛、運動的。

而從定價來看,9.98萬的起售價比較低,而編者試駕的是最走量的1.6L+6AT的車型。它的定價為11.18-14.58萬,市面上一般有着5000元左右的優惠。

1.6L自動擋車型採用了缸內直噴的供油方式,最大功率130馬力、最大扭矩157牛米。在功率方面表現不錯。

搭配6擋手自一體變速箱,它提供了ECO/SpORT駕駛模式,主要是通過換擋的時機選擇來決定動力和油耗的表現。

進入到車內,它的內飾給你的感覺是簡潔明了的,按鍵的布局也簡約、常規。而黑色的內飾,也帶有一定運動感。

方向盤的尺寸中等,而多功能按鍵使用起來也是順手拈來。在人機工程學上完善度不錯。

駕駛感受怎樣?

首先,領動的油門調校相當靈敏,起步時轉速提升相當快、提速過程爽快。而在SpORT模式下,它的動力輸出變得激進,變速箱的換擋時機更靠後、開起來相當的“沖”。

而ECO模式下,變速箱會把發動機的轉速緊緊控制在3000轉以下,動力響應變得遲緩一點。

領動的底盤其實還是比較有韌性的,雖然採用后扭力梁式非獨立懸架,但是走爛路時車身沒有太大幅度的彈跳。

只是懸架對於大震動的過濾稍有一點生硬,而對於像減速帶一樣的震動過濾得不錯。

油耗如何?

1.6L自動擋車型車主口碑油耗:7.2L/100km。

1.6L手動擋車型車主口碑油耗:6.8L/100km。

因為自動擋車型採用了缸內直噴等技術,加上變速箱表現不錯,所以油耗也比較的低。

另外,1.6L自動擋車型的百公里加速時間約為11.26秒,屬於中等水平。

競爭對手:

上汽通用別克-英朗

指導價:10.99-15.99萬

英朗和領動也是配置高、性價比給力的車型。不過英朗設計大氣穩重,而領動的設計則比較超前。所以它們針對的消費群體還是有一定差異。

編者語:

領動能滿足很多年輕消費者的需求,設計漂亮、動力夠用、油耗比較經濟。而如果你喜歡這款車,就可以先去4S店試駕一番再作決定。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

比寶馬奧迪要拉風的豪華車型 車主都說拉風到極點?

8AT變速箱在加速過程中順暢而且有強烈的推背感。還有F SpORT版車型的外觀真的很動感、犀利,和朋友那些寶馬、奧迪停在一起時,我的車真的要個性拉風很多。目前行駛里程:我是2015年9月份提車的,現在跑了也有11000公里了。平時跑高速多,在高速行駛平均百公里油耗7。

雷克薩斯-雷克薩斯IS

指導價:36.90-48.00萬

車主:秋名山文太

購買車型:2015款 200t 領先版

裸車價格:35.8萬

車主點評:最滿意的當然就是雷克薩斯的品質還有做工了!特別是內飾部分,它細節縫線工藝可以看出日本工匠精神。外觀不用多說,犀利又運動。車內的隔音也很棒,我特滿意。

比較不滿意的地方是腳剎,因為是進口車的原因,所以性價比和奔馳C級、寶馬3系對比沒有優勢。不過性能相當於對手車型的高功率版了,所以還能接受,買車就要買自己喜歡的!

目前行駛里程:我是今年3月份提車的,到現在行駛了7300公里,平均百公里油耗是9.8L。2.0T+8擋手自一體變速箱效率是不錯的。

車主:Elpacoco

購買車型:2015款 200t F SpORT

裸車價格:35.9萬

車主點評:裝配了2.0T發動機,動力提升油耗卻降低了。8AT變速箱在加速過程中順暢而且有強烈的推背感!

還有F SpORT版車型的外觀真的很動感、犀利,和朋友那些寶馬、奧迪停在一起時,我的車真的要個性拉風很多!

目前行駛里程:我是2015年9月份提車的,現在跑了也有11000公里了。平時跑高速多,在高速行駛平均百公里油耗7.8L,在城市郊區混合路面行駛則為8.4L左右!油耗比較省。

車主:德原朗

購買車型:2015款 200t F SpORT

裸車價格:34.8萬

車主點評:最滿意它騷氣的外觀,显示效果出色的儀錶盤。操控方面,在S模式下方向盤的回饋力度很適中,開起來讓人慾罷不能。跑山的時候會有一點側傾,但是不需要擔心,底盤的支撐性還是相當到位的。

還有紅色的座椅,視覺效果很出色。

中控屏幕尺寸有點小,手套箱的空間也有點小,看來這款進口車還是比較我行我素的!

目前行駛里程:我的IS目前行駛了4800公里,在磨合期,現在平均百公里油耗是10.8L。

編輯點評:

在BBA的一些對手車型給出比較大幅度優惠的現在,雷克薩斯IS的售價則非常堅挺。它的2.0T發動機,最大功率245馬力,並且搭配8AT變速箱的表現出色。在做工、隔音、操控方面都是有較高水準。如果你喜歡它的話,馬上去4S店體驗一番吧。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

扭矩達230牛米!這輛前衛車型有思域、卡羅拉強嗎?

而懸架具有彈性,對於大小震動都做出了不錯的過濾。只是懸挂行程比起兩廂的標緻308S更長,所以過彎時的車身擺動稍大些,不過支撐性已經不錯了。油耗表現如何。1。2T自動擋車型的車主口碑油耗:7。5L/100km。1。2T發動機的排量小,而且變速箱在D擋時的經濟性不錯。

最近有很多粉絲提議我們多聊一下靈活好開的家用轎車,這讓編者想起前段時間試駕過朋友的標緻308 1.2T車型。

標緻308 1.2T車型售價:10.97-13.57萬

308的外觀設計是標緻最新設計語言的縮影,這個設計年輕、時尚,車尾的線條流暢,比較大氣。兩個尾燈之間還採用了黑色裝飾板來點綴,讓它給人一種過目不忘的感覺。

它靈活好開,有駕駛樂趣的同時也給乘客不錯的舒適性,下面我們就來聊聊編者對這款車的感受!

動力總成採用了新穎的1.2T(三缸)渦輪增壓發動機,最大功率136馬力、峰值扭矩還達到了230牛米/1750-3500轉!動力參數漂亮,而編者的朋友買這款車也是衝著這發動機去的。

傳動方面搭配的是6擋手自一體變速箱,而同級別的日系對手,如卡羅拉1.2T車型採用的則是CVT變速箱。

上到車內,前衛的內飾讓年輕人覺得它前衛和很有設計感。尺寸很小的方向盤充滿玩味!

但問題是,儀錶盤的位置設計在中控的頂部,容易出現方向盤頂端擋住部分儀錶盤的情況。這與方向盤的高度調節和駕駛人的身高有關,所以在駕駛前盡量調好方向盤的位置。

駕駛起來,在D擋模式下,它的調校側重於降低油耗,所以總是积極升擋、降擋出現一點點“猶豫”的情況,在市區中代步動力夠用也平順。

而打開運動模式,變速箱的降擋直接乾脆!發動機在1900轉以後的動力爆發比較猛,提速能力強,而且在時速超過100km/h后,再加速能力也不錯,這套動力總成實際的表現已經接近1.8L的自然吸氣發動機了,所以在動力方面不用擔心。

小尺寸方向盤握感出眾,指向性精準,所以轉動起來充滿着玩味。而懸架具有彈性,對於大小震動都做出了不錯的過濾!只是懸挂行程比起兩廂的標緻308S更長,所以過彎時的車身擺動稍大些,不過支撐性已經不錯了!

油耗表現如何?

1.2T自動擋車型的車主口碑油耗:7.5L/100km。

1.2T發動機的排量小,而且變速箱在D擋時的經濟性不錯!所以油耗是較低的。

競爭對手

東風本田-思域

1.0T車型售價:11.59-12.79萬

在駕駛體驗上,標緻308 1.2T車型表現更好、也更有樂趣,而思域的空間表現更佳,不過購買思域的買家大多會選擇1.5T車型,所以兩者在進行着差異化競爭!

一汽豐田-卡羅拉

1.2T車型售價:10.98-14.38萬

卡羅拉採用的1.2T發動機最大功率為116馬力,數據沒有標緻308的漂亮,但是卡羅拉普遍優惠較大、車型選擇豐富,所以性價比較高些。

最後總結:

其實標緻308在駕駛樂趣和舒適性方面達到了不錯的平衡,如果你想要一款開起來有樂趣、不乏味的家用車,它是不錯的選擇。而它的優惠沒有對手車型多,所以性價比不算太高。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

要大,要硬,要安全,才是一輛好車

總結:一直以來,物流用途的商用車輛一味地追求大空間和低排放,注重燃油經濟性和裝載能力的提高卻忽視了一輛汽車最應該擁有的安全性能,而不斷在設計、品質、智能、安全方面超越自身的新全順卻從未被對手超越,擁有好品牌、大空間、高安全的福特新全順,是真正意義上的商用車佼佼者,也是創業者和物流運輸業的絕佳選擇。
老陳是物流公司創始人
因為業務擴本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

Hook踩坑記:React Hook react-unity-webgl

  自公司前後分離上手React以來,一個坑一個坑的踩,Class的全生命周期雲里霧裡,還么屢明白,就抱上了Hook的大腿不鬆手,確實爽到飛起。修改到Hook的過程基本比較順暢,直接少了三分之一的代碼,組件更容易封裝,調試更方便,諸多優點在此不再贅述,已有各路大佬紛紛評價,此處貼上中文官方地址:React-Hook文檔。這裏主要講講修改到一塊關於 Unity 3D模型加載的踩坑記。

  背景:React 加載 Unity 3D模型 ,使用到一個插件 react-unity-webgl,感興趣的盆友可以自行查閱。

  因為Class改Hook處理語法變動,邏輯代碼基本不用怎麼改動,所以基本沒有阻力,但是當我把這塊業務代碼改成Hook時,跟模型交互時通信失敗,無法驅動模型動作。百思不得其解,弄了倆測試頁面,test_hook、test_class,只能debugger,一步一步調,發現一些端倪。

  Class 有些初始化的代碼 都寫在了constructor(props){},這個大家都明白,第一次加載頁面的時候會走。hook呢,最外層是一個大方法,之前遷移的時候就寫在方法里最頂部了,也沒什麼問題。加載模型第一句是 const unityContent = new UnityContent(參數1,參數2);兩個頁面都能加載出來模型,但是跟斷點發現hook頁面的 unityContent 對象比class的缺少了一個重要的屬性:unityInstance,通信的方法就是靠它 Send() 的,而且發現同一個對象,屬性id一直在變,原來每次修改state時,都會走聲明的這段方法,導致每次都 new 一個新的對象,導致unityInstance屬性沒有正確掛在unityContent對象上。

  在知道大概原理的情況下,搞成全局變量,在加載時判斷是否已經初始化,問題就迎刃而解了(其實費了九牛二虎之力)。

  寫過hook的盆友第一反應會想到聲明寫到useEffect,然後 [] 只執行一次才是正確的寫法。

  之所以沒有呢,是因為模型加載跟其他的業務沒什麼關係,我並不需要渲染完整個DOM在來加載,並且加載模型很費時間,必須要剛加載頁面就同時加載模型,所以才有此次踩坑記。

  總結:Hook寫在useEffect之外的代碼會多次加載(包括刷新狀態),要做好判斷,否則很容易產生bug。更推薦(官方推薦)按業務按順序把初始化方法寫到useEffect。

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

Pytest單元測試框架——Pytest+Allure+Jenkins的應用

一、簡介

  pytest+allure+jenkins進行接口測試、生成測試報告、結合jenkins進行集成。

  pytest是python的一種單元測試框架,與python自帶的unittest測試框架類似,但是比unittest框架使用起來更簡潔,效率更高

  allure-pytest是python的一個第三方庫。用於連接pytest和allure,使它們可以配合在一起使用。

  allure-pytest基於pytest的原始執行結果生成適用於allure的json格式結果。該json格式結果可以用於後續適用allure生成html結果。

二、安裝  

  1、安裝pytest,命令行或終端中輸入

1 pip install pytest

  2、安裝allure-pytest,安裝成功

1 pip install allure-pytest

  allure-pytest安裝成功后截圖如下。

  3、下載安裝JDK

  官方下載:https://www.oracle.com/java/technologies/javase-jdk11-downloads.html

  安裝與配置不作闡述請諒解  

  4、下載安裝Jenkins

  官方下載:https://www.jenkins.io/

  安裝與配置不作闡述請諒解

三、下載Allure並配置

  下載allure並配置

  1、allure官網下載:https://github.com/allure-framework/allure2/releases

  如下圖所示

  2、allure2下載下來是一個zip的壓縮包,我們要解壓至自己的文件目錄下(可解壓放至項目的測試用例下或python安裝目錄下),自己可找到文件即可。

  3、打開allure2目錄,找到bin目錄,複製bin文件目錄, 然後進行環境變量的配置,設置環境變量的目的就是讓系統無論在哪個目錄下都可以運行allure2。

  4、環境變量設置:(桌面——我的電腦——右鍵屬性——高級系統配置——環境變量——系統變量——Path——編輯環境變量——把我們上面複製的目錄路徑新增至環境變量中即可)

  設置環境變量,如下圖所示。

 

  5、配置好后,打開cmd終端,輸入allure,出現以下幫助文檔,就說明配置成功了。

 四、Allure裝飾器描述

  Allure裝飾器

 五、Pytest+Allure的應用

  上述我們講了一些理論的知識,下面我們就來實戰練習一下吧。進一步理解Pytest+allure如何結合應用的。

  1、新建testcase文件夾,用來存放測試用例,新建test_Demo.py文件,作為pytest的具體測試用例文件。在test_Demo.py文件中輸入以下代碼。

 1 # test_Demo.py
 2 # Creator:wuwei
 3 # Date:2020-06-09
 4 
 5 import pytest
 6 import requests
 7 import allure
 8 import sys
 9 sys.dont_write_bytecode = True
10 
11 @allure.epic('測試描述'.center(30, '*'))
12 @allure.feature('測試模塊')
13 @allure.suite('測試套件')
14 class TestPytestOne():
15     @allure.story('用戶故事描述:用例一')
16     @allure.title('測試標題:用例一')
17     @allure.description('測試用例描述:用例一')
18     @allure.testcase('測試用例地址:https://www.baidu.com/')
19     @allure.tag('測試用例標籤:用例一')
20     def test_one(self):
21         print('執行第一個用例')
22         assert 1 == 1
23 
24     @allure.story('用戶故事描述:用例二')
25     @allure.title('測試標題:用例二')
26     @allure.description('測試用例描述:用例二')
27     @allure.testcase('測試用例地址:https://www.sogou.com/')
28     @allure.tag('測試用例標籤:用例二')
29     def test_two(self,action):
30         print('執行第二個用例')
31         assert True == True
32 
33 # pytest運行
34 if __name__ == "__main__":
35     pytest.main(['-s', '-v', 'test_Demo.py', '-q', '--alluredir', '../reports'])

  2、我們再來創建一個conftest.py,conftest用來共享數據及不同層次之間共享使用的文件,測試用例的前置和後置中一般都可以用到的。

 1 # conftest.py
 2 # Creator:wuwei
 3 # Date:2020-06-09
 4 
 5 import pytest
 6 import sys
 7 sys.dont_write_bytecode = True
 8 
 9 @pytest.fixture()
10 def action():
11     print("測試用例開始".center(30, '*'))
12     yield
13     print("測試用例結束".center(30, '*'))

  3、運行test_Demo.py文件,test_Demo文件中已經pytest+allure的結合,可查看allure的運行結果,可看出在根目錄中生成了一個reports文件夾,其中生成了測試報告的json文件,這裏面的json文件可通過allure生成html的測試報告。
  運行test_Demo.py,終端显示如下圖所示。

   生成的Json格式的測試報告,如下圖所示。

   4、使用allure將json文件生成html的測試報告,定位至項目文件根目錄下,運行以下命令,會在項目根目錄下生成一個名為allure_reports的文件夾,用來存放html測試報告。命令下如所示。

1 allure generate reports -o allure_reports/

  成功運行allure,結果如下圖所示。

  項目根目錄下的allure_reports文件,存放的是allure生成的測試報告。可看出文件下有一個HTML文件,可通過Python的編輯器Pycharm來打開該HTML文件(測試報告),或可通過allure命令來打開該HTML,展示HTML測試報告。如下所示。

  測試報告文件,HTML測試報告如下。

  allure命令打開HTML測試報告。命令如下所示。

1 allure open allure_reports/

  如下圖所示。

   打開生成的HTML測試報告如下圖所示。

 六、Pytest+Allure+Jenkins的應用

  1、Jenkins插件網站上下載allure插件最新版本:

    http://mirrors.jenkins-ci.org/plugins/allure-jenkins-plugin/

  2、Jenkins的安裝我已經在Postman+Newman+Git+Jenkins的篇章中講過了,沒看小夥伴可以看一下那篇文章。確認Jenkins服務是否開啟。確認開啟后,在瀏覽器中輸入:http://localhost:8080/,進入Jenkins配置頁面。

  3、http://localhost:8080/,登錄Jenkins的頁面,在管理Jenkins——插件管理——高級中找到上傳插件。將(1)步驟中下載的.hpi的文件上傳至jenkins上。

  上傳安裝好的allure-jenkins-plugin的插件,安裝完成並成功,是藍色圓點显示,因我已經安裝過一次,會提示已經安裝,重啟Jenkins即可生效。(注意:不是關閉瀏覽器重新打開,而是重啟Jenkins服務

  4、全局變量中配置allure路徑與JDK的路徑,

  配置JDK安裝的路徑,如下圖所示。

  配置allure安裝的路徑,如下圖所示。

  5、新建Item,配置構建后的allure測試報告生成。這裏配置Pytest執行完成之後,生成的allure文件所在的目錄位置。

  項目中生成allure的json測試報告的位置。需與下面構建后操作中的Results的Path文件一致。

  構建后操作的allure生成測試報告的配置,如下圖所示

  6、配置構建命令。就是上述在cmd中運行項目時的命令。如下圖所示。

注意:運行后發現有報錯。“Build step ‘Execute Windows batch command’ marked build as failure”,解決方案,在運行項目的命令后添加exit 0。如下圖所示。

  7、修改運行命令后我們再來運行一下。我們可發現運行后,allure裏面沒任務數據。因為我們還沒設置運行的項目路徑。設置工作空間,打開工作空間目錄,將我們的項目複製到jenkins的工作目錄中。

  我們可將代碼傳至GitHub上,在Jenkins中設置相關Github項目的配置,也可進行Jenkins部署。我在Postman+Newman+Git+Jenkins這篇博客里就應用到了。有興趣的可參考看看這篇Jenkins如何Git項目。在這裏我們使用本地項目來部署。

  測試報告無數據因為工作空間裏面沒有項目配置。

  複製項目至Jenkins工作空間的目錄中。

  8、添加項目后,我們再運行一下,藍點則為運行成功,可看到後面已經生成了allure的測試報告了。可直接點擊後面的alluree圖標跳轉至HTML的測試報告。如下圖所示。

  allure生成的HTML測試報告

八、總結

  上述我們聊了下pytest+allure+jenkins如何結合集成一起使用的,本地啟動jenkins,運行項目,調用allure生成測試報告。也簡單的做了一個小Demo。後期我將結合Requests接口測試和seleniumWeb測試應用至具體項目中。

 

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

※回頭車貨運收費標準

源碼分析 | 手寫mybait-spring核心功能(乾貨好文一次學會工廠bean、類代理、bean註冊的使用)

作者:小傅哥
博客:https://bugstack.cn – 匯總系列原創專題文章

沉澱、分享、成長,讓自己和他人都能有所收穫!

一、前言介紹

一個知識點的學習過程基本分為;運行helloworld、熟練使用api、源碼分析、核心專家。在分析mybaits以及mybatis-spring源碼之前,我也只是簡單的使用,因為它好用。但是他是怎麼做的多半是憑自己的經驗去分析,但始終覺得這樣的感覺缺少點什麼,在幾次夙興夜寐,靡有朝矣之後決定徹底的研究一下,之後在去仿照着寫一版核心功能。依次來補全自己的技術棧的空缺。在現在技術知識像爆炸一樣迸發,而我們多半又忙於工作業務開發。就像一個不會修車的老司機,只能一腳油門,一腳剎車的奔波。車速很快,但經不起壞,累覺不愛。好!為了解決這樣問題,也為了錢程似錦(形容錢多的想家裡的棉布一樣),努力!

開動之前先慶祝下我的iPhone4s又活了,還是那麼好用(嗯!有點卡);

二、以往章節

關於mybaits & spring 源碼分析以及demo功能的章節匯總,可以通過下列內容進行系統的學習,同時以下章節會有部分內容涉及到demo版本的mybaits;

  • 源碼分析 | Mybatis接口沒有實現類為什麼可以執行增刪改查
  • 源碼分析 | 像盜墓一樣分析Spring是怎麼初始化xml並註冊bean的
  • 源碼分析 | 基於jdbc實現一個Demo版的Mybatis

三、一碟小菜類代理

往往從最簡單的內容才有抓手。先看一個接口到實現類的使用,在將這部分內容轉換為代理類。

1. 定義一個 IUserDao 接口並實現這個接口類

public interface IUserDao {

    String queryUserInfo();

}

public class UserDao implements IUserDao {

    @Override
    public String queryUserInfo() {
        return "實現類";
    }

}

2. new() 方式實例化

IUserDao userDao = new UserDao();
userDao.queryUserInfo();

這是最簡單的也是最常用的使用方式,new 個對象。

3. proxy 方式實例化

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?>[] classes = {IUserDao.class};
InvocationHandler handler = (proxy, method, args) -> "你被代理了 " + method.getName();

IUserDao userDao = (IUserDao) Proxy.newProxyInstance(classLoader, classes, handler);

String res = userDao.queryUserInfo();
logger.info("測試結果:{}", res);
  • Proxy.newProxyInstance 代理類實例化方式,對應傳入類的參數即可
  • ClassLoader,是這個類加載器,我們可以獲取當前線程的類加載器
  • InvocationHandler 是代理后實際操作方法執行的內容,在這裏可以添加自己業務場景需要的邏輯,在這裏我們只返回方法名

測試結果:

23:20:18.841 [main] INFO  org.itstack.demo.test.ApiTest - 測試結果:你被代理了 queryUserInfo

Process finished with exit code 0

四、盛宴來自Bean工廠

在使用Spring的時候,我們會採用註冊或配置文件的方式,將我們的類交給Spring管理。例如;

<bean id="userDao" class="org.itstack.demo.UserDao" scope="singleton"/>

UserDao是接口IUserDao的實現類,通過上面配置,就可以實例化一個類供我們使用,但如果IUserDao沒有實現類或者我們希望去動態改變他的實現類比如掛載到別的地方(像mybaits一樣),並且是由spring bean工廠管理的,該怎麼做呢?

1. FactoryBean的使用

FactoryBean 在spring起到着二當家的地位,它將近有70多個小弟(實現它的接口定義),那麼它有三個方法;

  • T getObject() throws Exception; 返回bean實例對象
  • Class<?> getObjectType(); 返回實例類類型
  • boolean isSingleton(); 判斷是否單例,單例會放到Spring容器中單實例緩存池中

那麼我們現在就將上面用到的代理類交給spring的FactoryBean進行管理,代碼如下;

ProxyBeanFactory.java & bean工廠實現類

public class ProxyBeanFactory implements FactoryBean<IUserDao> {

    @Override
    public IUserDao getObject() throws Exception {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class<?>[] classes = {IUserDao.class};
        InvocationHandler handler = (proxy, method, args) -> "你被代理了 " + method.getName();

        return (IUserDao) Proxy.newProxyInstance(classLoader, classes, handler);
    }

    @Override
    public Class<?> getObjectType() {
        return IUserDao.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}

spring-config.xml & 配置bean類信息

<bean id="userDao" class="org.itstack.demo.bean.ProxyBeanFactory"/>

ApiTest.test_IUserDao() & 單元測試

@Test
public void test_IUserDao() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
    IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
    String res = userDao.queryUserInfo();
    logger.info("測試結果:{}", res);
}

測試結果:

一月 20, 2020 23:43:35 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-config.xml]
23:43:35.440 [main] INFO  org.itstack.demo.test.ApiTest - 測試結果:你被代理了 queryUserInfo

Process finished with exit code 0

咋樣,神奇不!你的接口都不需要實現類,就被安排的明明白白的。記住這個方法FactoryBean和動態代理。

2. BeanDefinitionRegistryPostProcessor 類註冊

你是否有懷疑過你媳婦把你錢沒收了之後都存放到哪去了,為啥你每次get都那麼費勁,像垃圾回收了一樣,不可達。

好嘞,媳婦那就別想了,研究下你的bean都被註冊到哪了就可以了。在spring的bean管理中,所有的bean最終都會被註冊到類DefaultListableBeanFactory中,接下來我們就主動註冊一個被我們代理了的bean。

RegisterBeanFactory.java & 註冊bean的實現類

public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(ProxyBeanFactory.class);

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
        registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // left intentionally blank
    }

}
  • 這裏包含4塊主要內容,分別是;
    • 實現BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry方法,獲取bean註冊對象
    • 定義bean,GenericBeanDefinition,這裏主要設置了我們的代理類工廠。我們已經測試過他獲取一個代理類
    • 創建bean定義處理類,BeanDefinitionHolder,這裏需要的主要參數;定義bean、bean名稱
    • 最後將我們自己的bean註冊到spring容器中去,registry.registerBeanDefinition()

spring-config.xml & 配置bean類信息

<bean id="userDao" class="org.itstack.demo.bean.RegisterBeanFactory"/>

ApiTest.test_IUserDao() & 單元測試

@Test
public void test_IUserDao() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
    IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
    String res = userDao.queryUserInfo();
    logger.info("測試結果:{}", res);
}

測試結果:

信息: Loading XML bean definitions from class path resource [spring-config.xml]
一月 20, 2020 23:42:29 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
信息: Overriding bean definition for bean 'userDao' with a different definition: replacing [Generic bean: class [org.itstack.demo.bean.RegisterBeanFactory]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring-config.xml]] with [Generic bean: class [org.itstack.demo.bean.ProxyBeanFactory]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
23:42:29.754 [main] INFO  org.itstack.demo.test.ApiTest - 測試結果:你被代理了 queryUserInfo

Process finished with exit code 0

納尼?是不有一種滿腦子都是騷操作的感覺,自己註冊的bean自己知道在哪了,咋回事了。

五、老闆郎上主食呀(mybaits-spring)

如果通過上面的知識點;代理類、bean工廠、bean註冊,將我們一個沒有實現類的接口安排的明明白白,讓他執行啥就執行啥,那麼你是否可以想到,這個沒有實現類的接口,可以通過我們的折騰,去調用到我們的mybaits呢!

如下圖,通過mybatis使用的配置,我們可以看到數據源DataSource交給SqlSessionFactoryBean,SqlSessionFactoryBean實例化出的SqlSessionFactory,再交給MapperScannerConfigurer。而我們要實現的就是MapperScannerConfigurer這部分;

1. 需要實現哪些核心類

為了更易理解也更易於對照,我們將實現mybatis-spring中的流程核心類,如下;

  • MapperFactoryBean {給每一個沒有實現類的接口都代理一個這樣的類,用於操作數據庫執行crud}
  • MapperScannerConfigurer {掃描包下接口類,免去配置。這樣是上圖中核心配置類}
  • SimpleMetadataReader {這個類完全和mybaits-spring中的類一樣,為了解析class文件。如果你對類加載處理很好奇,可以閱讀我的《用java實現jvm虛擬機》}
  • SqlSessionFactoryBean {這個類核心內容就一件事,將我們寫的demo版的mybaits結合進來}

在分析之前先看下我們實現主食是怎麼食用的,如下;

<bean id="sqlSessionFactory" class="org.itstack.demo.like.spring.SqlSessionFactoryBean">
    <property name="resource" value="spring/mybatis-config-datasource.xml"/>
</bean>

<bean class="org.itstack.demo.like.spring.MapperScannerConfigurer">
    <!-- 注入sqlSessionFactory -->
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    <!-- 給出需要掃描Dao接口包 -->
    <property name="basePackage" value="org.itstack.demo.dao"/>
</bean>

2. (類介紹)SqlSessionFactoryBean

這類本身比較簡單,主要實現了FactoryBean , InitializingBean用於幫我們處理mybaits核心流程類的加載處理。(關於demo版的mybaits已經在上文中提供學習鏈接)

SqlSessionFactoryBean.java

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean {

    private String resource;
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void afterPropertiesSet() throws Exception {
        try (Reader reader = Resources.getResourceAsReader(resource)) {
            this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public SqlSessionFactory getObject() throws Exception {
        return sqlSessionFactory;
    }

    @Override
    public Class<?> getObjectType() {
        return sqlSessionFactory.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }

}
  • 實現InitializingBean主要用於加載mybatis相關內容;解析xml、構造SqlSession、鏈接數據庫等
  • FactoryBean,這個類我們介紹過,主要三個方法;getObject()、getObjectType()、isSingleton()

3. (類介紹)MapperScannerConfigurer

這類的內容看上去可能有點多,但是核心事情也就是將我們的dao層接口掃描、註冊

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor {

    private String basePackage;
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            // classpath*:org/itstack/demo/dao/**/*.class
            String packageSearchPath = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";

            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);

            for (Resource resource : resources) {
                MetadataReader metadataReader = new SimpleMetadataReader(resource, ClassUtils.getDefaultClassLoader());

                ScannedGenericBeanDefinition beanDefinition = new ScannedGenericBeanDefinition(metadataReader);
                String beanName = Introspector.decapitalize(ClassUtils.getShortName(beanDefinition.getBeanClassName()));
                
                beanDefinition.setResource(resource);
                beanDefinition.setSource(resource);
                beanDefinition.setScope("singleton");
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(sqlSessionFactory);
                beanDefinition.setBeanClass(MapperFactoryBean.class);

                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
                registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // left intentionally blank
    }

    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
}

  • 類的掃描註冊,classpath:org/itstack/demo/dao/**/.class,解析calss文件獲取資源信息;Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
  • 遍歷Resource,這裏就你的class信息,用於註冊bean。ScannedGenericBeanDefinition
  • 這裡有一點,bean的定義設置時候,是把beanDefinition.setBeanClass(MapperFactoryBean.class);設置進去的。同時在前面給他設置了構造參數。(細細品味)
  • 最後執行註冊registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

4. (類介紹)MapperFactoryBean

這個類就非常有意思了,因為你所有的dao接口類,實際就是他。他這裏幫你執行你對sql的所有操作的分發處理。為了更加簡化清晰,目前這裏只實現了查詢部分,在mybatis-spring源碼中分別對select、update、insert、delete、其他等做了操作。

public class MapperFactoryBean<T> implements FactoryBean<T> {

    private Class<T> mapperInterface;
    private SqlSessionFactory sqlSessionFactory;

    public MapperFactoryBean(Class<T> mapperInterface, SqlSessionFactory sqlSessionFactory) {
        this.mapperInterface = mapperInterface;
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public T getObject() throws Exception {
        InvocationHandler handler = (proxy, method, args) -> {
            System.out.println("你被代理了,執行SQL操作!" + method.getName());
            try {
                SqlSession session = sqlSessionFactory.openSession();
                try {
                    return session.selectOne(mapperInterface.getName() + "." + method.getName(), args[0]);
                } finally {
                    session.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return method.getReturnType().newInstance();
        };
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{mapperInterface}, handler);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}
  • T getObject(),中是一個java代理類的實現,這個代理類對象會被掛到你的注入中。真正調用方法內容時會執行到代理類的實現部分,也就是“你被代理了,執行SQL操作!”

  • InvocationHandler,代理類的實現部分非常簡單,主要開啟SqlSession,並通過固定的key;“org.itstack.demo.dao.IUserDao.queryUserInfoById”執行SQL操作;

    session.selectOne(mapperInterface.getName() + “.” + method.getName(), args[0]);

    <mapper namespace="org.itstack.demo.dao.IUserDao">
    
    	<select id="queryUserInfoById" parameterType="java.lang.Long" resultType="org.itstack.demo.po.User">
    		SELECT id, name, age, createTime, updateTime
    		FROM user
    		where id = #{id}
    	</select>
    	
    </mapper>
    
  • 最終返回了執行結果,關於查詢到結果信息會反射操作成對象類,這部分內容可以遇到demo版本的mybatis

六、倒滿走一個

好!到這一切開發內容就完成了,測試走一個。

mybatis-config-datasource.xml & 數據源配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/itstack_demo_ddd?useUnicode=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/User_Mapper.xml"/>
        <mapper resource="mapper/School_Mapper.xml"/>
    </mappers>

</configuration>

test-config.xml & 配置xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
       default-autowire="byName">
    <context:component-scan base-package="org.itstack"/>

    <aop:aspectj-autoproxy/>

    <bean id="sqlSessionFactory" class="org.itstack.demo.like.spring.SqlSessionFactoryBean">
        <property name="resource" value="spring/mybatis-config-datasource.xml"/>
    </bean>

    <bean class="org.itstack.demo.like.spring.MapperScannerConfigurer">
        <!-- 注入sqlSessionFactory -->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!-- 給出需要掃描Dao接口包 -->
        <property name="basePackage" value="org.itstack.demo.dao"/>
    </bean>

</beans>

SpringTest.java & 單元測試

public class SpringTest {

    private Logger logger = LoggerFactory.getLogger(SpringTest.class);

    @Test
    public void test_ClassPathXmlApplicationContext() {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("test-config.xml");
        IUserDao userDao = beanFactory.getBean("IUserDao", IUserDao.class);
        User user = userDao.queryUserInfoById(1L);
        logger.info("測試結果:{}", JSON.toJSONString(user));
    }

}

測試結果;

一月 20, 2020 23:51:43 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@30b8a058: startup date [Mon Jan 20 23:51:43 CST 2020]; root of context hierarchy
一月 20, 2020 23:51:43 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [test-config.xml]
你被代理了,執行SQL操作!queryUserInfoById
2020-01-20 23:51:45.592 [main] INFO  org.itstack.demo.SpringTest[26] - 測試結果:{"age":18,"createTime":1576944000000,"id":1,"name":"水水","updateTime":1576944000000}

Process finished with exit code 0

酒乾熱火笑紅塵,春秋幾載年輪,不問。回首皆是Spring!Gun!變心!你被代理了!

七、綜上總結

  • 通過這些核心關鍵類的實現;SqlSessionFactoryBean、MapperScannerConfigurer、SqlSessionFactoryBean,我們將spring與mybaits集合起來使用,解決了沒有實現類的接口怎麼處理數據庫CRUD操作
  • 那麼這個知識點可以用到哪裡,不要只想着面試!在我們業務開發中是不會有很多其他數據源操作,比如ES、Hadoop、數據中心等等,包括自建。那麼我們就可以做成一套統一數據源處理服務,以優化服務開發效率
  • 由於這次工程類是在itstack-demo-code-mybatis中繼續開發,如果需要獲取源碼可以關注公眾號:bugstack蟲洞棧,回復:源碼分析

八、推薦閱讀

  • 這麼折騰學習畢業進大廠不是問題
  • 工作兩年簡歷寫的差教你優化
  • 講一下我自己的學習路線,給你一些參考
  • 基於Springboot的中間件開發,了解一下

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準