長頸鹿數量驟減 面臨無聲滅絕危機

摘錄自2019年08月17日中央通訊社非洲報導

在東非國家肯亞或非洲各地,世界最高哺乳動物長頸鹿的數量正悄悄地驟減。截至2018年的過去30年左右,肯亞、索馬利亞和衣索比亞的網紋長頸鹿(Reticulated giraffe)數量銳減60%。

自然保育聯盟(IUCN)掌握的數據顯示,1985年至2015年間,非洲大陸的長頸鹿數量大減40%,已經略低於10萬頭。同時,努比亞長頸鹿(Nubian giraffe)數量悲劇性大減97%,這個罕見物種幾乎要完全滅絕。非洲中部更偏遠地區,柯多方長頸鹿(Kordofan giraffe)數量也減少85%。

但較少人會注意到長頸鹿數量危機。長頸鹿專家芬尼西(Julian Fennessy)說:「長頸鹿是一種大型動物,你可以很容易在國家公園和保育區看見牠。這可能會製造一種錯誤印象,認為這個物種狀況良好。」

IUCN指出,盜獵、棲地遭破壞和地區衝突是導致這種溫和生物族群驟減的主因。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理

【職業甘苦談】

※幫你考照過關,堆高機裝卸操作教學影片大公開 !

※找工作! 想知道堆高機駕駛日薪是多少嗎? 哪裡有職缺?幫你快速媒合

 

巴西NGO:近一年亞馬遜森林砍伐增加16%

摘錄自2019年8月17日中央社巴西報導

巴西NGO亞馬遜人類環境研究所(Imazon)17日發布亞馬遜森林砍伐調查指出,去年8月至今年7月,森林損失面積5054平方公里,較前12個月增加16%。

Imazon森林砍伐預警系統在此期間檢測到5054平方公里的森林遭砍伐,主要是在巴拉(Para)、亞馬遜和馬托格羅索(Mato Grosso)等州。單單今年7月,亞馬遜森林破壞總面積即達1287平方公里,比2018年7月增加66%。

這個調查結果與巴西國家太空署監控觀察到的情況相似:2018年8月至2019年7月之間的森林損失面積達6833平方公里,較前12個月增加49.45%。國家太空署的系統觀測到7月伐林面積2254平方公里,較2018年同月增加278%。

近一個月來,國家太空署公布關於森林砍伐加劇的數據,引起巴西政府強烈抨擊,導致擁有超過40年的經驗的太空署長卡爾旺(Ricardo Galvao)辭職。巴西總統波索納洛不止一次地說,這些數據是騙人的,損害巴西在國外的形象,並指責卡爾旺「為一些非政府組織效力。」之後,巴西環境部長薩勒斯(Rocardo Salles)又說,國家太空署的資料有問題,他將聘請一所新的私人機構做監控。本週,巴西環境部已經開始測試新系統。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理【美妝保養品代工推薦】

※想知道哪幾家化妝品odm外銷到海外市場呢?

※尋找保養品odm專業設計、代工廠商?

※想要自創美妝品牌,面膜代工廠哪裡找呢?

※想知道南部地區有哪幾家乳液代工廠?有無產品設計、代工相關流程介紹?

※想找專業化妝水代工廠推薦哪一家?

※乳液代工廠,該選擇OEM、ODM還是OBM??

 

萌樣融化不少人 泰國儒艮寶寶因胃裡塑膠離世

摘錄自2019年8月18日中央社泰國報導

一隻數月前在泰國擱淺的易危海洋生物儒艮,因萌樣融化不少民眾,繼而帶起一股海洋保育風潮。但負責人員18日表示,儒艮胃裡塑膠殘留物導致感染惡化,醫治無效不幸離世。

這隻儒艮小名為馬利安(Mariam),被救上岸後不久,另一隻雄性儒艮幼獸也在同一地點被發現,泰國皇室公主將他取名為賈米爾(Jamil),意思是「帥氣的海中王子」。為了滿足兩隻儒艮寶寶的粉絲,照護人員還設置攝影機,24小時直播牠們的生活動態。但泰國董里府立海洋公園負責人查亞普克(Chaiyapruk Werawong)表示,馬利安18日凌晨突然休克,經急救無效不幸離世,死因是敗血症及胃部化膿,醫護人員也在馬利安腸道發現少量的塑膠垃圾。

獸醫南崔卡(Nantarika Chansue)在臉書上說,驗屍報告結果顯示,馬利安體內的塑膠殘留物導致胃阻塞,進而引起發炎反應與胃脹氣。

儒艮是海牛的近親,目前約有250隻儒艮棲息於馬利安和賈米爾被發現的區域,但泰國沿岸水域佈滿塑膠垃圾,對周遭生物棲息地造成一大威脅。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理【美妝保養品代工推薦】

※化妝品oem是什麼? 與odm有何區別?

※想知道哪一家的化妝品odm,受到各大保養品牌推薦?

※自創保溼美白產品,尋求保養品odm代工廠?

※想知道化妝品製造商如何從開發、設計、代工、包裝、銷售,一條龍作業流程?

※保養品製造商需取得國際級哪些認証?

 

綠島森林火勢 復燃獲控制

摘錄自2019年8月19日聯合報台東報導

台東縣綠島鄉白沙尾防風林15日午間發生森林大火,消防單位陸、空灌救27小時後滅火,不料,殘餘火星於前晚9時許復燃,林務局森林救火隊、綠島消防分隊、空勤總隊直升機再度出勤,昨天中午控制火勢,至晚間仍進行殘火處理。

台東縣消防局火調科表示,經派員前往火場勘查,疑似起火點接近綠島環島公路,但未找到明確火源,起火原因不排除是民眾亂丟菸蒂、中元普度燒紙錢灰燼或有人燒垃圾引燃雜草釀成,但確實火警原因還要調查。

綠島森林大火15日中午發生,經陸、空聯合灌救,16日下午3點才撲滅火勢。林務局森林救火隊留守島上監控,17日晚間9時許死灰復燃。森林救火隊前晚徹夜滅火,昨天一早地面人員在火場附近空地設置可蓄水18公噸大型水囊,由台東縣消防局綠島分隊抽取地下水灌入,方便空勤總隊黑鷹直升機兩噸的水袋就地取水從空中滅火,所幸至中午就控制火勢。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理

【生活常識】

飲用桶裝水到底安不安全? 破解錯誤迷思!

選用哪種桶裝水,外宿露營超方便?

北市爆首例本土登革熱 病患到過基隆、九份

摘錄自2019年8月19日聯合報台北報導

衛福部疾管署昨天公布北市出現本土登革熱,患者為大安區建安里30多歲男性。這是今年北市第一起本土登革熱病例,因患者居住與活動地靠近捷運忠孝敦化站,北市衛生局除了進行戶外消毒,今天也將進行家戶噴藥作業。

疾管署副署長莊人祥表示,該個案近期無出國史,8月15日出現全身痠痛、發燒症狀,當日就醫後返家,因仍感到不適,16日凌晨再次就醫,醫院隨即採檢通報,經檢驗確診登革熱。

莊人祥說,患者平時活動地點在台北市大安區,但8月2日及3日到過台南市東、安南、中西及北區及高雄市興達港;8月10與11日分別至基隆廟口夜市、新北市九份等地,將進一步調查可能感染源,病人目前狀況良好,在家休養。

對於登革熱疫情是否北移?患者是否與前幾天新北二例個案有關?莊人祥表示,該個案感染情況未明,無法確知關聯性;患者比較可能被感染的地方應是住家、工作地或基隆及新北,但登革熱潛伏期最長14天,也不排除是曾到過台南或高雄被感染。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理

【電腦軟硬體應用文章推薦】

※必看的水冷常識,電腦冷卻液有效降低電腦系統內的溫度

Low conductivity coolant 低導電水冷液金屬腐蝕結果測試報告大公開

※DIY水冷式幫浦 Brushless dc pump 優劣比較

綠鬣蜥族群擴散 高屏移除逾2500隻

摘錄自2019年8月19日自由時報高雄報導

外來種生物綠鬣蜥全國現蹤,屏科大野保所教授陳添喜表示,綠鬣蜥族群逐年擴散,今年移除3000多隻,以高屏地區最嚴重,農委會將管制買賣與繁殖,登記才能飼養、未經同意不得繁殖,違者最高恐開罰5萬元,陳添喜肯定有助於抑制綠鬣蜥數量。

高雄市府農業局表示,綠鬣蜥是外來進口寵物,剛出生時小巧可愛,長大可變成2公尺巨獸,台灣在野外沒有天敵,成體食量大,會吃昆蟲並危害農作物蔬菜,威脅台灣原生物種。

屏科大野保所教授陳添喜表示,綠鬣蜥族群逐年擴散,全國均發現蹤跡,自2014年迄今移除7000多隻,前三年抓不到100隻,但今年就移除3000多隻,以高屏地區最嚴重,超過2500隻,且擴散點很多。

農業局指出,綠鬣蜥於鳥松、仁武一帶,有明顯的繁殖地,列為重點捕捉區,鎖定成體加強捕捉,農業局今年委外捕捉超過500隻。民眾一旦發現綠鬣蜥,可打1999通報,千萬不要丟到野外,不但破壞自然生態,政府還要花更多錢善後。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理

【工業材料相關資訊推薦】

北部螺絲、螺帽專賣店-居家修繕大小事!

特製螺絲工廠批發-精密零件專售

不鏽鋼螺絲的應用常識-五金修繕

不鏽鋼螺絲一般用於什麼地方做固定?

高雄雨災農損逾千萬 全國最嚴重

摘錄自2019年8月19日自由時報高雄報導

高雄市連日大雨下不停,傳出土石流、積淹水災情,也造成農業損失擴大,農損增至1100萬元,為全國最嚴重,主要受害作物為木瓜;另六龜區農田受損8公頃,山區那瑪夏區有民眾失蹤搜救中。

此外,農損也持續擴大,增至1100萬元,主要受害作物為木瓜水傷。另有六龜區農田埋沒5公頃、流失3公頃;農業局表示,連日豪雨勘災困難,周四將與專家組成災情確認小組,確認這波豪雨農損程度,呼籲農民主動向區公所通報。

那瑪夏區則有37歲李姓男子8月12日晚上外出不知去向,親友於16日報警協尋,警義消和部落族人在附近農路和工寮地毯式搜索,仍一無所獲;由於山區持續下起豪大雨,親友十分擔心其安危。目前轉往兩權平台及青山巷(東西)沿線搜尋,希望能有好消息。

本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理本站聲明:網站內容來源再生能源資訊網https://e-info.org.tw/,如有侵權請聯繫我們,我們將及時處理

【在地推薦】

家庭、朋友聚會,享受輕鬆烤肉必備外燴烤爐NO.1

各種攤販小吃設備,沙威瑪機自動旋轉烤玉米機,側火烤爐應有盡有!

營業用紅外線烤爐比價站,怕你買貴,幫你找好康~

必買推薦!上下火烤爐全台最便宜都在這!

被台灣之光誤用!俄國設計師暖心「親自畫3張石虎」免費送台灣 感性透露「為你們盡份心力」圖案超可愛

台灣石虎原本數量眾多,然而因為棲息地被人為開發,生存空間受到壓縮,數量越來越少,更有學者推估,只有不到500隻,然而即使如此,卻頻頻傳出有石虎為了出外覓食、巢穴被馬路過於逼近等,被用路人直接碰上而離開的新聞,有鑑於此,交通部為了讓大家記住保育石虎的重要性,希望在有「石虎娘家」之稱的集集彩繪列車,畫上石虎的圖案,讓更多人了解這個美麗又無害的生物。

圖片來源:《自由時報》

影片來源:東森新聞 CH51

孰料列車推出後,原本受到很多民眾的好評,然而卻有專家指出,畫中的動物更近似於「花豹」,特生中心更指出,該有的「石虎特徵」幾乎都沒有,引起外界討論不斷,孰料又被網友起底,其實這個「完全不像石虎」的圖案,照理說應該由台灣之光設計師江孟芝,收下設計費後,竟然向國外圖庫買下圖案,最後由台鐵耗資300萬元打造石虎彩繪列車,讓外界有夠傻眼。

圖片來源:《上報》

尤其消息傳到圖案原作者,俄國的Катя Молодцова耳裡,她首先在社群平台強調,自己原本設計的就是花豹,根本不是什麼石虎,所以被誤用也很遺憾,不過熱情的她表示,「在聽到台灣的石虎瀕臨滅絕的危機後」,又親自繪製了石虎圖案,希望公開授權,送給台灣的民眾免費使用。

圖片來源:Катя Молодцова提供,下同。

消息傳出後,原本觀光局表示,可能要婉拒對方的好意,不過因為討論實在太熱烈,交通部長林佳龍稍早在臉書發文,已經親自到對方的IG留言致謝,並邀請對方,9月21日來台灣參加通車典禮。

對於Катя Молодцова為了替石虎盡一份心力,親自繪圖送給台灣,又將自己的IG大頭照,換成石虎的圖案,很多民眾都非常感動,紛紛留言:「之前的設計費應該給這位人美心也美的設計師!」、「一個俄國人,比台灣之光更在乎台灣!」、「太感動了吧!比我們還在意石虎,尤其還親自原創繪圖,之前的設計師到底是…」也有網友認為,設計師送的貼圖「比原本的更可愛啊,採用了很合理!」

設計師真的是人美心也美,希望她真的能來到台灣,見識台灣最美的風景啊!

本站聲明:網站內容來源http://www.look543.com,如有侵權,請聯繫我們,我們將及時處理

電子菸
電子煙
電子菸

Trie|如何用字典樹實現搜索引擎的關鍵詞提示功能

Trie字典樹

Trie字典樹又稱前綴樹,顧名思義,是查詢前綴匹配的一種樹形數據結構

可以分為插入(創建) 和 查詢兩部分。參考地址極客時間

下圖為插入字符串的過程:

創建完成后,每個字符串最後一個字母標記為終結點(圖中显示為紅色)

下圖為查詢字符串:“her”的過程:綠色箭頭表示查詢路徑
我們將要查找的字符串分割成單個的字符 h,e,r,一個一個查詢

下圖為查詢字符串:“he”的過程:綠色箭頭表示查詢路徑
因為‘e’不是終結點,所以不能完全匹配上。

Trie字典樹的實現

1.首先是字典樹 數據結構定義的代碼實現

樹形結構,類比於二叉樹的存儲嘛,每個結點兩條分支(二叉樹);
而字典樹,每個節點可以最多有 26個分支(存儲英文字母)。

1-1二維數組存儲字母

int trie[MAX_NODE][26];//MAX_NODE表示結點數量,每個結點有26個字母結點
int k;

MAX_NODE表示結點數量,每個結點有26個字母結點
Trie[i][j]的值是0,表示trie樹中i號節點,並沒有一條連出去的邊滿足邊上的字符標識是字符集中第j個字符(從0開始);
trie[i][j]的值是正整數x表示trie樹中i號節點,有一條連出去的邊滿足邊上的字符標識是字符集中第j個字符,並且
這條邊的終點是x號節點。

1-2鏈表
我這裏用C++中的vector實現,

vector< pair<char, int> > trie[MAX_NODE];
int k;

也可以寫一個真正的鏈表,包含二元組字段<char,int>型的對應關係

1-3hash,

map<char, int> trie[MAX_NODE];

每次我們想找i號節點有沒有標識
是某個字符ch的邊時,只要看trie[i][ch]的值即可
但是實際上map時空複雜度的常數都比較大

2.插入 和 查詢 兩個函數的代碼實現

插入 查詢 實際上是類似的,就是從樹的根開始往下遍歷,

2-1插入:從樹的根開始往下遍歷,到達一個結點,沒有這個字母就插入到這個結點下,作為這個結點的子節點

基於二維數組結構的插入功能實現

代碼的第6~8行,一開始trie[][]被初始化為0,保證每個節點被創建出來時,都沒有子節點。K初
始化為1表示一開始只有1個節點,也就是0號節點根節點。Color是用來標記一個節點是不是終結
點。Color[i]=1標識i號節點是終結點。
第9~21行是插入函數insert(w),w是字符指針,實際上可以看作是一個字符串。
第11行是p從0號節點開始。
第12~19行是依次插入w的每一個字符。
第13行是計算w[i]是字符集第幾個字符,這裏我們假設字符集只包含26個小寫字母。
第14~17行是如果p沒有連出標識是w[i]的邊,那麼就創建一個。這裏新創建的節點一定就是k號節
點。所謂創建新節點實際上也沒什麼可創建的,新節點就是個編號。所以我們直接令trie[i][c]=k
即可,然後將k累加1,整個創建過程就完成了。
第18行是沿着標記着w[i]的邊移動到下一個節點。
最後第20行,是將最後到達的節點p標記為終結點。

2-2查詢:從樹的根開始往下遍歷,查看是否匹配上當前正在查的單詞
基於二維數組結構的查詢功能實現

第24行是從p=0也就是根節點開始。
第25~29行是枚舉s的每一個字符。
第26行是計算當前字符s[i]在字符集的序號。
第27行是判斷p節點有沒有連出標識s[i]字符的邊,如果沒有,說明現在無路可走,直接返回0;如
果有的話,
第28行就是移動到下一個節點。如果整個循環結束還沒有return 0,那就說明成功沿着s的每一個
字符到達了p節點。這時只要判斷p節點是不是終結點即可,也就是第30行的代

3.完整代碼C++版

public class Trie {
  private TrieNode root = new TrieNode('/'); // 存儲無意義字符

  // 往 Trie 樹中插入一個字符串
  public void insert(char[] text) {
    TrieNode p = root;
    for (int i = 0; i < text.length; ++i) {
      int index = text[i] - 'a';
      if (p.children[index] == null) {
        TrieNode newNode = new TrieNode(text[i]);
        p.children[index] = newNode;
      }
      p = p.children[index];
    }
    p.isEndingChar = true;
  }

  // 在 Trie 樹中查找一個字符串
  public boolean find(char[] pattern) {
    TrieNode p = root;
    for (int i = 0; i < pattern.length; ++i) {
      int index = pattern[i] - 'a';
      if (p.children[index] == null) {
        return false; // 不存在 pattern
      }
      p = p.children[index];
    }
    if (p.isEndingChar == false) return false; // 不能完全匹配,只是前綴
    else return true; // 找到 pattern
  }

  public class TrieNode {
    public char data;
    public TrieNode[] children = new TrieNode[26];
    public boolean isEndingChar = false;
    public TrieNode(char data) {
      this.data = data;
    }
  }
}

Trie字典樹的時間複雜度 與 缺點

插入的時間複雜度:O(N),N為所有待插入字符串的長度之和
查詢的時間複雜度:O(K),K為待查詢字符串的長度

占內存:如果用二維數組實現,每個節點就會額外需要 26*8=208 個字節
優化思路:將每個節點中的數組換成其他數據結構,比如有序數組(可以二分查找)、跳錶、散列表、紅黑樹等。

Trie變體,縮點優化:對只有一個子節點的節點,而且此節點不是一個串的結束節點,可以將此節點與子節點合併

Trie字典樹的實際應用

1.搜索引擎輸入框關鍵詞提示

因為字典樹是查找 “與前綴匹配的字符串”,又稱為前綴樹。
關鍵詞提示就是 查尋找前綴匹配的前綴合適關鍵詞,當然還有更複雜的關鍵詞排名問題,這裏不再展開。

2.自動補全功能,如:IDE編譯器自動補全,輸入法自動補全等

原理與搜索引擎類似。

3.敏感詞過濾系統

4.其它

Trie在面試與算法競賽中的例題

1.hihoCoder1014

hihoCoder1014

解題思路:Trie字典樹

首先我們把集合中的N個字符串都插入到trie中。
對於每一個查詢s我們在trie中查找s,如果查找過程中無路可走,那麼一定沒有以s為前綴的字符串。
如果最後停在一個節點p,那我們就要看看以p為根的子樹里一共有多少終結點。
終結點的數目就是答案。

但是如果我們每次都遍歷以P為根的子樹,那時間複雜度就太高了。解決的辦法是用空間換時間,我們增加一個數組intcnt[MAX_NODE]
cnt[i]記錄的是以i號節點為根的子樹中,有幾個終結點。
然後我們每次insert一個字符串的時候,順便就把沿途的節點的cnt值都+1。
這樣就不用每次遍歷以P為根的子樹,而是直接輸出cnt[P]即可。

代碼:

2.hihoCoder1107微軟面試題

hihoCoder1014

其實就是找一個節點p,滿足以p為根的子樹中的終結點不多於5個,同時以p的父節點為根的子樹中的終結點大於5個。
和上題一樣用cnt數組標記,之後dfs查找終結點的數目

3.Trie應用在整數xor異或值最大的題目

給定一個包含N個整數的集合S={A1, A2, A3, … AN}。然
後有M個詢問,每次詢問給定一個整數X,讓你找一個Ai使得Ai xor X的值最大。

首先我們知道一個整數可以用二進製表示成一個01串。比如3=(011)2, 5=(101)2, 4=(100)2……。
我們假設輸入的整數都在0~2^32-1之間,於是我們可以用一個長度是32位的01串表示一個整數。
然後對於給定的N個整數A1, A2, A3, … AN,我們把它們對應的01串都插入到一個trie中。注意這裏字符集只有0和1,所以整個trie是一棵二叉樹。

下面我們舉一個例子,為了描述方便,我們假設整數都在0~7之間,也就是可以用3位01串表示。
現在假設S={1, 2, 7},也就是說我們要在Trie中插入{001, 010, 111}:

這時假設我們要查詢x=4,也就是哪個數和4異或結果最大?4=(100)2,
我們的做法是在trie樹中,盡量與4的二進制位反着走。
比如4的第一位(最高位)是1,我們從0出發第一步就盡量沿着0走。因為我們要異或和最大,01相反才能異或值是1。
並且這一步是可以貪心的,也就是說如果有相反的邊,那麼我們一定沿着這條邊走。因為最高位異或得1的話,即便後面都是0, 10000…000也要比最高位是0,後面都是1的011111…111大。
所以我們第一步沿着標識是0的邊,移動到了1號節點;4第二位是0,所以我們沿着標識是1的邊移動到4號節點;
4的第三位是0,但是4號節點沒有標識是1的邊,所以我們也只好沿着標識是0的邊移動到5號節點。
已經到了終結點,所以5號節點對應的A2=(010)2=2就是我們要求的答案,A2 xor 4 = 6是最大的。

【精選推薦文章】

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

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

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

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

ApplicationContextRunner如何簡化自動配置測試

 

1. 概覽

眾所周知,自動配置是Spring Boot的關鍵功能之一, 但測試自動配置可能會很棘手。

在以下部分中,我們將展示ApplicationContextRunner如何簡化自動配置測試。

2. 測試自動化配置方案

ApplicationContextRunner是一個實用程序類,它運行ApplicationContext並提供AssertJ樣式斷言。 最好用作測試類中的字段以便共享配置,然後我們在每個測試中進行自定義:

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();

讓我們通過測試一些案例來展示它的魔力。

2.1. 測試Class Condition

在本節中,我們將測試一些使用@ConditionalOnClass和@ConditionalOnMissingClass 註解的自動配置類:

@Configuration
@ConditionalOnClass(ConditionalOnClassIntegrationTest.class)
protected static class ConditionalOnClassConfiguration {
    @Bean
    public String created() { return "This is created when ConditionalOnClassIntegrationTest is present on the classpath"; } } @Configuration @ConditionalOnMissingClass("com.baeldung.autoconfiguration.ConditionalOnClassIntegrationTest") protected static class ConditionalOnMissingClassConfiguration { @Bean public String missed() { return "This is missed when ConditionalOnClassIntegrationTest is present on the classpath"; } } 

我們想測試自動配置是否正確實例化或跳過createdmissing beans給定的預期條件。

  • ApplicationContextRunner為我們提供了withUserConfiguration方法,我們可以根據需要提供自動配置,以便為每個測試自定義ApplicationContext

  • run 方法將 ContextConsumer 作為將斷言應用於上下文的參數。 測試退出時,ApplicationContext將自動關閉:

@Test
public void whenDependentClassIsPresent_thenBeanCreated() {     this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class)       .run(context -> {         assertThat(context).hasBean("created");         assertThat(context.getBean("created"))           .isEqualTo("This is created when ConditionalOnClassIntegrationTest is present on the classpath");       }); }   @Test public void whenDependentClassIsPresent_thenBeanMissing() {     this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class)         .run(context -> {             assertThat(context).doesNotHaveBean("missed");         }); } 

通過前面的示例,我們發現測試classpath上存在某個類的場景的簡單性。但是,當類不在classpath上時,我們如何測試相反的情況呢

這就是FilteredClassLoader發揮作用的地方。它用於在運行時過濾classpath上指定的類:

@Test
public void whenDependentClassIsNotPresent_thenBeanMissing() {     this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class)         .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class))         .run((context) -> {             assertThat(context).doesNotHaveBean("created");             assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class);         }); }   @Test public void whenDependentClassIsNotPresent_thenBeanCreated() {     this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class)       .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class))       .run((context) -> {         assertThat(context).hasBean("missed");         assertThat(context).getBean("missed")           .isEqualTo("This is missed when ConditionalOnClassIntegrationTest is present on the classpath");         assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class);       }); } 

2.2. 測試 Bean Condition

我們剛剛測試了 @ConditionalOnClass 和 @ConditionalOnMissingClass 註解, 現在 讓我們看看使用@ConditionalOnBean和@ConditionalOnMissingBean註釋時的情況。

首先, 我們同樣需要 一些自動配置的類:

@Configuration
protected static class BasicConfiguration {
    @Bean
    public String created() {         return "This is always created";     } } @Configuration @ConditionalOnBean(name = "created") protected static class ConditionalOnBeanConfiguration {     @Bean     public String createOnBean() {         return "This is created when bean (name=created) is present";     } } @Configuration @ConditionalOnMissingBean(name = "created") protected static class ConditionalOnMissingBeanConfiguration {     @Bean     public String createOnMissingBean() {         return "This is created when bean (name=created) is missing";     } } 

然後,我們將像上一節一樣調用withUserConfiguration方法,然後發送我們的自定義配置類來測試自動配置是否在不同的條件下恰當地實例化bean或跳過createOnBeancreateOnMissingBean :

@Test
public void whenDependentBeanIsPresent_thenConditionalBeanCreated() {     this.contextRunner.withUserConfiguration(BasicConfiguration.class,       ConditionalOnBeanConfiguration.class)     // ommitted for brevity } @Test public void whenDependentBeanIsNotPresent_thenConditionalMissingBeanCreated() {     this.contextRunner.withUserConfiguration(ConditionalOnMissingBeanConfiguration.class)     // ommitted for brevity } 

2.3. 測試 Property Condition

在本節中,我們測試使用 @ConditionalOnPropertyannotations的自動配置類。

首先,我們需要這個測試的屬性:

com.baeldung.service=custom

然後,我們編寫嵌套的自動配置類,根據前面的屬性創建bean:

@Configuration
@TestPropertySource("classpath:ConditionalOnPropertyTest.properties") protected static class SimpleServiceConfiguration {     @Bean     @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "default")     @ConditionalOnMissingBean     public DefaultService defaultService() {         return new DefaultService();     }     @Bean @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "custom") @ConditionalOnMissingBean public CustomService customService() { return new CustomService(); } } 

現在,我們調用withPropertyValues方法來覆蓋每個測試中的屬性值:

@Test
public void whenGivenCustomPropertyValue_thenCustomServiceCreated() { this.contextRunner.withPropertyValues("com.baeldung.service=custom") .withUserConfiguration(SimpleServiceConfiguration.class) .run(context -> { assertThat(context).hasBean("customService"); SimpleService simpleService = context.getBean(CustomService.class); assertThat(simpleService.serve()).isEqualTo("Custom Service"); assertThat(context).doesNotHaveBean("defaultService"); }); } @Test public void whenGivenDefaultPropertyValue_thenDefaultServiceCreated() { this.contextRunner.withPropertyValues("com.baeldung.service=default") .withUserConfiguration(SimpleServiceConfiguration.class) .run(context -> { assertThat(context).hasBean("defaultService"); SimpleService simpleService = context.getBean(DefaultService.class); assertThat(simpleService.serve()).isEqualTo("Default Service"); assertThat(context).doesNotHaveBean("customService"); }); } 

3. 結論

總結一下, 這篇教程主要展示 如何使用ApplicationContextRunner運行帶有自定義的ApplicationContext並應用斷言.

我們在這裏介紹了最常用的場景,而不是列出如何自定義ApplicationContext 。

在此期間,請記住ApplicationConetxtRunner適用於非Web應用程序,因此請考慮WebApplicationContextRunner用於基於servlet的Web應用程序,ReactiveWebApplicationContextRunner用於響應式Web應用程序。

本文源代碼,請訪問GitHub。

原文:www.baeldung.com/spring-boot…

作者:baeldung

譯者:Leesen

 

【精選推薦文章】

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

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

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

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