敏捷開發:項目管理的一些思考

誤區

之前我沒有項目經驗,在上一家公司的項目管理上,我只是照葫蘆畫瓢。

  1. 產品發起,整個項目沒有項目經理這一說。或者說有,但卻真的感受不到,一丁點也感受不到。

  2. 產品發起會議,或者開發發起會議。無論誰來發起會議,一般都會針對於某一具體需求或者某一具體實現方式。

  3. 沒有具體的任務規劃,任務拆得不夠細緻。這個和開發自身有關係。當然那時的公司確實沒有一些指導性質的模板和導師。

  4. 任務分得不夠細緻,就會導致工期評估差距比較大。

  5. 各種O們的臨時緊急需求,很多O沒有技術背景和項目管理背景。很多時候提出的需求都是發生在項目開始過程中。

    都是很急的需求,不得不重新估算時間和排期。開發為了避免延期風險,就是讓產品排優先級,然後我們根據優先級估時。

    直到有必要的需求都在這個迭代中計劃上。

  6. 沒人全局把控,產品從產品角度,開發從開發角度,業務從業務角度。始終沒有一個最終的協調人。

    產品在對各種O的對話中,氣場和身份不足,導致需求基本是提出就會安排。即便是請出青島總負責人出面溝通,最終的結果一般就是接受。

  7. 之前我們是青島為開發,北京為產品、UI、前端、測試。異地溝通。電話會議是常有的事情,私下的臨時溝通電話更是家常便飯。

    信息同步、開會、理解程度 都會造成溝通上的成本增加。

  8. 緊急需求上線后,三個月沒人反饋。問了才知道,財務提的需求他們沒用過。

  9. 開會一般都會臨時決定,發起人會準備資料,但是其他人提前看資料準備問題的情況極少。導致會議冗長效率低。

解決

現在來看,無論如何,我們在知道這些問題,但是為什麼不去處理呢?應該還是習慣了,即便是整個項目非常掙扎,依然是按老規矩走。大家都是困在了這個圍牆中。

我現在也有了一年的項目管理經驗,初入門道。只是對自己的過往進行一下分析解決。

以上的誤區和問題,我覺得需要一個有經驗並且有點能力的人來帶領這個項目團隊。

1. 確認項目經理

但是按照我上家公司的情況,一般會立經驗豐富的主管直接管理這個項目。

當時的情況是,項目主管在項目上的精力完全不夠,甚至說項目管理在項目主管心中的優先級比較低。

根本原因,青島作為研發中心,技術基因強大。很多技術管理人員,沒有意識到項目管理的重要性。

組織架構主要是垂直單線架構,技術-主管-經理-總監-CTO。無非是自己下面的人多,按照業務或者大項目分了組而已。

如果讓開發作為項目經理,

首先這個開發是否願意承擔項目經理職責?

是否真的能夠賦給項目經理一些實權?

是否有鼓勵機制,比如晉陞優先或者獎金等?

建議:

加強項目管理意識;

加強項目管理能力;

必要的話可以作為量化指標來看;

加入一些激勵機制;

2. 培養主動性

因為技術基因影響。主管或者經理出於“好心”考慮。

他可能會考慮到,如果把項目管理中的某些事情分配給組員,會不會引起反感?會不會影響在組員中的美好形象?

也算是確實分下來一些,比如項目規劃和估時以及排期。但是我沒經驗的,是不是可以稍微引導一下?

領導總想為老好人,但是這樣自己手頭的任務分不下去。

下面的人也得不到成長。

建議

對組員有一定的規劃和成長要求,而不是放任其隨意生長(有一定風險)

領導應該提高自身的管理能力,管理技巧。而不是憑經驗論。

定時關切Review分下去的任務,從結果或者過程提出建議和優化。

3. 確認好需求邊界

產品經理和負責人,確認好需求邊界。飄忽不定的需求給項目的打擊是很大的。

開發在搖搖墜墜中估時,此時的估時肯定會有大量的冗餘,因為之前需求的變動,上線時間一改再改。

在加上,主管、經理偶爾砍幾刀。所以開發在估工時都會冗餘很多。為了被砍,為了需求不定。

建議:

確認好需求,可將項目周期縮短,小版本迭代。

強化項目上線時間約定,鍥約精神。不僅僅是開發要遵守。其他人員最好也能嚴格遵守。(當初這個做起來真的比較困難)

信心是做出來的,幾次項目的延期和需求的變更會嚴重打擊大家的信心和士氣。所以按時上線很重要。

規劃得有,但是是不是可以考刪掉遠在4個月以後的需求。

4. 緊急需求

比如財務的一些緊急需求,其實確實緊急,但是使用頻率很低。

是不是可以有另一種解決方案?不一定非要按照財務提出的那種設想。

我們達到並滿足了他們的目標,後期再去做頁面更加直觀。

比如要一個訂單查看頁面。那我使用程序定時拉取新訂單推送到企業微信或者釘釘。結果也是非常滿意的。

不一定非要做一個頁面,很多時候做成一個頁面,大家會發揮自己的產品意識,增加一些不必要的按鈕、功能和邏輯。

建議

深入了解需求,而不僅僅是一句話,也不是根據用戶提出的需求來做,用戶到底想要什麼?--他就想要有訂單能及時知道。

緊急需求是否真緊急,也得看使用頻率。使用頻率低,是否有其他方式實現。

能擱置的暫且擱置一下,之前就我一個人開發,很多原本緊急的需求因為開發不夠,擱置了也就擱置了。然後甚至有的都自己消失了。

5. 高效開會

會議開始前,大家幾乎么有預習的習慣,會上很多時候沒有主持人,大家就問題會討論很深,導致時間不可控。

有的會能一個電話解決的就沒必要拉這個拉那個來開會。這種儀式感不重要,開會也不是拉家常。

為了讓領導知道這次會議的重要性,這個項目的重要性。拉着領導一起開:

但是領導的事情多,很多時候在會上他們是一直回複信息,其實當時是比較尷尬的,領導不能專心處理問題。我們看着領導沒用心聽,不了解的同事還以為領導漠不關心呢。

建議:

發起人拉群,提前@人提醒大家關注和看會議內容。

發起人做會議:主題、流程、最終結論

確認會議主持人,隨時控制會議進度。有些細節會後溝通。

領導可以不必參加需求討論會,把會上討論的疑難問題,會後單獨和領導會報,再拉一個小會議電話溝通確認即可。

 重要項目啟動會、項目上線等會議盡量簡短,領導全身心參加。保證大家的鬥志,統一思想達成一致。有些形式必須要有的。

6. 相關方

開發與客戶溝通少,因為兩地溝通,基本是產品作為翻譯官將業務轉成需求轉達給開發。

開發沒有感知用戶的存在。

建議

多聽聽用戶怎麼說。

大家達成一致,每月電話會議或者視頻會議溝通一次。會議可以控制在1小時以內,氛圍可以輕鬆,主要是收集需求以及反饋問題。

如果有多個業務部門都是相關方,那麼主要思想就是設置定期溝通(規律的定期溝通)
    

7. 轉變

優勝劣汰的企業付薪給我們,我們就要服務於這個企業用戶。甚至說服務好用戶。

我們開發也要主動從自身求變。好好說話,真心替我們的用戶思考過問題。

從產品和業務角度認可業務優先級,而不是緊緊盯着開發重構、新技術的應用。

建議

轉變意識:我想為你們服務;

我能力不行,但是我能主動學習項目管理知識和經驗,並在項目中實踐,反思,再實踐。

我要為我開發的產品負責,它的迭代,扔給它的需求,和它相關方,它的應變能力。

主動一點,也許事情看起來並沒有那麼難。

現在的我,我們

新的公司,給了我很多的機會,糾正了我很多認知,我也從實踐中反思了很多,收穫了很多。

公司的組織架構是矩形架構:橫向職能,垂直項目

項目首先會有項目經理,項目經理有一定的項目經理獎金。當然項目經理要履行項目經理的職責。都會有績效。

項目經理,開發,產品,測試,DBA,運維,PMO 這些會組成一個項目組。

整個項目組會在項目經理的引導下,開發項目直到上線。然後迭代下一版本。

現在項目中,有使用瀑布開發,有使用敏捷開發。

我所認知的一點是,各個職能團隊人員雖然屬於職能。但是基本會長期泡在各個項目中。

項目中學習到的東西,在項目中的成長也是很重要的。所以項目經理有一定的敏捷角色中PM的角色:引導大家,賦能給大家。

我們正在嘗試的敏捷(嘗試)

其他團隊物理面板:

我們團隊的面板:非常簡單

項目并行和項目特殊性,我們採用周交付,不確定哪一天交付什麼(特殊需求除外)。

因為項目為運維性質的項目,有開發,緊急需求,客戶答疑問題較多。時間不太可控。

並且大家积極性都很高,沒必要要求必須排滿周開發任務。

自己開發完直接到需求池,領取最優先級的需求,或者幫助其他組員分解開發任務。

業務需求 + 技術需求 雙向需求驅動,佔比5:1。

周最高優先級佔比 1:4

這樣大家不會因為具體時間的衝突導致交付的壓力。周交付的任務為必須交付的最小單元(本周必須交付)。

沒必要的會議去掉,我們基本都坐在一起,不去會議室。工位周邊就可以開會。電腦操作隨時記錄,會後發出來。

周五:計劃會(15:00 ~ 15:30)

10分鐘,材料都是平時積累,會前整理完

地點:工位

目的:回顧上版本迭代精進結果。分析過程問題原因,總結問題。認知好與不足,下版本迭代重點要解決的問題。;討論新需求優先級;達成一致周最小目標。

周五會後 + 周一開會前 

這段時間,是大家緩一緩,總結自己規劃下周的時間。

磨刀不誤砍柴工,想好怎麼做,才能預知困難和風險。

對新需求進行任務拆分,需求理解,任務具體估時。

周一:迭代會(10:00 ~ 10:15)

15~30分鐘,微調任務;統一思想;確認周迭代目標;

地點:工位

周三:如果需要可以開一個簡短溝通會

我們自己維護的計劃和交付,簡單高效。團隊協作,互相可看。

我們的產品是剛畢業的新人,我們互相指導學習。

他最近也在研究用戶故事如何寫好。他打算下周先打印出來,大家看看自己感受一下。

最近我看完了一本敏捷開發相關的書籍,同時推薦給了他。我們想單獨摘出好的或者值得討論的地方,大家圍在一起拿出半小時討論一下也未嘗不可。

還有一本我正在看,可能我實踐經驗不足。總是感覺一般般的感覺。思路不是很清晰。

有讀過的朋友可以發表一下看法。

總結

敏捷我們在路上。不為敏捷而敏捷。

我們互相提高,互相幫助,能力提升,升職加薪。生活質量更好。

大街上敏捷一大堆,根據實際情況摸索敏捷之道。發揮大家的能力,提升大家的能力。為大家帶來點實際的東西。為企業帶來點實際的東西。

項目管理根本目標是把項目管好,項目管好,大家更加自信,互相也都信任。所以項目管好是項目組良性循環的根本。項目經理要多花大力氣去關注,去學習。

謝謝關注公眾號

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

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

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

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

荷蘭團隊要打造世界第一台以甲酸為燃料巴士

隨著環保意識提升,再生能源的利用逐漸受到各國重視,荷蘭一群學生就開發出一種儲存能源的方法,不僅簡單製造、可用性高也更持久,他們打算利用這項技術來打造第一台使用甲酸(Formic acid)做為燃料的巴士。  
用甲酸做燃料的巴士   甲酸,又被稱做蟻酸,是螞蟻及蚊蟲在叮咬中傳播的物質,化學式為HCOOH,這種簡單的羧酸已經被使用在紡織和皮革加工作業中,也可以用來做為家畜飼料的防腐劑,或是添加在家用的水垢去除劑。

 

(Source:Flickr/Brian Gratwicke CC BY 2.0)   而由荷蘭恩荷芬理工大學(TU/e)多學科學生團隊組成的新創公司Team FAST  找到了一種方法,讓甲酸能夠有效攜帶氫燃料電池必需的成分,為電動車提供電力。   BBC 報導,Team FAST 計畫打造的巴士主要燃料叫做Hydrozine(並不是聯氨Hydrazine),由99% 的甲酸組成,呈現液體型態,能夠輕易的傳送運輸,因此在車輛上也能夠快速的進行「加油」,就像是目前一般使用的燃料一樣。   但和現今的燃料不同的是,Hydrozine 更環保。   Team FAST 的發言人Lucas van Cappellen 表示,使用這種燃料,車輛排放的尾氣中只會有二氧化碳和水,不會具有其他有害氣體,像是一氧化氮、煤煙或硫氧化物。   為了證明這個概念可行,Team FAST 目前正和VDL 集團合作,打造第一台甲酸燃料巴士,預計2017 下半年間將在荷蘭登場,除了在展覽中亮相以外,巴士也會在一般道路上行駛。   這台巴士將透過VDL 開發的電力系統驅動,並且能夠透過托掛在後方拖車上的甲酸燃料電池系統接收額外的電力。   根據van Cappellen 透露,目前的燃料箱大約是300 公升,因此這台電動巴士的續航力大約是200 公里,但未來要再把燃料箱加大也是非常簡單的。   但為什麼要一開始就從巴士下手,而不是選擇一般車輛呢?   van Cappellen 解釋,因為團隊覺得電動車已經是一個很好的解決方案,如果選擇從一般車輛入手,Hydrozine 將會面對和電動車競爭的問題。   「但相反來看,如果我們能夠建造一台滿足巴士公司需求的巴士,續航力達到400 公里左右,也能夠快速補充燃料,我們就能在還沒有競爭對手的領域中,展現出Hydrozine 的潛力。」  
商業化的可行性   根據Team FAST 官網和van Cappellen 的說明,團隊先是將溶於水的氫氣和二氧化碳運用催化劑合併為甲酸製成Hydrozine,之後再透過催化劑在「reformer」的裝置中分解為氫氣和二氧化碳,將氫氣加到燃料電池中與氧氣反應,產生電力供巴士使用。  

(Source:Team FAST)   Team FAST 目前正在為「reformer」申請專利中,新設計的「reformer」體積只有過去的十分之一,這可能也是Hydrozine 首次能夠被運用在交通運輸上的原因。   負責交通解決方案的VDL ETS 總經理Menno Kleingeld 表示,VDL 一直在尋找新技術,能夠透過簡單方式拓展零排放交通的範圍,「將甲酸分解為氫氣就是一項很有希望的新技術」。   van Cappellen 估計,將一般加油站轉換為Hydrozine 補充站的整體費用大概是3.5 萬歐元(約120 萬元台幣),比起直接架設會便宜許多,而且Hydrozine 比汽油更加便宜,預計未來價格還會持續下降,因此他認為商業化是可行的。   除此之外,Team FAST 認為,雖然這樣的巴士也會排放二氧化碳,但製造Hydrozine 的原料之一就是二氧化碳,是由現有的來源收集而來,因此並沒有額外的碳產生,因此能夠達到環保概念中所謂的「碳循環」效果。   荷蘭一些專家和企業都看好並支持這個計畫,研究的學生也都非常投入在其中,除了15 位全心投入計畫的人員外,其他學生每周也都投入20~25 小時在計畫中研究。   van Cappellen 表示,儘管他們不能從中獲得學分,但能從大學中獲得的實際經驗大概就只有那麼一些,「我們正在建造自己的未來」。   (合作媒體:。首途來源:pixabay;圖片出處:TechNews)  

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

【其他文章推薦】

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

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

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

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

特斯拉大眾電動車Model 3本周量產,預估月底交車

特斯拉周一公佈第二季僅交車2.2萬輛,上半年合計4.7萬輛,僅以最低標達陣。不過這不打緊,市場最關注的是特斯拉執行長馬斯克(Elon Musk)隨後宣布大眾化電動車Model 3本周五即可進入量產,比預估時程提前兩周。

特斯拉說電池模組供給嚴重不足,導致產出受限,直至六月才獲得抒解,預期Model S與Model X等高檔車下半年交車狀況有望優於上半年。特斯拉原預期上半年交車量介於4.7-5萬輛之間。(路透社)

特斯拉目前已收到近40萬輛Model 3的預購訂單,據馬斯克表示,首批30輛Model 3將在7月28日交車,九月產能可提升至1500輛,估計十二月可達成月產2萬輛的目標。

市場研究機構Consumer Edge Research分析師艾伯汀(James Albertine)指出,按照特斯拉現在的規劃,Model 3進度微幅超前,不然至少也在預期之內,證明馬斯克之前的豪語不是隨便說說。(金融時報)

特斯拉股價周一於正常交易時段收跌2.49%,但今年迄今累計漲幅仍高達65%,市值來到580億美元。

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

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

Volvo 兩年後只生產電動車,中國政府是幕後推手

  Volvo 宣布要讓內燃機引擎退場,2019 年生產車款全面配備電動引擎,正式從生產傳統汽車轉向電動車,其實Volvo 此舉的最大幕後推手是近年積極發展綠能的中國政府,被中資買下的Volvo 只是配合中國政策布局。   華爾街日報(WSJ)分析指出,中國是全球最大汽車市場,因此中國政策一舉一動對產業變化是牽一髮動全身,隨著中國治理空汙政策逐步兌現,汽車大廠不得不跟著改變策略、加緊跟上,更別說現在Volvo 的老闆是中國吉利汽車。   現在中國每年電動車銷售量可達50 萬台,超過美國與其他已開發國家,中國政府上月更新電動車政策,旨在鼓勵生產更大容量電池的電動車,在此政策下生產高品質電動車的廠商將受惠,但不利於在電動車領域發展較晚的企業。   電動車快速成長打破市場對中國抑制生產的謠言。但是中國政府的確要稍微踩煞車,如同過去避免太陽能面板到風力渦輪機生產過剩的現象。政策調整後,現在生產高品質,電池續航力更久的電動車製造商,若沒有達到綠色汽車產量標準所面臨的罰則較輕,且生產高品質電動車可以在中國新能源汽車積分制度上中賺取積分,在市場上賣給其他負積分的廠商,成為一筆收入來源。   中國政府希望政策調整能夠在淘汰低品質產品同時保持生產力道。德國戴姆勒(Daimler)近日表示,將升級與中國合資企業共同使用的設備,以生產更多電動車。福特也表示將在中國生產電動車,計劃在2025 年前將七成電動車產能移往中國。   福斯(Volkswagen)電動車設計也是以中國市場為核心,目標是在2025 年前每年賣出100 萬台電動車,其中六成銷往中國。日本大廠也不放過,本田(Honda)汽車宣布要在2018 年於中國上市純電動車。   不過新政策對中國最大SUV 製造商長城汽車而言沒有好處,因為SUV 賣得太好,因此長城汽車的燃油消耗仍遠高於政府規定的目標,市場認為長城汽車短期內不會發展電動車,而吉利汽車相較同業可獲得較大利益。   中國十三五計畫明訂發展電動車產業,在政策扶植下已成為正在強勢發展的明星級產業,中國訂下2020 年讓500 萬輛電動車上路的目標。報導認為,中國政策加上全球汽車大廠的配合,將是推動電動車發展的最大幕後黑手。   (合作媒體:。圖片出處:pixabay CC0)  

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

【其他文章推薦】

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

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

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

貪心算法(會場安排問題、區間選點)

學習算法課程之後的第一次記錄,漸漸的,程序設計考慮的因素增多,程序=數據結構+算法,這個等式讓我深有體會。從開始簡單的C++編程,再到選擇合適數據結構,現在需要更進一步,從算法層次上考慮程序執行的效率。我對算法的理解是用更少的開銷獲得更優的執行效果。

分治法、動態規劃在此之前沒有記錄下來,學到貪心算法的時候,覺得需要總結一下學過的東西,也能更好的理解。動態規劃的設計,要滿足最優子結構性質和重疊子問題,採用自底向上的策略,計算出最優值,找到整體最優解。這個過程有時候挺難的,主要在寫出遞歸式,要自底向上填表。貪心策略有點像動態規劃,但在一些方面是不同的,有時候貪心算法的思想更容易想到。它要滿足子問題最優而得到整體最優?兩個條件:最優子結構性質和貪心選擇性質。滿足貪心選擇性質一定滿足最優子結構性質,而滿足最優子結構性質不一定滿足貪心選擇性質,比如背包問題可以用貪心算法解決,而0-1背包問題只能用動態規劃。

典型的貪心問題活動安排,有n個活動,給出開始時間和結束時間,要盡可能安排多的活動(時間互相不衝突)。解決這個問題正確的貪心思想是以每個活動結束時間為比較變量,按結束時間升序排好活動次序,接着就進行比較選擇。而會場安排問題與活動又有些不同之處,下面是我的解題過程。

7-2 會場安排問題 (20 分)

假設要在足夠多的會場里安排一批活動,並希望使用盡可能少的會場。設計一個有效的 貪心算法進行安排。(這個問題實際上是著名的圖着色問題。若將每一個活動作為圖的一個 頂點,不相容活動間用邊相連。使相鄰頂點着有不同顏色的最小着色數,相應於要找的最小 會場數。)

輸入格式:

第一行有 1 個正整數k,表示有 k個待安排的活動。 接下來的 k行中,每行有 2個正整數,分別表示 k個待安排的活動開始時間和結束時間。時間 以 0 點開始的分鐘計。

輸出格式:

輸出最少會場數。

輸入樣例:

5
1 23
12 28
25 35
27 80
36 50 

輸出樣例:

3
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
    int begin;
    int end;
    int flag;//標記該活動是否被安排,0表示未安排,1表示已安排 
}t[10001];
int cmp(const node &a,const node &b)//比較規則:以結束時間升序排列 
{ 
    return a.end<b.end;
 } 
int main()
{
    int i,j,n;
    node temp;
    cin>>n;
    for(i=0;i<n;i++) 
    {
        cin>>t[i].begin>>t[i].end;
        t[i].flag=0;
    }
    sort(t,t+n,cmp);
        
    int sum=0;//總共需要的會場數量 

    for(i=0;i<n;i++)//方法2 
    {
        if(!t[i].flag)//找到未安排的活動,進行場地安排 
        {
            sum++;
            int p=i;
            for(j=p+1;j<n;j++)//當前活動結束時間與下一個活動開始不相交 ,則安排到同一個會場 
            {
                if(t[p].end<=t[j].begin&&!t[j].flag)
                {
                    p=j;t[j].flag=1;
                }
            }
            t[i].flag=1;
        }
    }

    cout<<sum;
    return 0;
}

View Code

貪心策略為:把盡可能多的時間互不衝突的活動安排到一個會場,若活動時間交叉,則在安排到另一個會場。

將所有活動按結束時間升序排列,利用sort函數,自定義cmp方法。循環體中,每次可以找到還沒有安排的活動,並以這個活動搜索能同時容納到一個會場的其他活動(這一步嵌套在內層循環中),經過兩層循環,把所有活動全部安排好,這時也已經計算出需要的會場數量sum。

類似的問題是區間選點

7-10 選點問題 (15 分)  數軸上有n個閉區間[ai, bi]。取盡量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。

輸入格式:

第一行一個数字n,表示有n個閉區間。 下面n行,每行包含2個数字,表示閉區間[ai, bi]

輸出格式:

一個整數,表示至少需要幾個點

輸入樣例:

在這裏給出一組輸入。例如:

3
1 3
2 4
5 6

輸出樣例:

在這裏給出相應的輸出。例如:2

開始想找出幾個區間共同段,並且記錄每個共同段中包含哪些區間,這樣算出最少選點。後來發現覺得這個想法其實可以簡化一下,策略為:以右端為擋板,看看前面是否包含其他區間,如果是,則不記數,反之,說明沒有共同段,需要計數並且移動擋板位置繼續尋找。貪心策略是選擇區間右端點,保證能夠包含更大交叉段,選的點最少。

#include<bits/stdc++.h>
using namespace std;
struct dot{
    int l,r;
    bool v[10001];
}dots[10001];

int cmp(const dot &a,const dot &b)//比較規則,按區間右端點升序排列 
{
    return a.r<b.r;
} 

int main()
{
    int n,i,j,count=1,select;
    cin>>n;
    for(i=0;i<n;i++)
        cin>>dots[i].l>>dots[i].r;
    sort(dots,dots+n,cmp);//預處理,將區間按規則排好序,方便後續比較 
    select=dots[0].r;
    //貪心策略是選擇區間右端點,保證能夠包含更大交叉段,選的點最少 
    for(i=1;i<n;i++)//每次將當前選擇的一個區間的右端點與下一個(或者同一區間,可忽略)左端比較 
    {
        if(dots[i].l>select)//如果沒有交叉,選點+1,並以此區間右端為新一輪比較的點 
        {
            count++;
            select=dots[i].r;
        }
    }
    cout<<count;
    return 0;
}

View Code

學習算法之後,發現解決問題上需要思維上的改變,程序設計之前的算法選擇很重要,還要向大佬們學習,典型算法的學習研究真是博大精深呀!

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

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

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

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

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

WeTest明星工具-移動端性能測試PerfDog初探

在十一月初,騰訊就官宣了一則消息,騰訊WeTest明星工具-PerfDog面向全球發布。官宣介紹如下:。我在看到該新聞時,有種大開眼界的感覺,移動端的性能測試原來可以這麼簡單。今天閑暇之餘,來了一波初探,簡單體驗了一番。

軟件性能數據採集

我們先來了解下通過該工具能採集到哪些性能數據:

PerfDog支持移動平台所有應用程序(遊戲、APP應用、瀏覽器、小程序等)及Android模擬器,桌面應用程序PerfDog支持在Windows和Mac機器使用運行。在iOS和Android平台獲取性能參數如下:

iOS平台 (與蘋果官方Xcode工具參數對齊一致)

  • Screenshot
  • FPS(1秒內遊戲畫面或者應用界面真實平均刷新次數,俗稱幀率/FPS)
       1) Avg(FPS):平均幀率(一段時間內平均FPS)
       2) Var(FPS):幀率方差(一段時間內FPS方差)
       3) Drop(FPS):降幀次數(平均每小時相鄰兩個FPS點下降大於8幀的次數)
  • Jank(1s內卡頓次數。iOS9.1以下系統暫時不支持。類似Android的Jank卡頓和iOS的FramePacing平滑度統計原理。幀率FPS高並不能反映流暢或不卡頓。比如:FPS為50幀,前200ms渲染一幀,后800ms渲染49幀,雖然幀率50,但依然覺得非常卡頓。同時幀率FPS低,並不代表卡頓,比如無卡頓時均勻FPS為15幀。所以,平均幀率FPS與卡頓無任何直接關係)
        PerfDog計算方法:同時滿足兩條件,則認為是一次卡頓Jank.
        1、 當前幀耗時>前三幀平均耗時2倍。
        2、 當前幀耗時>兩幀電影幀耗時(1000ms/24*2=84ms)。
        同時滿足兩條件,則認為是一次嚴重卡頓BigJank.
        1、 當前幀耗時>前三幀平均耗時2倍。
        2、 當前幀耗時>三幀電影幀耗時(1000ms/24*3=125ms)。
    計算思路:考慮視覺慣性,假設以前三幀的平均幀耗時為參考,作為vsync時間間隔,連續兩次vsync沒有新渲染畫面刷新,則認為是一次潛在卡頓,也就是說下一幀耗時大於前三幀平均幀耗時2倍,則認為一次潛在卡頓。同時單幀耗時滿足大於兩倍電影幀耗時1000ms/24*2 (由於人眼低於24幀才能辨別畫面不連續性),則認為是一次真正卡頓。同時若單幀耗時大於3倍電影幀耗時,則認為是一次嚴重卡頓。
    註解:為什麼是兩次vsync?GPU一般是3重緩衝buffer,當前幀已佔用一個buffer,即剩餘2緩衝buffer,人眼一般可容忍2幀延遲。 為什麼是兩幀電影幀耗時?低於24幀畫面,人眼就能感知到畫面不連續性,電影一般都是24幀。即電影幀耗時1000ms/24=41.67ms,兩幀電影幀耗時也就是41.67ms*2,三幀電影幀耗時是41.67ms*3。
       1) BigJank:1s內頓嚴重卡次數
       2) Jank(/10min):平均每10分鐘卡頓次數。
       3) BigJank(/10min):平均每10分鐘嚴重卡頓次數
  • FTime(上下幀畫面显示時間間隔,即認為幀耗時,iOS9.1以下系統暫時不支持。)
       1) Avg(FTime):平均幀耗時 
       2) Delta(FTime):增量耗時(平均每小時兩幀之間時間差>100ms的次數)
  • CPU Usage(Total整機/App進程,統計結果合Xcode一致)
  • Memory (是統計FootPrint,注:OOM與FootPrint有關,與系統、機型無關。只與RAM有關,如1G內存機器。FootPrint超過650MB,引發OOM)。受iOS平台限制,暫時無法獲取ios10及以下系統的memory。後續版本增加。如做性能測試,建議升級iOS系統版本
  • Xcode Memory (XCode Debug Gauges統計方式即XCode Memory)。受iOS平台限制,暫時無法獲取ios10及以下系統的Xcode Memory。後續版本增加。如做性能測試,建議升級iOS系統版本
  • Real Memory(Xcode Instrument統計方式即Real Memory,實際佔用物理內存。注:物理內存與系統策略有關,關注意義不大)
  • Virtual Memory(虛擬內存)
  • Wakeups(線程喚醒次數)。注:超過150進程很大可能會被系統kill
  • CSwitch(上下文切換測試)。注:單核超過14000進程會被系統Kill
  • GPU Utilization(Render/Tilter/Device)
       1) Render:渲染器利用率(像素着色處理階段,若佔比高,說明是PS階段出現瓶頸,shader過於複雜或紋理大小、採樣複雜等) 
       2) Tilter:Tilter利用率(頂點着色處理階段,若佔比高,說明是VS階段出現瓶頸,頂點數太多等原因)
       3) Device:設備利用率(整體GPU利用率)
  • Network(Recv/Send,測試目標進程流量,和Xcode結果一致)
  • Battery Power(整機實時Current電流、Voltage電壓、Power功率)(注:和Xcode Instrument結果一致)
  • Log(系統調試日誌信息)

Android平台

  • Screenshot
  • FPS(1秒內遊戲畫面或者應用界面真實平均刷新次數,俗稱幀率/FPS)
       1) Avg(FPS):平均幀率(一段時間內平均FPS)
       2) Var(FPS):幀率方差(一段時間內FPS方差)
       3) Drop(FPS):降幀次數(平均每小時相鄰兩個FPS點下降大於8幀的次數)
  • Jank(1s內卡頓次數。解釋說明如iOS平台說明)
       1) BigJank:1s內嚴重卡頓次數
       2) Jank(/10分鐘):平均每10分鐘卡頓次數
       3) BigJank(/10分鐘):平均每10分鐘嚴重卡頓次數 
  • FTime(上下幀畫面显示時間間隔,即認為幀耗時)
       1) Avg(FTime):平均幀耗時
       2) Delta(FTime):增量耗時(平均每小時兩幀之間時間差>100ms的次數)
  • CPU Usage(Total整機/App目標進程,統計結果和Android Studio Profiler一致)
  • CPU Clock(各個CPU核心的頻率和使用率)
  • Memory (PSS Memory,統計結果和Android Java API標準結果一致,與Meminfo也一致。注:部分三星機器系統修改了Meminfo底層統計方式,導致Meminfo與Java AP統計結果不一致,新出三星機器已修復)
  • Swap Memory (Swap Memory)
  • Virtual Memory
  • Memory Detail(NativePSS、GFX、GL、Unknown)
  • GPU Usage(目前僅支持高通芯片手機)
  • GPU Frequency(目前僅支持高通芯片手機)
  • Network(Recv/Send)
  • CTemp(CPU溫度)
  • Battery Power(Current電流、Voltage電壓、Power功率)(注:與儀器測試誤差<3%左右)
  • Log(系統調試日誌信息)

上述內容來自官網使用文檔。我們了解了參數,就實際來操作一下吧。對於工具的介紹,網絡上都有,我就結合自己的實際體驗來說吧。

使用的基本流程

在自己實踐使用時,基本流程如下:

1.註冊賬號(只有註冊賬號后才能下載安裝包)

2.下載安裝包並解壓

3.在perfdog後台創建測試項目

4.打開可執行文件PerfDog.exe

5.使用註冊的賬號登錄

6.使用usb將手機和電腦連接(不能鎖屏,開啟調試模式)

7.選擇連接模式(wifi還是usb)

8.選擇app應用列表

9.配置要監控的數據

10.開始記錄數據

11.操作對應app

12.停止記錄數據(不能少於10S)

13.上傳記錄數據

14.進入perfdog後台查看性能數據

流程介紹

前五步操作就不講述了,大家都懂。我們直接從第六步說起,我使用的是ios設備。

連接設備

iOS: 則即插即用,用戶無需做任何操作。

Android: 有兩種模式,非安裝模式和安裝模式。

  • a. 非安裝模式:

    手機即插即用,無需任何設置及安裝,使用非常簡單,但手機屏幕上沒有實時性能數據显示。

  • b. 安裝模式:

    需要在手機上自動安裝PerfDog.apk,手機屏幕上有實時性能數據显示。(請開啟Debug調試模式、允許USB安裝和PerfDog懸浮窗管理權限),啟動PC版PerfDog.exe,則會在手機上自動PUSH安裝PerfDog.apk,具體安裝類似各個手機廠商安裝第三方APP提示安裝即可。(注:由於很多手機安裝需要賬號密碼,導致無法自動安裝,如果自動安裝失敗,則會把安裝文件PerfDog.apk釋放到當前文件夾里,手動安裝PerfDog.apk即可)。

這裏重點說明下Android平台下,LMK和Swap這兩個參數意義:

LMK:Android平台下OOM與遊戲進程內存大小無關,主要是系統剩餘物理內存有關。系統剩餘物理內存小於LMK,則會引起OOM。

Swap: 系統進程用到zram/vnswap內存壓縮技術。不同手機系統啟用Swap memeroy大小不同。

測試模式

通過usb連接電腦後,出現如下界面,可以選擇測試模式:

USB模式測試:

  USB連線,在設備列表選擇USB圖標設備進行USB模式測試(插線模式測試功率無任何意義)。

WIFI模式測試(測試功率):

  USB連線后,在設備列表選擇WIFI圖標設備進行WIFI模式測試。WIFI檢測連接成功后,拔掉USB連接線。(注:需要PC和被測手機連接同一WIFI,WIFI檢測連接成功后,拔掉被測手機USB線(插線模式測試功率無任何意義))。

在實踐中,USB和WiFi模式我都有使用。選擇模式后,界面會展示設備的詳細信息,如下:

選擇測試應用

選擇模式后,則可以選擇要測試的應用了(當前手機中的所有app都可以被選擇),如下頁面:

選擇對應被測應用,並操作對應的app,界面展示如下:

注意點:Android平台,安裝模式下,手機屏幕左上角有實時性能數據显示(Android手機請打開PerfDog懸浮窗管理權限,否則手機上不會显示性能參數)。

開啟懸浮權限

android設備中的界面性能參數显示如下:

功能介紹

1.性能參數配置

性能參數可在界面中配置,點擊界面中的+號即可,如下:

①點擊對應條目參數,顏色會變深,圖表數據則會展示在界面中

②勾選對應條目參數,表示需要收集該數據

2.記錄保存

點擊右側的藍色開始按鈕,則表示在記錄數據,如下:

需要注意的是:記錄時間不能少於10S。少於10S,則會提示如下信息:

點擊按鈕后,記錄會停止記錄並保存數據,如下:

2.1 提交記錄到perfdog後台

可以修改名稱,點擊confirm,數據會上傳到perfdog的後台,如下:

可以查看詳細的性能數據,如下所示:

2.2 記錄保存到本地

勾選保存按鈕,數據就會保存到本地,如下:

可以打開excel文件查看對應的性能數據:

3.數據回放

點擊perfdog界面上的文件夾按鈕,選擇對應的本地數據,即可以回放記錄,操作如下:

可在界面查看回放結果,如下:

4.批註及標定

雙擊鼠標左鍵,增加批註,再次雙擊,則取消批註。

單擊鼠標左鍵,則增加標定,再次點擊則重新標定。

增加了批註和標定的界面如下所示,紅色為批註,淡紫色為標定:

5.性能參數分析

5.1 數據統計

可以選擇一個時間段內的數據,進行統計,如下:

5.2 設置性能參數統計分析閾值

在perfdog界面中的setting下,可以配置,如下:

5.3 保存框選數據

對某一時間段內的數據框選后,可以單獨保存片段,在框選範圍內,右鍵即可,如下:

6.場景標籤

通過標籤按鈕給性能數據打標籤,鼠標左鍵雙擊顏色區域可修改對應區域標籤名

7.日誌記錄

在perfdog界面,可以查看對應日誌,也可以設置查看日誌的等級,如下:

在嘗試WIFI模式時,發現log按鈕勾選不了。

8.停止功能

停止測試應用,不需要拔掉數據線,或者斷開連接,在選擇應用的界面中,選擇NULL即可,如下:

9.截圖錄屏

連接安卓設備,並使用安裝模式,可配置截屏參數,如下:

界面就會記錄操作的過程,如下所示:

如此記錄是不是很明了?但這種用法會影響性能參數,實際用途中不推薦。如果覺得新鮮,可以嘗試使用即可。

PerfDog後台使用

1.邀請人員

可以邀請對應人員一起維護測試項目

2.數據共享

數據共享后,可以在任務數據中查看明細,可按android、ios區分,以及app包的版本,設備版本來查看。

使用注意點

1.設備連接

iOS: 若PerfDog檢測不到連接手機或無法測試,請先安裝確保最新iTunes是否能連上手機。

Android: 請開啟手機Debug調試模式及允許USB安裝。

2.截圖記錄影響性能

截屏記錄影響性能(整體FPS影響<=1。小米5:CPU=1%左右。IPhone7P:CPU<2%),若無需請不要開啟截屏。

總結

使用PerfDog工具下來,整體有以下幾點感受。

1.對性能指標的測試,更加便捷;

2.易操作

3.記錄支持回放

4.數據便於管理與查看

PerfDog工具是款不錯的性能測試工具,點贊一波。

最後,附上官方的操作手冊:

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

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

scrapy介紹及使用

scrapy的流程

 

其流程可以描述如下:

  1. 調度器把requests–>引擎–>下載中間件—>下載器
  2. 下載器發送請求,獲取響應—->下載中間件—->引擎—>爬蟲中間件—>爬蟲
  3. 爬蟲提取url地址,組裝成request對象—->爬蟲中間件—>引擎—>調度器
  4. 爬蟲提取數據—>引擎—>管道
  5. 管道進行數據的處理和保存

注意:

  • 圖中綠色線條的表示數據的傳遞
  • 注意圖中中間件的位置,決定了其作用
  • 注意其中引擎的位置,所有的模塊之前相互獨立,只和引擎進行交互

scrapy中每個模塊的具體作用

 

 

 1.scrapy項目實現流程

  • 創建一個scrapy項目:scrapy startproject 項目名

  • 生成一個爬蟲:scrapy genspider 爬蟲名 允許爬取的範圍

  • 提取數據:完善spider,使用xpath等方法

  • 保存數據:pipeline中保存數據

2. 創建scrapy項目

命令:scrapy startproject +<項目名字>

示例:scrapy startproject myspider

生成的目錄和文件結果如下:

 

 

settings.py中的重點字段和內涵

  • USER_AGENT 設置ua
  • ROBOTSTXT_OBEY 是否遵守robots協議,默認是遵守
  • CONCURRENT_REQUESTS 設置併發請求的數量,默認是16個
  • DOWNLOAD_DELAY 下載延遲,默認無延遲
  • COOKIES_ENABLED 是否開啟cookie,即每次請求帶上前一次的cookie,默認是開啟的
  • DEFAULT_REQUEST_HEADERS 設置默認請求頭
  • SPIDER_MIDDLEWARES 爬蟲中間件,設置過程和管道相同
  • DOWNLOADER_MIDDLEWARES 下載中間件

創建爬蟲

命令:scrapy genspider +<爬蟲名字> + <允許爬取的域名>

生成的目錄和文件結果如下:

完善spider

完善spider即通過方法進行數據的提取等操做:

注意:

  1. response.xpath方法的返回結果是一個類似list的類型,其中包含的是selector對象,操作和列表一樣,但是有一些額外的方法
  2. extract() 返回一個包含有字符串的列表
  3. extract_first() 返回列表中的第一個字符串,列表為空沒有返回None
  4. spider中的parse方法必須有
  5. 需要抓取的url地址必須屬於allowed_domains,但是start_urls中的url地址沒有這個限制
  6. 啟動爬蟲的時候注意啟動的位置,是在項目路徑下啟動

 

數據傳遞到pipeline

為什麼要使用yield?

  • 讓整個函數變成一個生成器,有什麼好處呢?
  • 遍歷這個函數的返回值的時候,挨個把數據讀到內存,不會造成內存的瞬間佔用過高
  • python3中的range和python2中的xrange同理

注意:

  • yield能夠傳遞的對象只能是:BaseItem,Request,dict,None

6. 完善pipeline

 

 

 

 

pipeline在settings中能夠開啟多個,為什麼需要開啟多個?

  • 不同的pipeline可以處理不同爬蟲的數據
  • 不同的pipeline能夠進行不同的數據處理的操作,比如一個進行數據清洗,一個進行數據的保存

pipeline使用注意點

  • 使用之前需要在settings中開啟
  • pipeline在setting中鍵表示位置(即pipeline在項目中的位置可以自定義),值表示距離引擎的遠近,越近數據會越先經過
  • 有多個pipeline的時候,process_item的方法必須return item,否則后一個pipeline取到的數據為None值
  • pipeline中process_item的方法必須有,否則item沒有辦法接受和處理
  • process_item方法接受item和spider,其中spider表示當前傳遞item過來的spider

 

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

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

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

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

算法導論

  

一.算法

  非形式地說,算法【algorithm】就是任何定義的計算過程,該過程取某個值或值的集合作為輸入併產生某個值或值的集合作為輸出。這樣算法就是把輸入轉換成輸出的計算步驟的一個序列。

  我們也可以把算法看成是用於求解計算問題的工具。一般來說,問題陳述說明了期望的輸入/輸出關係。算法則描述一個特定的計算過程來實現該輸入/輸出關係。例如,我們可能需要把一個數列進行升序排序。實際上,這個問題經常出現,並且為引入許多標準的設計技術和分析工具提供了足夠的理由。

  輸入:n個數的一個序列(a1,a2,…,an)

  輸出:輸入序列的一個排序(a`1,a`2,…,a`n)

  例如,給定輸入序列(6,3,1,2,8,5),排序算法將返回序列(1,2,3,5,6,8)作為輸出。這樣的輸入序列稱為排序問題的一個實例。一般來說,問題實例由計算該問題解所必需的【滿足問題陳述中的各種約束】輸入組成。

  因為許多程序使用排序作為中間步驟,所以排序是計算機科學中的一個基本操作。因此,已有許多好的排序算法供我們任意使用。對於給定應用,哪個算法最好依賴於一下因素:將要被排序的項數、這些項已被稍微排序的程度、關於項值的可能限制、計算機的體繫結構、以及使用的存儲設備的種類【內存、磁盤或磁帶】。

  若對每個輸入實例算法都以正確的輸出結束,則稱該算法是正確的,並稱正確的算法解決了給定的計算問題。不正確的算法對某些輸入實例可能根本不停止,也可能以不正確的方式結束。與人們期望的相反,不正確的算法只要其錯誤率是可控的,有時還是有用的。例如:在研究大素數算法時,將會是一個具有可控錯誤率的算法。

  算法可以用英文說明,也可以說明成計算機程序,甚至說明成硬件設計。唯一的要求是這個說明必須準確描述所要遵循的計算過程。

二.算法解決那些問題

  排序絕不是已開發算法的唯一計算問題,實際上,算法的實際應用是無處不在的,例如:

  

  1.人類基因工程

    識別人類DNA中所有10萬個基因,確定構成人類DNA的30億個化學基對的序列。

  2.互聯網搜索

    互聯網使得全世界的人都能快速地訪問與檢索大量信息。藉助於一些聰明的算法,互聯網上的網站能夠管理和處理這些海量數據。

  3.电子商務

    电子商務使得貨物能夠以电子方式洽談與交換,並且依賴於信用卡號、密碼和銀行結單這類個人信息的保密性。

  4.製造業、廣告推送等等

  5.A/B兩點的最短路徑

  6.最長公共子序列

  7.工廠流水線設計等等

  雖然這些問題的列表還未窮盡,但是它們卻展示了許多有趣的算法問題所共有的兩個特徵:

    1.存在許多候選解,但絕大多數候選解都沒有解決手頭上的問題。尋找一個真正的解或一個最好的解可能是一個很大的挑戰。

    2.存在實際應用。例如,最短路徑問題就是一個很常見的例子。地圖導航、貨物運輸、網絡路由等等

三.數據結構

  數據結構是一種存儲和組織數據的方式,旨在便於訪問和修改。沒有一種單一的數據結構對所有用途都有效,所有重要的是知道不同數據結構的優點和局限。

四.技術

  

  雖然你可能掌握了很多的算法,但是也許某一天你會遇到這樣一個問題,你一時無法找到一個你所知曉或搜索到的算法來解決它。那麼你需要知道如何自己設計與分析一個算法,並且可以去證明及測試它的效率。

五.并行性

  我們或許可以指望處理器時鐘速度能以某個持續的比率增加多年。然而物理的限制對不斷提高的時鐘速度給出了一個限制:因為功率密度隨着時鐘速度超線性增長,一旦時鐘速度變的足夠快,芯片就有融化的危險。因此,為了每秒執行更多的計算,芯片被設計成包含不止一個核心,不同核心之間可以并行執行。因此,為了算法從多核計算機中獲得最佳性能,設計算法時必須考慮并行性。

六.算法無處不在

  

  我們應該像計算機硬件一樣把算法看成一種技術。整個系統的性能不但依賴於選擇快速的硬件而且還依賴於選擇有效的算法。可能你會想,我只是開發一個簡單的WEB程序,只有html和css,那麼抱歉,其中還是設計了不少算法,其中,圖形界面的渲染依賴了算法,WEB程序依賴互聯網,網絡中的路由高度依賴路由算法。程序需要中有需要編譯的代碼沒?編譯器也廣泛使用算法。因此,算法時當前計算機中使用的大多數計算的核心。

  進一步說,隨着計算機能力的不斷增強,我們使用計算機來解決比之前更大的問題,因此,在面對海量的數據時,算法的優劣就顯得尤為重要。

  是否具有算法知識與技術的堅實基礎是區分真正熟練的程序員與初學者的一個特徵。使用現代計算技術,如果你對算法懂得不多,你也可以完成一些任務,但是,如果有一個好的算法背景,那麼你可以做的事情就會多得多。

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

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

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

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

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

SpringBoot系列之切換log4j日誌框架

SpringBoot系列之使用切換log4j日誌框架

ok,在pom文件右鍵->Diagrams->show Dependencies….,如圖,找到spring-boot-starter-logging,可以看到SpringBoot的日誌實現默認依賴與logback,ok,如果你對這些知識不是很理解的,建議先看我Springboot專欄的日誌系列博客:

本博客要實現的是切換默認日誌框架為log4j,當然是不建議這樣做的,因為log4j有性能問題,所以其作者才開發了logback,不過作為學習的話,還是可以學一下怎麼切換Springboot默認的日誌框架

先去拿一張圖:圖示,切換日誌框架,為了避免衝突,一般都是先排除日誌框架的實現jar,然後再將之前博客提到的偷梁換柱jar,比如log4j-to-slf4j.jar等等先排除,然後再引入對應的日誌實現jar,如圖所示的slf4j-log4j12.jar,因為本博客並非入門教程,所以學習之前請先參考我之前Springboot日誌方面的博客,再來學習

ok,基於slf4j官方提供的知識,我們就可以實踐了,首先選中logback-classic.jar(logback實現jar)、log4j-to-slf4j.jar(將log4j API強制切換回slf4j的偷梁換柱jar),然後右鍵,選擇exclusion

ok,再次打開pom文件,可以看到idea自動幫我們exclusion一些jar了

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>logback-classic</artifactId>
                    <groupId>ch.qos.logback</groupId>
                </exclusion>
                <exclusion>
                        <artifactId>log4j-to-slf4j</artifactId>
                    <groupId>org.apache.logging.log4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

ok,避免日誌衝突,exclusion了logback的實現jar和偷梁換柱的log4j-to-slf4j之後,我們還需要引入log4j的實現jar

<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>

ok,這是slf4j官網的說法,但是我發現在一些舊的版本SpringBoot是有提供spring-boot-starter-log4j這個場景啟動器的,所以我們可以更簡便的做log4j引入

直接exclusion spring-boot-starter-logging:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

然後直接引入log4j的場景啟動器,建議加上版本,因為有些版本並沒有提供log4j配置,本博客是換回1.5.7才支持的,2.2.1的版本仲裁都沒提供對應版本的

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j</artifactId>
            <version>1.3.8.RELEASE</version>
        </dependency>

ok,然後在resources直接丟log4j.properties

# LOG4J rootCategory config
log4j.rootCategory=INFO, stdout, file
# LOG4J console config
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n

# root日誌輸出
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.file=logs/springboot.log
log4j.appender.file.DatePattern='.'yyyy-MM-dd
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n

啟動SpringBoot日誌:

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

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

SpringBoot 正式環境必不可少的外部化配置

前言

中有讀者反應:

部署后運維很不方便,比較修改一個 IP 配置,需要重新打包。

這一點我是深有體會,17 年自學,並很大膽的直接在生產環境用的時候,我都是讓產品經理(此時他充當我們的運維,嘿嘿)用壓縮軟件打開 jar,然後複製出配置,修改完之後再替換回去。為什麼我這麼大膽,因為當時才入行一年,而且覺得有架構師兜底,我就奔放了。你是不知道,當時負責這個項目的開發(c#開發)一開始不想用 SpringBoot 的。

不過如今看到這個問題,我有點震驚,都 9102 年了,竟然還擔心這樣的問題。我想說,哥們,這真的不是事兒。SpringBoot 早就提供了方法來解決這個問題。

SpringBoot 生產特性

SpringBoot 有很多生產特性,可以在生產環境中使用時更加方便。其中外部化配置基本都會用到。

Spring Boot 允許外部化配置,以便相同的應用在不同的環境中工作。
屬性值可以在 Spring 環境中使用 @Value 或 @ConfigurationProperties 使用。

此次參考的版本是 SpringBoot-2.2.0.RELEASE

優先級

外部化配置的優先級順序如下:

  1. Devtools 全局配置:當 devtools 啟用時,$HOME/.config/spring-boot
  2. 測試類中的 @TestPropertySource
  3. 測試中的 properties 屬性:在 @SpringBootTest 和 用來測試特定片段的測試註解
  4. 命令行參數
  5. SPRING_APPLICATION_JSON 中的屬性:內嵌在環境變量或系統屬性中的 JSON
  6. ServletConfig 初始化參數
  7. ServletContext 初始化參數
  8. java:comp/env 中的 JNDI 屬性
  9. Java 系統屬性:System.getProperties()
  10. 操作系統環境變量
  11. 隨機值(RandomValuePropertySource):random.*屬性
  12. jar 包的指定 profile 配置文件:application-{profile}.properties
  13. jar 包的指定 profile 配置文件:application-{profile}.properties
  14. jar 包的默認配置文件:application.properties
  15. jar 包的默認配置文件:application.properties
  16. 代碼內的 @PropertySource註解:用於 @Configuration 類上
  17. 默認屬性:通過設置 SpringApplication.setDefaultProperties 指定

注意:以上用 properties 文件的地方也可用 yml文件

配置隨機值

my.uuid=${random.uuid}

命令行屬性

java -jar -Ddemo=vm demo.jar --demo=arg
  • -Dxxx 為 vm 參數,在代碼中通過 System#getProperty 獲取
  • –xxx 為 spring 命令行參數,通過 Environment#getProperty 獲取,若通過此方法獲取不到,會獲取 vm 同名參數
  • xxx.jar 之後的參數都是 arg 參數,都會在 main 方法中的 arg 數組中獲取到

示例

public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(ArgApplication.class, args);
    LOGGER.info("----------------");
    /* 打印 arg 參數 */
    Arrays.stream(args)
        .forEach(
            arg -> {
              LOGGER.info("arg:{}", arg);
            });
    /* 命令行傳參 demo */
    LOGGER.info("System#getProperty:{}", System.getProperty("demo"));
    LOGGER.info("Environment#getProperty:{}", context.getEnvironment().getProperty("demo"));
}

輸入命令

java -jar -Ddemo=vm arg-0.0.1-SNAPSHOT.jar aaa bbb ccc --demo=arg

效果如下:

----------------
arg:aaa
arg:bbb
arg:ccc
arg:--demo=arg
System#getProperty:vm
Environment#getProperty:arg

而如果執行命令是:

java -jar -Ddemo=vm arg-0.0.1-SNAPSHOT.jar aaa bbb ccc

結果如下:

arg:aaa
arg:bbb
arg:ccc
System#getProperty:vm
Environment#getProperty:vm

如果執行命令是:

java -jar arg-0.0.1-SNAPSHOT.jar aaa bbb ccc --demo=arg

結果如下:

arg:aaa
arg:bbb
arg:ccc
arg:--demo=arg
System#getProperty:null
Environment#getProperty:arg

屬性文件

優先級:

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

如果定義了 spring.config.location,如:classpath:/custom-config/,file:./customr-config/,優先級如下:

  1. file:./custom-config/
  2. classpath:custom-config/

如果指定了 spring.config.additional-location,會先加載 additional 配置 如:spring.config.additional-location=classpath:/custom-config/,file:./customr-config/,優先級如下:

  1. file:./custom-config/
  2. classpath:/custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

指定 profile 的屬性

默認的 profile 是 default,當沒有指定spring.profiles.active 屬性時,默認會加載application-default.properties 文件。指定 profiles 文件的加載順序與上述不指定 profiles 文件的加載一致。指定 profile 文件的屬性始終覆蓋未指定文件的屬性。如:spring.profiles.active=dev,則 application-dev.properties文件內的屬性會覆蓋 application.properties 內的同名屬性。

注意:如果在 spring.config.location 屬性中指定了 文件,則此文件對應的特定 profiles 類文件不起作用。如果想要起作用,在 spring.config.location 中使用 文件夾

佔位符

配置文件中可以引用之前定義的值,如下:

app.name=MyApp
app.description=${app.name} is a Spring Boot application.

可以用此特性創建一些已存在的 Spring Boot 配置的較短、易於使用的變量。如下:

# nacos 配置示例
spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: d9a39d78-xxxxxxxx-ea4f282e9d99
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: d9a39d78-xxxxxxxx-ea4f282e9d99
# Discovery 配置示例        
nacos:
  plugin:
    namespace: d9a39d78-xxxxxxxx-ea4f282e9d99

可改為如下配置

spring:
  cloud:
    nacos:
      config:
        server-addr: ${app.server-addr}
        namespace: ${app.namespace}
      discovery:
        server-addr: ${app.server-addr}
        namespace: ${app.namespace}
# Discovery 配置示例        
nacos:
  plugin:
    namespace: ${app.namespace}

app:
  server-addr: 127.0.0.1:8848
  namespace: d9a39d78-xxxxxxxx-ea4f282e9d99

然後在命令行可以直接通過 -Dapp.namespace--app.namespace 來傳參,會方便很多。特別是在多個地方用到同一個屬性的時候。

屬性加密

Spring Boot 不支持屬性加密,但提供鈎子節點修改配置屬性。EnvironmentPostProcessor 接口允許在應用啟動前操作 Environment

yaml

yaml 文件使用的時候非常直觀、方便。而且在 Spring Boot 中做了處理,獲取 yaml 和 properties 文件中的屬性基本是一樣的操作。

一個文件指定多 pfofile

通過 spring.profiles 指示何時使用對應的配置,使用 ---進行配置分隔

# application.yml
server:
  address: 192.168.1.100
---
spring:
  profiles: development
server:
  address: 127.0.0.1
---
spring:
  profiles: production & eu-central
server:
  address: 192.168.1.120

yaml 缺點

@PropertySource 不能加載 yaml 文件,這種情況下只能使用 properties 文件。

在特定 profile 的 yaml 文件中使用多 profile 配置,會有意料之外的情況:

# application-dev.yml
server:
  port: 8000
---
spring:
  profiles: "!test"
  security:
    user:
      password: "secret"

當運行時指定 --spring.profiles.active=dev ,啟用 dev profile,其它的 profile 會忽略。也就是此例中 spring.security.user.password 屬性會失效。

因此,不要在指定 profile 的 yaml 文件中使用多種 profile 配置。

類型安全的屬性配置

JavaBean 屬性綁定

通過 @ConfigurationProperties 註解將屬性(properties、yml 文件、環境變量等)綁定到類對象中。與自動配置類類似。

@ConfigurationProperties("acme")
public class AcmeProperties{
    private boolean enabled;
    private InetAddress remoteAddress;
    private final Security security = new Security();
    // getter and setter
    public static class Security{
        private String username;
        private String password;
        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
         // getter and setter
    }
}

這種安排依賴於默認的無參構造器,getter 和 setter 通常是必需的,因為綁定就像 Spring MVC 一樣是通過標準的 Java Beans 屬性描述符進行的。在下列情況下,可省略 setter:

  • Maps:只要被初始化后,getter 必須而 setter 不必須,binder 可以對它們進行修改
  • Collections 和 數組:可以通過索引或逗號分隔的值來設定屬性。後者必須有 setter 方法。建議對於這種情況一直加上 setter。如果初始化了一個 Collection,確保它不是不可變類型。
  • 如果初始化了嵌套的 POJO 屬性(如上例中的 Security),setter 不是必須的。如果需要 binder 通過其默認構造器動態創建實例,則需要 setter

注意:如果使用 Lombok 生成 getter 和 setter,確保不會生成任何特定的構造器,不然容器會自動使用它來實例化對象。
最後,只有標準 Java Bean 屬性可以這樣綁定屬性,靜態屬性不支持。

構造器綁定

上述示例可以改成如下:

@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties{
  private final boolean enabled;
  private final InetAddress remoteAddress;
  private final Security security;
  
  public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security){
      this.enabled = enabled;
      this.remoteAddress = remoteAddress;
      this.security = security;
  }
  // getter and setter
  
  public static class Security{
      private final String username;
      private final String password;
      private final List<String> roles;
      public Security(String username, String password, @DefaultValue("USER") List<String> roles){
          this.username = username;
          this.password = password;
          this.roles = roles;
      }
      // getter and setter
  }
}

@ConstructorBinding 註解表示使用構造函數綁定屬性值。這意味着 binder 將期望找到一個包含待綁定參數的構造器。
@ConstructorBinding 類的嵌套成員也將通過構造函數綁定屬性值。

可以使用 @DefaultValue 指定默認值,轉換服務將字符串值強轉為缺少屬性的目標類型。

要使用構造綁定,類必須允許使用 @EnableConfigurationProperties 或 配置屬性掃描方式。不能對由常規 Spring 機制創建的 bean 使用構造函數綁定。如:@Component Bean、通過@Bean 方法創建的 Bean 或使用@Import 加載的 Bean

如果類中有多個構造器,可以直接將 @ConstructorBinding 註解使用在要綁定的構造器上。

啟用 @ConfigurationProperties 註解類型

Spring Boot 提供了一個基礎設施來綁定這些類型並將它們自動註冊為 bean。
如果應用程序中使用 @SpringBootsApplication,用 @ConfigurationProperties 註解的類將被自動掃描並註冊為 bean。默認情況下,將從聲明此註解的類的包中進行掃描。如果要掃描特定的包,可以對 ·@SpringBootsApplication 註解的類顯式使用 @ConfigurationPropertiescan 註解,如下例所示:

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}

有時,用 @ConfigurationProperties 註釋的類可能不適合掃描,例如,如果正在開發自己的自動配置,在這些情況下,可以在任何@Configuration 類上指定要處理的類型列表,如下例所示:

@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration { }

注意:當使用配置屬性掃描或通過@EnableConfigurationProperties 註冊@ConfigurationProperties bean 時,bean 有一個常規名稱:<prefix>-<fqn>,其中 <prefix>@ConfigurationProperties 註解中指定的環境 key 前綴,<fqn> 是 bean 的完全限定名。如果註解沒有提供任何前綴,則只使用 bean 的完全限定名。
上例中 bean name 是 acme-com.example.AcmeProperties

使用@ConfigurationProperties 註解類型

這種類型的配置在 SpringApplication 外部 YAML 配置中特別適用,如下例所示:

# application.yml

acme:
  remote-address: 192.168.1.1
  security:
    username: admin
    roles:
      - USER
      - ADMIN

@ConfigurationProperties bean 可以像其它 bean 一樣注入使用。如下:

@Service
public class MyService{
    private final AcmeProperties properties;
    
    @Autowired
    public MyService(AcmeProperties properties){
        this.properties = properties;
    }
    
    // ...
}

使用 @ConfigurationProperties 還可以生成元數據文件,IDE 可以使用這些文件提供代碼自動完成功能。

第三方配置

除了可以在 上使用 @ConfigurationProperties 註解,還可以在 public @Bean 方法上使用它。如果要將屬性綁定到不在控制範圍內的第三方組件,那麼這樣做特別有用。

要從 Environment 屬性配置 bean,將 @ConfigurationProperties 添加到其 bean 註冊中,如下例所示:

@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
    //... 
}

another 前綴定義的任何 JavaBean 屬性都映射到 AnotherComponent bean 上,映射方式類似於前面的 AcmeProperties 示例。

鬆綁定

Spring Boot 使用一些寬鬆的規則將 Environment 屬性綁定到@ConfigurationProperties bean,因此環境屬性名和 bean 屬性名之間不需要完全匹配。常見的包括短劃線分隔的環境屬性(例如,context-path 綁定到 contextPath)和大寫的環境屬性(例如,PORT 綁定到 port)。

@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
    private String firstName;
    public String getFirstName() {
        return this.firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}

對於以上 Java Bean,可以使用以下屬性

注意:註解的前綴值必須是短橫線 (小寫,用-分隔,如:acme.my-project.person)。

放寬每個屬性源的綁定規則

建議:如果可能的話,將屬性存儲為小寫的短橫線格式,例如:my.property-name=acme。

在綁定到 Map 屬性時,如果 key 包含除小寫字母-数字字符或 - 之外的任何內容,則需要使用括號符號,以便保留原始值。如果 key 沒有被[]包圍,則刪除任何不是字母数字或 -的字符。

acme:
  map:
    "[/key1]": value1
    "[/key2]": value2
    /key3: value3

上面的屬性將綁定到 Map 的這些 key 中:/key1/key2key3

合併複雜類型

List

當在多個位置配置 list 時,通過替換(而非添加)整個 list 來覆蓋。

@ConfigurationProperties("acme")
public class AcmeProperties {
    private final List<MyPojo> list = new ArrayList<>();
    public List<MyPojo> getList() { return this.list;
    }
}
acme:
  list:
    - name: my name
      description: my description
---
spring:
  profiles: dev
acme:
  list:
    - name: my another name

當啟用 dev 配置時,AcmeProperties.list 中值包含一個 MyPojo 對象(name 為my another name),不是添加操作,而是覆蓋操作。

當一個 List 在多個 profiles 中定義時,最高優先級的被使用。

Map

對於 Map 屬性,可以使用從多個屬性源獲取屬性值進行綁定。但是,對於多個源中的同一屬性,將使用優先級最高的屬性。

@ConfigurationProperties("acme")
public class AcmeProperties {
    private final Map<String, MyPojo> map = new HashMap<>();
    public Map<String, MyPojo> getMap() {
    return this.map;
    }
}
acme:
  map:
    key1:
      name: my name 1
      description: my description 1
---
spring:
  profiles: dev
acme:
  map:
    key1:
      name: dev name 1
    key2:
      name: dev name 2
      description: dev description 2

當 dev 配置啟用時,AcmeProperties.map 中包含兩個鍵值對。key1 中 pojo name 為 dev name 1,description 為 my description 1;key2 中 pojo name 為 dev name 2,description 為 dev description 2。

不同屬性源的配置進行了合併

以上合併規則適用於所有的屬性源

屬性轉換

Spring Boot 試圖在綁定到 @ConfigurationProperties bean 時將外部應用程序屬性強轉為正確的類型。如果需要自定義類型轉換,可以提供 ConversionService bean(帶有名為 ConversionService 的 bean)或自定義屬性編輯器(通過 CustomEditorConfigurer bean)或自定義 Converters (使用 bean 定義註解 @ConfigurationPropertiesBinding )。

注意:由於此 bean 在應用程序生命周期的早期被請求,請確保限制 ConversionService 正在使用的依賴項。通常,需要的任何依賴項在創建時都可能未完全初始化。如果自定義的 ConversionService 不需要配置 keys 強轉,並且僅依賴於使用 @ConfigurationPropertiesBinding 限定的自定義轉換器,則可能需要將它重命名。

時間區間轉換

SpringBoot 對錶示持續時間有專門的支持。如果暴露 java.time.Duration 屬性,則可以用以下格式:

  • 常規的 long 表示(除非指定了 @DurationUnit,否則使用毫秒作為默認單位)
  • java.time.Duration 使用的標準 ISO-8601 格式
  • 一種更可讀的格式,其中值和單位是耦合的(例如,10s 表示 10 秒)
@ConfigurationProperties("app.system")
public class AppSystemProperties {

    @DurationUnit(ChronoUnit.SECONDS)
    private Duration sessionTimeout = Duration.ofSeconds(30);

    private Duration readTimeout = Duration.ofMillis(1000);

    public Duration getSessionTimeout() {
        return this.sessionTimeout;
    }

    public void setSessionTimeout(Duration sessionTimeout) {
        this.sessionTimeout = sessionTimeout;
    }

    public Duration getReadTimeout() {
        return this.readTimeout;
    }

    public void setReadTimeout(Duration readTimeout) {
        this.readTimeout = readTimeout;
    }

}

要指定 30 秒的 sessionTimeout,30、PT30S 和 30s 都是等效的。500ms 的 readTimeout 可以用以下任何形式指定:500、PT0.5S 和 500ms。
也可以使用以下任何支持的單位:

  • ns:納秒
  • us:微妙
  • ms:毫秒
  • s:秒
  • m:分
  • h:時
  • d:天

默認的單位是毫秒,可以使用 @DurationUnit 指定

數據 size 轉換

Spring 框架有一個 DataSize 類型,以字節表示大小。如果暴露一個 DataSize 屬性,則可以用以下格式:

  • 常規的 long 表示(除非指定了 @DataSizeUnit,否則使用字節作為默認單位)
  • java.time.Duration 使用的標準 ISO-8601 格式
  • 一種更可讀的格式,其中值和單位是耦合的(例如,10MB 表示 10 兆字節)。
@ConfigurationProperties("app.io")
public class AppIoProperties {

    @DataSizeUnit(DataUnit.MEGABYTES)
    private DataSize bufferSize = DataSize.ofMegabytes(2);

    private DataSize sizeThreshold = DataSize.ofBytes(512);

    public DataSize getBufferSize() {
        return this.bufferSize;
    }

    public void setBufferSize(DataSize bufferSize) {
        this.bufferSize = bufferSize;
    }

    public DataSize getSizeThreshold() {
        return this.sizeThreshold;
    }

    public void setSizeThreshold(DataSize sizeThreshold) {
        this.sizeThreshold = sizeThreshold;
    }

}

要指定 10 兆字節的 bufferSize1010MB 是等效的。256 字節的 sizeThreshold 可以指定為 256256B
也可以使用以下任何支持的單位:
B:字節
KB:千字節
MB:兆字節
GB:千兆字節
TB:兆兆字節

默認的單位是字節,可以使用 @DataSizeUnit 指定

@ConfigurationProperties 校驗

每當對 @ConfigurationProperties 類使用 Spring 的@Validated 註解時,Spring Boot 就會驗證它們。可以直接在配置類上使用 JSR-303 javax.validation 約束註解。必須確保類路徑上有一個兼容的 JSR-303 實現(如:hibernate-validator),然後將約束註解添加到字段中。

@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
    @NotNull
    private InetAddress remoteAddress;
    
    // ... getters and setters
}

注意:還可以通過註解@Bean 方法來觸發驗證,該方法使用@Validated 創建配置屬性。

儘管嵌套屬性在綁定時也將被驗證,但最好對關聯字段使用 @Valid。這確保即使找不到嵌套屬性,也會觸發驗證。

@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {

    @NotNull
    private InetAddress remoteAddress;

    @Valid
    private final Security security = new Security();

    // ... getters and setters

    public static class Security {

        @NotEmpty
        public String username;

        // ... getters and setters

    }

}

還可以通過創建ConfigurationPropertiesValidator bean 來添加自定義 Spring Validator@Bean 方法應該聲明為 static 。配置屬性驗證器是在應用程序生命周期的早期創建的,將@Bean 方法聲明為 static 可以創建 Bean,而無需實例化@configuration 類。這樣做可以避免任何可能由早期實例化引起的問題。

注意:spring-boot-actuator 模塊包含一個端點,該端點暴露所有 @ConfigurationProperties bean。訪問 /actuator/configprops 可獲得相關信息。

@ConfigurationProperties vs. @Value

@Value 註解是一個核心容器特性,它不提供與 @ConfigurationProperties 相同的特性。

如果需要為組件定義了一組配置鍵,建議將它們配置到一個 @ConfigurationProperties 註解的 POJO 中。由於 @Value 不支持鬆綁定,如果需要使用環境變量提供值,則它不是一個好的選項。
雖然可以在 @Value 中編寫 SpEL 表達式,但此類表達式不會從 properties 文件中處理。

使用配置中心

如果項目比較大的話,分成了好幾個 SpringBoot 工程,可以使用某些 SpringCloud 組件,比如:配置中心。配置中心支持一個地方管理所有的配置,有些還可以支持修改配置實時生效而不用重啟應用,真的是很棒棒呢。推薦使用 nacos。如果項目比較小,你用 git 或者指定文件夾來作為配置存放的地方也可以。

怎麼樣?有了這些用法的支持,你還會覺得 Springboot 打成一個 jar 會在部署的時候很不方便嗎?

參考資料

公眾號:逸飛兮(專註於 Java 領域知識的深入學習,從源碼到原理,系統有序的學習)

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

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

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

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