環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※超省錢租車方案
※別再煩惱如何寫文案,掌握八大原則!
※回頭車貨運收費標準
※教你寫出一流的銷售文案?
※FB行銷專家,教你從零開始的技巧
![]() |
新華社報導,由中國中車唐山公司研製的世界首列商用型氫燃料混合動力100%低地板現代有軌電車,10月26日在河北唐山市唐胥鐵路載客營運,為全球氫燃料電池有軌電車首次商業營運,也是中國在新能源軌道交通領域實現重大突破。 經過4年多時間,中車唐山公司率先在全球首次突破了燃料電池/超級電容混合動力牽引和控制等一系列關鍵技術,研製的有軌電車完全取消受電弓和接觸網,實現污染物「零排放」和全程「無網」運行。 據悉,唐山工業旅遊線路採用氫燃料電池有軌電車,無需架設接觸網,不用沿途安裝第三軌和充電樁,完整保留了百年唐胥鐵路的原貌;列車採用世界最先進的100%低地板技術,車廂地板距軌道面僅35公分,無需月臺;最小轉彎半徑僅19公尺,可沿現有城市道路直接鋪設軌道,在地面行駛和停靠;線路運營全程13.84公里,有軌電車一次快速加氫只需15分鐘,可持續行駛40公里,最高運行時速70公里。 中車唐山公司表示,旗下氫燃料混合動力有軌電車係採用2動1拖3輛編組,設乘客座位66個,最大載客量336人,還可根據運營需求靈活增加編組和載客量;這種有軌電車不僅可最高速度持續運行,且在制動、停站時,由燃料電池和制動能量回收系統為超級電容和蓄電池充電,能量回收率達30%以上。 (本文內容由授權使用。首圖為中車唐山電車示意圖,來源:)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司"嚨底家"!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
![]() |
石油輸出國組織(OPEC)11月7日發布「世界石油展望(WOO)」報告指出,假設全球電動車(EV)年度銷售量在2040年達到8千萬輛(相當於每5台車就有3台是電動車),在電動車滲透率高於預期的情況下、全球石油日需求量可能會在2040年較基準預估值減少250萬桶至1.08億桶。據此推斷,全球石油需求將在2030年代下半階段持平於這個水位。 WOO指出,2016年全球上路的電動車據估計已升至200萬輛。目前已有6個國家的電動車市佔率(占整體轎車銷售量比重)突破1%、挪威電動車銷售量佔比更是高達29%。不過,電動車目前僅佔全球整體轎車車隊不到0.2%的比例。 WOO預估(見圖),2040年電動車在經濟合作暨發展組織(OECD)美洲新車市場的銷售佔比將高達35%左右、屆時中國電動車銷售佔比預估也將逼近29%,印度預估將達18%。 根據DNV GL首度發布的「能源轉型展望」報告,受電動車滲透率持續上揚的影響,石油供應將在2020~2028年期間轉趨持平、隨後大幅下降,2034年將遭天然氣超越。這份報告預估電動車、內燃引擎車將在2022年達到「成本平價」,預估到2033年全球半數輕型新車銷售量都將是電動車。 Thomson Reuters報導,嘉能可(Glencore)董事長Tony Hayward 5月受訪時表示,電動車的快速進步意味著石油需求可能會在2040年以前觸頂,深海鑽油、加拿大油砂等高成本原油生產商恐將先被淘汰出局,擁有生產成本優勢的OPEC相對較不受衝擊。Hayward曾任英國石油公司(BP Plc)執行長。 英國金融時報8月報導,瑞銀(UBS)預估2021年歐洲未經補貼的純電動車整體持有成本將與傳統內燃機汽車相當、中國也可望在2025年達到這項里程碑。 (本文內容由授權使用。首圖來源:public domain CC0)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※教你寫出一流的銷售文案?
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※回頭車貨運收費標準
※別再煩惱如何寫文案,掌握八大原則!
※超省錢租車方案
※產品缺大量曝光嗎?你需要的是一流包裝設計!
轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
原文出處:https://dzone.com/articles/why-masses-are-not-using-latest-css-features-in-20
儘管CSS每年都會發布全新的特性,但實際上這些新功能很少會被web開發人員實際在生產項目中使用到,甚至去了解它們的動力也不會比去多完成幾個需求更多。那究竟是什麼原因導致的呢?
在一個新項目的初期階段,它用到的可能只是幾條CSS規則,但隨着項目的持續更新和迭代,項目中使用到的規則就會變得越來越複雜,CSS也會越來越複雜尺寸也會隨之不斷膨脹。因此,作為項目優化的第一要務,作為資源的CSS需要盡可能的精簡和減少複雜度,第一是為了便於更好地理解和維護,第二也是為了加載更為高效。那麼,更實用且可投入生產環境的一些CSS特性會被高頻使用,其他的特性則會被暫時擱置一旁。
並且,在一般情況下,樣式和品牌在一段時間內都會相對固定,完成任務的需求要比使用最新CSS的特性要更緊迫。
(圖片來源於網絡)
預算成本是影響了所有項目的主要因素。它在開發階段會高度影響事項的優先級。集成新的CSS功能需要時間,而開發團隊來說,增加的這部分時間成本會影響到項目的整體進度。因此,開發進度會重視在優化其他功能(而不是CSS功能)時花費的時間成本。
另外,引入了最新的CSS特性,還可能會使開發團隊把一部分精力放在解決瀏覽器兼容性問題上。這點和JavaScript不同,JavaScript有Babel來完成編譯,而CSS沒有提供類似功能。
(圖片來源於網絡)
JavaScript每隔一段時間舉行一次會議。同樣,Vue和React也會為了幫助開發人員跟上社區的步伐而定期舉行會議。但是,對於CSS而言,它們根本沒有這樣的活動!因此,開發人員很難掌握其功能和路線圖。他們應該如何保持對新功能發展趨勢的了解? 沒有版本發布說明,也沒有定期的發布會,這根本不能點燃社區用戶的學習激情。
對普通用戶而言,既然舊的技術已經滿足了需求,那麼又何必那麼麻煩閱讀文檔學習新的功能呢?
和框架和其他編程語言不同,CSS沒有針對安全問題的補丁程序。他只是一套標準,反正大多數客戶只需要關心網站看起來UI差不多就行了。
即使你在掌握CSS方面付出了很多的努力,對CSS的新特性也了如指掌,但你也很難向你的客戶或老闆證明這一點,因為類似像這樣“熟練掌握CSS3以外的CSS特性”對他人而講是沒有意義的,因為它不是CSS3。在CSS開發領域,CSS3的出現是很有意義的,因為它完成了前端領域的統一:
巨大的需求帶來了巨大的機會。除了大量的書籍、課程和視頻來幫助人們了解CSS3外,還催生了全新的布局模型,如Flexbox和Grid,儘管它們不是CSS3的一部分。
但這裏我們指的是CSS3外的特性,它們本身除了認可程度很低外,對開發團隊來講也是個相對不熟悉的東西,因此,開發團隊很難會把時間花在對市場沒有意義的事情上,客戶也不會關心你到底用不用新的技術。
編寫CSS的主要目的是使你的網站的表現內容的形式更美觀及易於理解。CSS通過控制兩類事物來幫助開發人員去實現這個目標:布局和設計。布局(Layout)負責元素列和行排布,而設計(design)指顏色、字體、間距、動畫和邊框等基礎外觀。
但目前,舊的特性已經能處理的很好了,為什麼要花更多時間去使用新特性去替代已經很好的形式呢?
CSS發布周期沒有固定的周期和計劃,導致一切都來的很突然 ,另外舊的CSS特性已經能很好的完成日常工作了,這讓很多Web開發人員沒有特別的動力去升級它們。
另外,新的特性知名度也不高,對最終用戶的吸引力也不足,很難從需求層面驅動使用。所以這就是為什麼都2020年了,CSS的新特性仍然使用的人較少的原因。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司“嚨底家”!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新
線程(Thread)是併發編程的基礎,也是程序執行的最小單元,它依託進程而存在。
一個進程中可以包含多個線程,多線程可以共享一塊內存空間和一組系統資源,因此線程之間的切換更加節省資源、更加輕量化,也因此被稱為輕量級的進程。
線程的狀態在 JDK 1.5 之後以枚舉的方式被定義在 Thread 的源碼中,它總共包含以下 6 個狀態:
NEW,新建狀態,線程被創建出來,但尚未啟動時的線程狀態;
RUNNABLE,就緒狀態,表示可以運行的線程狀態,它可能正在運行,或者是在排隊等待操作系統給它分配 CPU 資源;
BLOCKED,阻塞等待鎖的線程狀態,表示處於阻塞狀態的線程正在等待監視器鎖,比如等待執行 synchronized 代碼塊或者使用 synchronized 標記的方法;
WAITING,等待狀態,一個處於等待狀態的線程正在等待另一個線程執行某個特定的動作,比如,一個線程調用了 Object.wait() 方法,那它就在等待另一個線程調用 Object.notify() 或 Object.notifyAll() 方法;
TIMED_WAITING,計時等待狀態,和等待狀態(WAITING)類似,它只是多了超時時間,比如調用了有超時時間設置的方法 Object.wait(long timeout) 和 Thread.join(long timeout) 等這些方法時,它才會進入此狀態;
TERMINATED,終止狀態,表示線程已經執行完成。
線程狀態的源代碼如下:
|
public enum State { /** * 新建狀態,線程被創建出來,但尚未啟動時的線程狀態 */ NEW,
/** * 就緒狀態,表示可以運行的線程狀態,但它在排隊等待來自操作系統的 CPU 資源 */ RUNNABLE,
/** * 阻塞等待鎖的線程狀態,表示正在處於阻塞狀態的線程 * 正在等待監視器鎖,比如等待執行 synchronized 代碼塊或者 * 使用 synchronized 標記的方法 */ BLOCKED,
/** * 等待狀態,一個處於等待狀態的線程正在等待另一個線程執行某個特定的動作。 * 例如,一個線程調用了 Object.wait() 它在等待另一個線程調用 * Object.notify() 或 Object.notifyAll() */ WAITING,
/** * 計時等待狀態,和等待狀態 (WAITING) 類似,只是多了超時時間,比如 * 調用了有超時時間設置的方法 Object.wait(long timeout) 和 * Thread.join(long timeout) 就會進入此狀態 */ TIMED_WAITING,
/** * 終止狀態,表示線程已經執行完成 */ } |
線程的工作模式是,首先先要創建線程並指定線程需要執行的業務方法,然後再調用線程的 start() 方法,此時線程就從 NEW(新建)狀態變成了 RUNNABLE(就緒)狀態;
然後線程會判斷要執行的方法中有沒有 synchronized 同步代碼塊,如果有並且其他線程也在使用此鎖,那麼線程就會變為 BLOCKED(阻塞等待)狀態,當其他線程使用完此鎖之後,線程會繼續執行剩餘的方法。
當遇到 Object.wait() 或 Thread.join() 方法時,線程會變為 WAITING(等待狀態)狀態;
如果是帶了超時時間的等待方法,那麼線程會進入 TIMED_WAITING(計時等待)狀態;
當有其他線程執行了 notify() 或 notifyAll() 方法之後,線程被喚醒繼續執行剩餘的業務方法,直到方法執行完成為止,此時整個線程的流程就執行完了,執行流程如下圖所示:
【BLOCKED 和 WAITING 的區別】
雖然 BLOCKED 和 WAITING 都有等待的含義,但二者有着本質的區別。
首先它們狀態形成的調用方法不同。
其次 BLOCKED 可以理解為當前線程還處於活躍狀態,只是在阻塞等待其他線程使用完某個鎖資源;
而 WAITING 則是因為自身調用了 Object.wait() 或着是 Thread.join() 又或者是 LockSupport.park() 而進入等待狀態,只能等待其他線程執行某個特定的動作才能被繼續喚醒。
比如當線程因為調用了 Object.wait() 而進入 WAITING 狀態之後,則需要等待另一個線程執行 Object.notify() 或 Object.notifyAll() 才能被喚醒。
【start() 和 run() 的區別】
首先從 Thread 源碼來看,start() 方法屬於 Thread 自身的方法,並且使用了 synchronized 來保證線程安全,源碼如下:
|
public synchronized void start() { // 狀態驗證,不等於 NEW 的狀態會拋出異常 if (threadStatus != 0) throw new IllegalThreadStateException(); // 通知線程組,此線程即將啟動
group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { // 不處理任何異常,如果 start0 拋出異常,則它將被傳遞到調用堆棧上 } } } |
run() 方法為 Runnable 的抽象方法,必須由調用類重寫此方法,重寫的 run() 方法其實就是此線程要執行的業務方法,源碼如下:
|
public class Thread implements Runnable { // 忽略其他方法…… private Runnable target; @Override public void run() { if (target != null) { target.run(); } } } @FunctionalInterface public interface Runnable { public abstract void run(); } |
從執行的效果來說,start() 方法可以開啟多線程,讓線程從 NEW 狀態轉換成 RUNNABLE 狀態,而 run() 方法只是一個普通的方法。
其次,它們可調用的次數不同,start() 方法不能被多次調用,否則會拋出 java.lang.IllegalStateException;而 run() 方法可以進行多次調用,因為它只是一個普通的方法而已。
【線程優先級】
在 Thread 源碼中和線程優先級相關的屬性有 3 個:
|
// 線程可以擁有的最小優先級 public final static int MIN_PRIORITY = 1;
// 線程默認優先級 public final static int NORM_PRIORITY = 5;
// 線程可以擁有的最大優先級 public final static int MAX_PRIORITY = 10 |
線程的優先級可以理解為線程搶佔 CPU 時間片的概率,優先級越高的線程優先執行的概率就越大,但並不能保證優先級高的線程一定先執行。
在程序中我們可以通過 Thread.setPriority() 來設置優先級,setPriority() 源碼如下:
|
public final void setPriority(int newPriority) { ThreadGroup g; checkAccess(); // 先驗證優先級的合理性 if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if((g = getThreadGroup()) != null) { // 優先級如果超過線程組的最高優先級,則把優先級設置為線程組的最高優先級 if (newPriority > g.getMaxPriority()) { newPriority = g.getMaxPriority(); } setPriority0(priority = newPriority); } } |
【線程的常用方法】
線程的常用方法有以下幾個。
join()
在一個線程中調用 other.join() ,這時候當前線程會讓出執行權給 other 線程,直到 other 線程執行完或者過了超時時間之後再繼續執行當前線程,join() 源碼如下:
|
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; // 超時時間不能小於 0 if (millis < 0) { throw new IllegalArgumentException(“timeout value is negative”); } // 等於 0 表示無限等待,直到線程執行完為之 if (millis == 0) { // 判斷子線程 (其他線程) 為活躍線程,則一直等待 while (isAlive()) { wait(0); } } else { // 循環判斷 while (isAlive()) { long delay = millis – now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() – base; } } } |
從源碼中可以看出 join() 方法底層還是通過 wait() 方法來實現的。
例如,在未使用 join() 時,代碼如下:
|
public class ThreadExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { for (int i = 1; i < 6; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“子線程睡眠:“ + i + “秒。“); } }); thread.start(); // 開啟線程 // 主線程執行 for (int i = 1; i < 4; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“主線程睡眠:“ + i + “秒。“); } } } |
程序執行結果為:
複製主線程睡眠:1秒。
子線程睡眠:1秒。
主線程睡眠:2秒。
子線程睡眠:2秒。
主線程睡眠:3秒。
子線程睡眠:3秒。
子線程睡眠:4秒。
子線程睡眠:5秒。
從結果可以看出,在未使用 join() 時主子線程會交替執行。
然後我們再把 join() 方法加入到代碼中,代碼如下:
|
public class ThreadExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { for (int i = 1; i < 6; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“子線程睡眠:“ + i + “秒。“); } }); thread.start(); // 開啟線程 thread.join(2000); // 等待子線程先執行 2 秒鐘 // 主線程執行 for (int i = 1; i < 4; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(“主線程睡眠:“ + i + “秒。“); } } } |
程序執行結果為:
複製子線程睡眠:1秒。
子線程睡眠:2秒。
主線程睡眠:1秒。
// thread.join(2000); 等待 2 秒之後,主線程和子線程再交替執行
子線程睡眠:3秒。
主線程睡眠:2秒。
子線程睡眠:4秒。
子線程睡眠:5秒。
主線程睡眠:3秒。
從執行結果可以看出,添加 join() 方法之後,主線程會先等子線程執行 2 秒之後才繼續執行。
yield()
看 Thread 的源碼可以知道 yield() 為本地方法,也就是說 yield() 是由 C 或 C++ 實現的,源碼如下:
|
public static native void yield(); |
yield() 方法表示給線程調度器一個當前線程願意出讓 CPU 使用權的暗示,但是線程調度器可能會忽略這個暗示。
比如我們執行這段包含了 yield() 方法的代碼,如下所示:
|
public static void main(String[] args) throws InterruptedException { Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(“線程:“ + Thread.currentThread().getName() + “ I:“ + i); if (i == 5) { Thread.yield(); } } } }; Thread t1 = new Thread(runnable, “T1”); Thread t2 = new Thread(runnable, “T2”); t1.start(); t2.start(); } |
當我們把這段代碼執行多次之後會發現,每次執行的結果都不相同,這是因為 yield() 執行非常不穩定,線程調度器不一定會採納 yield() 出讓 CPU 使用權的建議,從而導致了這樣的結果。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※教你寫出一流的銷售文案?
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※回頭車貨運收費標準
※別再煩惱如何寫文案,掌握八大原則!
※超省錢租車方案
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新
![]() |
福斯汽車(Volkswagen)深陷柴油車排氣造假案使得品牌形象受重創,為了早點擺脫「柴油門」陰影,轉移消費者的眼光,福斯近來大力推動電動車,雄心勃勃的發展電動車的同時,傳出找來德國逆變器大廠SMA Solar 結盟。
SMA Solar 成立於1981 年,公司名來自「系統、測量、系統工程」(System, Mess and Anlagentechnik)德文簡寫,為全球最大逆變器廠,逆變器應用於直流電交流電轉換,不僅應用於太陽能,也應用於電池能源儲存系統,SMA Solar 市場地位穩固,特斯拉(Tesla)於2016 年5 月宣布Powerwall 將進行小規模規格提升,其重點之一就是改為可支援SMA Solar 產品。
福斯在「柴油門」事件後,積極將事業目標轉向電動車,以便洗刷受到作假事件影響的聲譽,投注數十億歐元資金,大力發展零碳排放的純電動車以及隨選共乘服務,計劃在2025 年以前推出30 款電動車,攻佔四分之一的全球電動車市場。
但是分析師指出,福斯在2015 年只不過出貨6.7 萬輛電動車與油電混合車,以這樣的市佔與進度,要在2025 年攻佔四分之一電動車市場的目標可能很難達成,尤其是競爭對手早已起步,為了追上豐田(Toyota)與雷諾(Renault)日產(Nissan)聯盟,福斯需要找尋強大的合作夥伴。
德國地方日報《黑森下薩克森大眾報》(Hessische Niedersaechsische Allgemeine)於2016 年8 月初報導,福斯尋求能源儲存與綠能大廠SMA Solar 的合作。
福斯的電動車廠表示,SMA Solar 在靜態能源儲存領域相當強勢,對福斯來說,尋求正確的合作夥伴,將是發展電動車的重要關鍵。不過,SMA Solar 目前已經與賓士製造商戴姆勒(Daimler)以及特斯拉在能源儲存方面合作,目前對於福斯的可能合作消息不表示意見。
(本文授權自《》──〈〉。照片來源:)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司“嚨底家”!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新
![]() |
不論是在汽車、能源還是科技界,不論發生什麼事情都在大眾目光焦點的特斯拉 (Tesla),既三月份成立臺灣分公司之後有更進一步的動作。特斯拉的臺北旗艦店在今日 (9 月1 日) 在臺北信義商圈開幕,有興趣的人可以到店體驗特斯拉房車Model S,並且預約試駕和進一步訂購,預計明年 (2017) 第一季交車。
特斯拉看中臺灣在科技產業的樞鈕地位,因此在亞太區暨中國、香港、澳門、澳洲之後,選擇臺灣,成為特斯拉全球第25 個設立的國家。而在信義商圈新光三越A11 的台灣旗艦店,則是第204 家店。選在臺灣的首善之都臺北,則是著眼信義商圈是臺北最繁盛的購物商圈,對新事物的接受度高,因此選在新光三越A11 設旗艦店,並且還跟新光三越合作,在百貨公司的地下停車場設立充電站。
電動車要能方便,必須有足夠的的充電站。Tesla香港、澳門及台灣地區區域總監范菁怡表示,目前除了設在車主自家的居家充電站之外,還會與百貨商場、飯店合作,在停車場設置目的地充電站。未來特斯拉也將在高速公路沿線設置超級充電站,服務需長距離駕駛的特斯拉車子。
由於特斯拉代表新一代的潔淨能源運用型式,對於提高都市運輸效率和降低污染有顯著效果,因此除了特斯拉的代表和合作的百貨公司代表以外,臺北市政府也由副市長林欽榮出席。另外還有負責招商相關事務的行政院全球招商及攬才聯合服務中心何怡明執行長,以及經濟部工業局黃裕峰副組長出席。林欽榮致詞時表示,臺北市仍然要繼續推動共享汽車,U-Car 計畫。
儘管目前在臺灣還只能預購特斯拉的Model S 房車車型,但是特斯拉計畫在臺引進平價車款Model 3,定價3 萬5,000 美元,預計明年引進,目前正在商品檢驗階段。
「電動車勢必是未來交通方式的主流,Tesla 一直期望扮演推動永續能源應用的角色。我們樂見台灣對環保、綠色能源的高接受度,也很高興Tesla 能成為這波改革中的一股力量。」Tesla 全球副總裁暨亞太區總裁任宇翔表示:「臺灣特殊的地理和城市發展環境,以及政府對於相關政策和補助的支持,讓Tesla 清楚看到電動車在臺灣的發展性。臺灣廠商不僅是Tesla供應鏈的合作夥伴,更在電動車的推廣上佔有重要地位。隨著Tesla 電動車在台上市與充電站的逐步擴充,Tesla 對臺灣市場的發展潛力深具信心,除了希望對合作夥伴和經濟發展帶來正面影響,更期望與臺灣一起開創電動車的新篇章。」
特斯拉之後將在臺灣設立客服,還有佈建充電網路,當特斯拉的Model S 在臺灣的道路奔馳時,超級充電站和目的地充電站在商圈、景點等地方,形成足夠的網狀分佈,維持特斯拉的輪胎不停轉動。全球有超過9,000 萬臺汽車,目前只有不到0.2% 的汽車是電動車,特斯拉推動電動車,還可以有很大的施力空間。
(首圖:設在新光三越信義A11 地下4 樓停車場的特斯拉目的地充電站,在2017 年特斯拉車子在臺灣道路奔馳之際,這類設在購物商場的充電站將會越來越多。來源:科技新報)
(本文授權轉載自《》──〈〉)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※超省錢租車方案
※別再煩惱如何寫文案,掌握八大原則!
※回頭車貨運收費標準
※教你寫出一流的銷售文案?
※FB行銷專家,教你從零開始的技巧
※聚甘新
該文章,GitHub已收錄,歡迎老闆們前來Star!
GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual
搜索關注微信公眾號“碼出Offer”,送你學習福利資源!
在我們的項目資源中,你會發現需要導入的jar包越來越多,讓jar包的管理越來越沉重。它會表現為以下幾個缺點:
- 每個項目都需要手動搜集和導入所需要的jar包
- 項目中用到的jar包有版本更新,我們需要重新搜集並導入到項目中
- 相同的jar包導入到不同的項目中,jar包會在本地存儲多份
針對上述問題,我們就需要使用統一的管理工具:Maven
Maven是一個基於項目對象模型(POM)的概念的純Java開發的開源的項目管理工具。主要用來管理Java項目,進行依賴管理(jar包依賴管理)和項目構建(項目編譯、打包、測試、部署)。此外還能分模塊開發,提高開發效率。
關於Maven的下載,我們需要下載它的解壓包。
Maven下載地址: https://us.mirrors.quenda.co/apache/maven/maven-3/3.6.3/binaries/
image-20200616171323409
下載后將Maven解壓到目錄中就可以了!
注意: 解壓的目錄與tomact服務器的形式是一樣的,不要有中文及特殊符號!
image-20200616171637526
| 目錄名稱 | 描述 |
|---|---|
| bin | 存儲mvn的各種可執行文件 |
| boot | 含有plexus-classworlds類加載器框架,Maven 使用該框架加載自己的類庫 |
| conf | 存放settings.xml等配置文件 |
| lib | 存儲Maven運行時所需要的Java類庫 |
| LICENSE/NOTICE/README.txt | 針對Maven的版本、第三方軟件等簡要介紹 |
Maven依賴Java環境的配置環境,所以要確保jdk版本在1.7以上,maven版本在3.3以上。
- 配置環境變量與jdk環境變量配置是一樣的,在本機中創建
MAVEN_HOME環境變量,並將maven的解壓路徑設置進去,點擊確定(路徑參考上圖解壓后的結果圖路徑)- 修改
path環境變量,添加%MAVEN_HOME%\bin后,一路點擊確定即可!
下載解壓、配置環境變量后,我們打開DOS命令窗口,鍵入
mvn -v查看maven版本信息
- 如果看到如下圖片maven的版本信息,證明maven安裝配置成功!
- 在Maven的版本信息你就可以得知它依賴於jdk環境!
image-20200616172931556
本地倉庫簡單來說,就是在本地的maven中存儲管理所需jar包
首先,打開maven目錄
conf文件夾中的settings.xml配置文件其次,找到標號1的那一行配置信息,並複製此配置信息放在其下面
然後,在磁盤中創建一個目錄,作為存儲jar文件的本地倉庫
最後,將複製的此配置信息路徑替換成自己創建的本地倉庫目錄路徑,參考標號2的操作
image-20200616174928266
由於Maven依賴於jdk環境,所以我們也需要在maven中配置jdk(我使用的jdk是主流的1.8版本)
- 打開
settings.xml配置文件,找到<profiles>標籤,你會發現標籤內都是註釋的內容,我們需要在標籤內,寫入自己的jdk的配置信息。配置如下:- 在maven中添加好jdk的配置信息后,我們需要在</profiles>結束標籤后添加<activeProfiles>標籤內容,讓配置好的<profiles>標籤中內容生效
注意: profile標籤中的id是此配置信息的名稱,在後面使用activeProfile標籤讓其配置生效的時候,需要保證id與activeProfile的名稱一致!(貼圖供大家參考!)
<!-- 配置jdk -->
<profile>
<id>jdk1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
<!-- 使配置好的profiles標籤中內容生效 -->
<activeProfiles>
<activeProfile>jdk1.8</activeProfile>
</activeProfiles>
image-20200616181057029
後面我們會了解到maven項目是通過pom.xml進行構建信息配置和依賴信息配置。其中就包括配置編譯需要的jdk版本。所以我們直接修改pom文件就可以實現單個項目修改,但是我們並不推薦此種方式,因為這個方式需要每個項目都要修改,不具有可重用性!
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
- 存儲依賴的地方,體現形式就是本地的一個目錄。
- 倉庫中不僅存放依賴,而且管理着每個依賴的唯一標識(坐標),Java項目憑坐標獲取依賴。
Maven倉庫可以分為本地倉庫和遠程倉庫,其中遠程倉庫又分為中央倉庫、公共倉庫和私服
- 本地倉庫: 本地倉庫存放着項目中所需jar文件
- 中央倉庫: Maven的中央倉庫是由Maven社區提供存儲jar文件的倉庫
- 公共倉庫: 國內廠家提供的存儲jar文件的倉庫,比如:aliyun倉庫
- 私服: 由公司創建的存儲jar文件的倉庫,可在公司範圍內共享,不對外開放
當項目中需要jar文件依賴時,會從倉庫中查找獲取,如果我們把所有倉庫都配置好。maven在查找獲取依賴的時候遵循一個依賴查找順序,如下:(如果本地倉庫找不到依賴就去私服下載,以此類推……)
依賴查找順序: 本地倉庫 – > 私服 – > 公共倉庫 – > 中央倉庫
image-20200616184606968
本地倉庫: 本地目錄中存放所需jar包,需修改
settings配置文件來配置本地倉庫
- 使用過的依賴都會存儲在本地倉庫中,實現復用
中央倉庫: Maven中央倉庫是由Maven社區提供的倉庫,不用任何配置,maven中內置了中央倉庫地址。其中就包含絕大多數流行的開源Java構件
- https://mvnrepository.com/可以搜索需要的依賴的相關信息(倉庫搜索服務)
- http://repo.maven.apache.org/maven2/為中央倉庫地址
公共倉庫: 第三方維護的jar文件倉庫,比如阿里雲提供的倉庫。但是jar文件可能不如官方的中央倉庫全,有時候也會找不到,所以如果項目構建不成功,可以更改鏡像為官方的,下載完jar包再去改回來
aliyun倉庫地址:http://maven.aliyun.com/nexus/content/groups/public/
因為Maven社區提供的中央倉庫在國外,國內使用下載依賴速度過慢,所以一般我們都配置國內的公共倉庫來代替中央倉庫
使用時,需要在
settings.xml配置文件中添加配置信息。打開settings.xml配置文件,找到<mirrors>標籤,你也會發現這是一個空標籤,最後標籤內填寫如下配置就OK!
<!--setting.xml中添加如下配置-->
<mirror>
<id>aliyun</id>
<!-- 中心倉庫的 mirror(鏡像) -->
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<!-- aliyun倉庫地址 以後所有要指向中心倉庫的請求,都會指向aliyun倉庫-->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
image-20200616223651045
私服: 公司創建存儲jar文件的倉庫,只對公司範圍共享,不對外開放。可以通過
Nexus來創建、管理一個私服。
私服是架設在局域網的一種特殊的遠程倉庫,目的是代理遠程倉庫及部署第三方構件。
有了私服之後,當 Maven 需要下載依賴時,直接請求私服,私服上存在則下載到本地倉庫;否則,私服請求外部的遠程倉庫,將構件下載到私服,再提供給本地倉庫下載。
私服可以解決在企業做開發時每次需要的jar包都要在中心倉庫下載,且每次下載完只能被自己使用,不能被其他開發人員使用
所謂私服就是一個服務器,但是不是本地層面的,是公司層面的,公司中所有的開發人員都在使用同一個私服
我們可以使用專門的 Maven 倉庫管理軟件來搭建私服,比如:Apache Archiva,Artifactory,Sonatype Nexus。這裏我們使用
Sonatype Nexus
- 我們可以在圖中得到在無私服的情況下,我們都需要從遠程倉庫去獲取jar文件並存儲在本地倉庫,由於中央倉庫是國外的,所以下載速度比較慢等等原因,並存在很多缺點,比如我們公司內使用
- 我們在圖中可清晰的看到,如果有私服的話,我們需要從私服中,查找jar文件,如果私服沒有該jar文件,就需要去中央倉庫或公共倉庫去下載,然後傳到私服中,最後傳入到自己的本地倉庫進行使用。假設公司員工再一次使用到該jar文件,它會先從私服中找有沒有這個jar文件,由於我們之前的員工已經將該jar文件存儲到了私服中,所以就省去了其他員工調用遠程倉庫的步驟。並且私服是公司內部局域網類型的,下載速度會比遠程倉庫快出很多倍
| 無私服 | 有私服 |
|---|---|
| 私服1 | 私服2 |
Nexus官網地址:https://blog.sonatype.com/
下載地址:https://help.sonatype.com/repomanager2/download/download-archives—repository-manager-oss
下載我們需要下載Zip解壓包即可,將解壓包解壓到本地盤符中即可!
解壓后,你會看到nexus目錄為私服目錄,sonatype-work目錄中包含存儲私服下載的依賴。
訪問私服:http://localhost:8081/nexus/
登錄私服的賬號為
admin,密碼為admin123
| 倉庫類型 | 描述 |
|---|---|
| group | 包含多個倉庫,通過group庫的地址可以從包含的多個倉庫中查找構件 |
| hosted | 私服 服務器本地的倉庫,其中存儲諸多構件 |
| proxy | 代理倉庫,其會關聯一個遠程倉庫, 比如中央倉庫,aliyun倉庫,向該倉庫查找構件時,如果沒有會從其關聯的倉庫中下載 |
| 倉庫名 | 描述 |
|---|---|
| Releases | 存放項目的穩定發布版本,一個模塊做完后如果需要共享給他人,可以上傳到私服的該庫 |
| Snapshots | 對應不穩定的發布版本 |
| 3rd party | 存放中央倉庫沒有的 ,如ojdbc.jar,可以上傳到私服的該庫中 |
| 倉庫列表 |
|---|
| 私服_list |
而此時就有問題,私服中有很多倉庫,每個倉庫都有自己的url,則項目中配置哪個倉庫呢 ?
私服中有一個倉庫組,組中包含多個倉庫,可以指定倉庫組的url,即可從多個倉庫中獲取構件
關於倉庫的設置: 由於我們在使用私服的時候,本地倉庫沒有的jar文件,需要去私服找,私服沒有的話,就去中央倉庫找。所以我們需要把私服內的中央倉庫換為阿里雲倉庫,這樣可以保證我們國內的下載速度。
| 倉庫組 注意:proxy的倉庫排序在最後 |
|---|
| 私服_deploy2 |
配置
settings.xml,設置私服地址、認證等信息(關聯私服需要添加配置文件信息如下,找到父標籤,添加子標籤內容即可)
<servers>
<server>
<id>nexus-public</id> <!-- nexus的認證id -->
<username>admin</username> <!--nexus中的用戶名密碼-->
<password>admin123</password>
</server>
</servers>
<profiles>
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>nexus-public</id> <!--nexus認證id 【此處的repository的id要和 <server>的id保持一致】-->
<!--name隨便-->
<name>Nexus Release Snapshot Repository</name>
<!--地址是nexus中倉庫組對應的地址-->
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
<pluginRepositories> <!--插件倉庫地址,各節點的含義和上面是一樣的-->
<pluginRepository>
<id>nexus-public</id> <!--nexus認證id 【此處的repository的id要和 <server>的id保持一致】-->
<!--地址是nexus中倉庫組對應的地址-->
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>yourjdk</activeProfile>
<!-- 使私服配置生效 -->
<activeProfile>nexus</activeProfile>
</activeProfiles>
- 執行
mvn deploy指令即可將項目部署到私服對應的倉庫中,此時項目中的打包方式多為jar- 但需要提前在項目的
pom.xml中配置部署私服倉庫位置,如下:注意: 如上的 repository的 id 依然是要和settings.xml中配置的server中的id 一致,才能通過私服的認證
<project>
...
<dependencies>
.....
</dependencies>
<!-- 在項目的pom.xml中 配置私服的倉庫地址,可以將項目打jar包部署到私服 -->
<distributionManagement>
<repository>
<id>nexus-public</id> <!-- nexus認證id -->
<url>http://localhost:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>nexus-public</id> <!-- nexus認證id -->
<url>http://localhost:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
| 創建Maven項目 |
|---|
| image-20200616215847109 |
| 指定項目名稱和項目位置 |
| image-20200616220455702 |
| 節點 | 詳細描述 |
|---|---|
| groupId | 這是項目組的編號,這在組織或項目中通常是獨一無二的。 例如,一家銀行集團 com.company.bank擁有所有銀行相關項目。 |
| artifactId | 這是項目的 ID。這通常是項目的名稱。 例如,consumer-banking。 除了 groupId 之外,artifactId 還定義了 artifact 在存儲庫中的位置。 |
| version | 這是項目的版本。與 groupId 一起使用,artifact 在存儲庫中用於將版本彼此分離。 例如:com.company.bank:consumer-banking:1.0,com.company.bank:consumer-banking:1.1 |
- 規則:正式穩定版本從v0.1.0開始,配套軟件公共API
- 注意:正式版發布后不可修改,只能在下一個版本中發布新內容
| 版本類型 | 詳細描述 |
|---|---|
| 主要版本 | 當你做了不兼容的API 修改(正式版發布、架構升級) |
| 次要版本 | 當你做了向下兼容的功能性新增(功能增減) |
| 修訂版本 | 當你做了向下兼容的問題修正(BUG修復、查缺補漏) |
在使用maven過程中,我們在開發階段經常性的會有很多公共庫處於不穩定狀態,隨時需要修改併發布,可能一天就要發布一次,遇到bug時,甚至一天要發布N次。我們知道,maven的依賴管理是基於版本管理的,對於發布狀態的artifact,如果版本號相同,即使我們內部的鏡像服務器上的組件比本地新,maven也不會主動下載的。如果我們在開發階段都是基於正式發布版本來做依賴管理,那麼遇到這個問題,就需要升級組件的版本號,可這樣就明顯不符合要求和實際情況了。但是,如果是基於快照版本,那麼問題就自熱而然的解決了,而maven已經為我們準備好了這一切。
maven中的倉庫分為兩種,snapshot快照倉庫和release發布倉庫。snapshot快照倉庫用於保存開發過程中的不穩定版本,release正式倉庫則是用來保存穩定的發行版本。定義一個組件/模塊為快照版本,只需要在pom文件中在該模塊的版本號后加上-SNAPSHOT即可(注意這裏必須是大寫),如下:
<groupId>cc.mzone</groupId>
<artifactId>m1</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
maven會根據模塊的版本號(pom文件中的version)中是否帶有-SNAPSHOT來判斷是快照版本還是正式版本。如果是快照版本,那麼在mvn deploy時會自動發布到快照版本庫中,會覆蓋老的快照版本,而在使用快照版本的模塊,在不更改版本號的情況下,直接編譯打包時,maven會自動從鏡像服務器上下載最新的快照版本。如果是正式發布版本,那麼在mvn deploy時會自動發布到正式版本庫中,而使用正式版本的模塊,在不更改版本號的情況下,編譯打包時如果本地已經存在該版本的模塊則不會主動去鏡像服務器上下載。
在maven的約定中,依賴的版本分為兩類——SNAPSHOT和RELEASE。SNAPSHOT依賴泛指以-SNAPSHOT為結尾的版本號,例如1.0.1-SNAPSHOT。除此之外,所有非-SNAPSHOT結尾的版本號則都被認定為RELEASE版本,即正式版,雖然會有beta、rc之類說法,但是這些只是軟件工程角度的測試版,對於maven而言,這些都是RELEASE版本。所以一般我們需要上傳到發布倉庫的時候可以在<version>標籤內直接寫版本即可,不需要再添加任何標籤!
在IDEA中關聯本地安裝的maven,後續就可以通過idea來使用maven管理項目(我使用的aliyun倉庫)
| 在全局設置中關聯Maven |
|---|
| image-20200616222756521 |
| Maven項目展示 (缺少test包下resources文件夾) |
| image-20200616224937892 |
我們在使用IDEA創建Maven項目時,IDEA是沒有幫我們創建test包下的resources文件夾。但是Maven規範中是包含這個文件夾的,所以我們需要手動創建並聲明該文件夾
| 創建存放測試配置的文件夾 |
|---|
| image-20200616225355373 |
| 指定文件夾名稱 (下拉框選擇resources文件夾創建即可) |
| image-20200616225859663 |
| 文件目錄結構展示 (完整Maven規範目錄結構) |
| image-20200616230042781 |
注意: 項目中的創建包、創建類、執行,都與普通項目無異
| 目錄名稱 | 描述 |
|---|---|
| src/main/java | 用於創建包,存放編寫的源代碼(.java文件) |
| src/main/resources | 存放項目中所需配置文件,比如:c3p0.properties |
| src/test/java | 用於創建包,存放編寫的測試代碼(.java文件) |
| src/test/resources | 存放項目中測試代碼所需配置文件 |
| 根目錄/pom.xml | 項目對象模型(project object model),maven項目核心文件,其中定義項目構建方式,聲明依賴等 |
根據項目類型,在
pom.xml文件中添加相應配置。
項目類型分為Java項目和JavaWeb項目
如果項目為Java項目需要在<project>標籤內添加
jar如果項目為JavaWeb項目需要在<project>標籤內添加
war注意: Maven可以根據項目類型來確定打包方式,比如Java項目打包成jar包 、JavaWeb項目打包成war包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mylifes1110</groupId>
<artifactId>firstmaven</artifactId>
<version>1.0-SNAPSHOT</version>
<!--
設置項目類型,打包方式:
如果為Java項目則使用jar
如果為JavaWeb項目使用war
-->
<packaging>jar</packaging>
<!-- <packaging>war</packaging>-->
</project>
建好項目后,需要導入需要的jar包,要通過坐標來在倉庫中查找導入
- 每個構件都有自己的坐標,其坐標分為
groupId、artifactId、version三種,翻譯後為項目標識、項目名稱、版本號- 在maven項目中只需要配置坐標,maven便會自動加載對應依賴。刪除坐標則會移除依賴
| 節點 | 描述 |
|---|---|
| project | 工程的根標籤。 |
| modelVersion | 模型版本需要設置為 4.0。 |
| groupId | 這是工程組的標識。它在一個組織或者項目中通常是唯一的。例如,一個銀行組織 com.companyname.project-group 擁有所有的和銀行相關的項目。 |
| artifactId | 這是工程的標識。它通常是工程的名稱。例如,消費者銀行。groupId 和 artifactId 一起定義了 artifact 在倉庫中的位置。 |
| version | 這是工程的版本號。在 artifact 的倉庫中,它用來區分不同的版本。例如:com.company.bank:consumer-banking:1.0 com.company.bank:consumer-banking:1.1 |
依賴查找服務需要在如下網址中查找依賴,獲取依賴坐標后,在maven項目中的
pom.xml文件中導入
- 依賴查找服務地址: https://mvnrepository.com/
| 查找jar文件 |
|---|
| image-20200616111418839 |
| jar文件的選擇 |
| image-20200616112444879 |
| Copy依賴坐標 |
| image-20200617003002005 |
在項目的
pom.xml文件中添加依賴
- 首先添加<dependencies>標籤
- 最後添加複製好的依賴坐標
注意: 導入依賴可以導入多個所需jar文件的依賴,依次在<dependencies>標籤內添加依賴坐標即可
| 導入依賴 |
|---|
| image-20200617003853705 |
導入依賴后,你會發現
pom.xml文件中的依賴坐標是紅色報錯的,而在IDEA的右下角有那麼一個框。這時候需要點擊框內提示信息在maven倉庫中同步下載依賴到項目中
| 同步下載依賴到項目中 |
|---|
| image-20200617004515463 |
導入並同步下載好的依賴,可以通過項目和IDEA中Maven控制面板查看
| 查看依賴 |
|---|
| image-20200617005635304 |
pom.xml文件中設置<packaging>war/packaging>修改打包方式為web項目
基於Maven項目,我們導入了maven所需依賴,如果創建web項目的話,還需要導入
JSP、Servlet和JSTL依賴,使Maven項目具有web編譯環境。(在pom.xml文件中添加以下依賴)
<dependency>
<!-- jstl 支持 -->
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<!-- servlet編譯環境 -->
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<!-- jsp編譯環境 -->
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
image-20200617123210482
web項目在IDEA中有web規範目錄文件夾的,比如webapp、WEB-INF、web.xml、index.jsp。而由於Maven項目中沒有該規範目錄,這就需要我們自己創建目錄結構了!
創建web項目目錄結構有以下注意點:
- webapp文件夾必須是基於main目錄下創建的,與java文件夾同級
- webapp文件夾IDEA自動識別此文件夾,給與了特殊藍色圓點標識
- 在WEB-INF目錄下創建的的
web.xml是一個空的xml文件,我們需要在該文件中鍵入如下web.xml空白模板信息,只需要將下面的模板複製到項目中的web.xml文件中即可!- 創建的文件夾以及文件名稱千萬不要寫錯!
注意: 在創建項目的時候,其實我們是可以指定使用IDEA來創建來創建web項目的目錄結構的,創建項目時需要勾選
Create from archetype。只是IDEA為我們構建的項目架構是有版本差異的,而且還附加了很多對我們無用的註解等等,所以我們一般都手動創建,IDEA自動構建作為了解就好!
xml空白模板
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
</web-app>
| IDEA自動構建項目結構 |
|---|
| image-20200617164915737 |
| 手動構建web項目結構 |
|---|
| 基於main目錄下創建webapp文件夾 |
| image-20200617124249878 |
| image-20200617124319926 |
| 基於webapp目錄創建WEB-INF文件夾 |
| image-20200617124624648 |
| 基於WEB-INF目錄創建web.xml文件 |
| image-20200617125038803 |
| image-20200617125055216 |
| xml文件內容展示 |
| image-20200617125729115 |
| 基於webapp目錄創建index.jsp文件 |
| image-20200617125613861 |
| 目錄展示 (完整的web項目目錄結構) |
| image-20200617125808227 |
關於Tomact服務的引入,需要我們手動添加tomact服務
添加tomact服務后,如果對tomact服務器在IDEA中的開發流程不熟悉的小夥伴,不要灰心。請參考tomact服務器基礎和開發步驟即可,此文章中詳細講到了關於tomact的各種知識點!
| 添加tomact服務 |
|---|
| image-20200617131801103 |
默認的打包名稱:
artifactid+verson.打包方式我們可以通過build中finalName修改,如下操作:
<build>
<finalName>maven_name</finalName>
</build>
dependencies引入開發需要的jar包,有時候我們還需要引入一些常用的插件,比如:jdk、tomact、分頁插件等等
插件配置位置也是在<build>標籤中,如下:
<build>
<plugins>
<!-- java編譯插件,配jdk的編譯版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
如果在java文件夾中添加java類,會自動打包編譯到classes文件夾下。但是xml文件默認不會被打包,需要我們手動指定打包。可以使用<resources>標籤來指定要打包資源的文件夾要把哪些靜態資源打包到classes根目錄下
<!--打包指定靜態資源-->
<build>
<resources>
<resource>
<!-- 指定要打包資源的文件夾 要把哪些靜態資源打包到 classes根目錄下-->
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>spring/*</exclude>
</excludes>
<includes>
<include>*.xml</include>
<!--<include>*/*.properties</include>-->
</includes>
</resource>
</resources>
</build>
jar文件的生效時間段可以成為依賴的生命周期
前三個是常用的依賴生命周期設置,而後兩個製作了解即可,幾乎用不到!
| 標識 | 周期 |
|---|---|
| compile | 缺省值(默認依賴生命周期),適用於所有階段(測試運行,編譯,運行,打包) |
| provided | 類似compile,期望JDK、容器或使用者會提供這個依賴。如servlet-api.jar;適用於(測試運行,編譯)階段 |
| test | 只在測試時使用,適用於(編譯,測試運行)階段,如 junit.jar |
| runtime | 依賴在編譯器不使用,只在運行時使用,如 mysql的驅動jar,適用於(運行,測試運行)階段 |
| system | Maven不會在倉庫中查找對應依賴,在本地磁盤目錄中查找;適用於(編譯,測試運行,運行)階段 |
關於依賴生命周期的使用,需要在期望指定生命周期的依賴內添加<scope>標籤,在此標籤內添加所需依賴標識。
complie
jstl依賴默認沒有compile標識的生命周期。因為在依賴中不指定生命周期就是默認指定適用於所有階段的生命周期,其默認標識為compile。
image-20200617135847510
provided
servlet和jsp依賴默認指定provided標識的生命周期。因為我們在servlet或jsp代碼時是需要這兩個依賴的,但是我們將項目部署到tomact中,本地tomact目錄的lib文件夾下也會有一些jar文件,所以這造成了一種依賴衝突。為了避免這種依賴衝突我們需要指定依賴的生命周期為編譯和測試運行階段。這樣我們在書寫代碼時,編譯期也有有依賴可以使用,不會飄紅,而在過了編譯期後項目部署到了tomact中,該依賴聲生命就會被結束掉了,不會影響tomact服務器內置依賴的使用!
image-20200617135818392
test
在maven項目中,項目結構是區分main主文件和test測試文件的。如果我們在使用Junit單元測試時,指定依賴的生命周期為test,那該依賴只適用於test測試文件內,在其他文件的階段默認沒有單元測試的依賴。
簡單來說,在test文件夾內創建的測試類,使用@Test註解不會有任何問題。如果換做在main文件夾和其他文件夾中創建測試類,使用@Test註解就會因沒有依賴注入而報錯。
image-20200617140515452
runtime
我們在添加mysql驅動的依賴時,你會發現它並沒有指定生命周期為runtime。這是因為我們在書寫jdbc工具類的操作時,如果在編譯期沒有mysql驅動的依賴,它並不會飄紅報錯。如果沒有依賴只有在我們運行的時候才會發生報錯,並告知mysql驅動依賴未找到。所以,這就顯得runtime這個依賴生命周期十分的雞肋。因此,可以不指定該生命周期。
image-20200617141145812
system
當依賴的生命周期設置為system時,表示該依賴項是我們自己提供的,不需要Maven到倉庫裏面去找。
指定scope為system需要與另一個屬性元素systemPath一起使用,它表示該依賴項在當前系統的位置,使用的是絕對路徑。由於此類依賴不是通過 Maven 倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此應該慎用。systemPath元素可以引用環境變量。
image-20200617142301138
一般命令的鍵入在IDEA中的框中鍵入命令就可以!
image-20200617170717904
| 命令 | 描述 |
|---|---|
| mvn compile(常用) | 編譯項目,生成target文件 |
| mvn package(常用) | 打包項目,生成war或jar文件 |
| mvn clean(常用) | 清理編譯或打包后的項目結構 |
| mvn install(常用) | 打包後上傳到Maven本地倉庫 |
| mvn source:jar | 打包項目,生成jar包 |
| mvn deploy | 只打包,不測試 |
| mvn site | 生成站點 |
| mvn test | 執行測試源碼 |
maven項目的生命周期分為了三個階段,而這三個階段相互獨立、互不影響
- 清理生命周期(Clean Lifecycle): 該生命周期負責清理項目中多餘信息,保持資源和代碼的整潔性。一般用來清空目錄下的文件
- 默認構建生命周期(Default Lifeclyle): 該生命周期表示項目的構建過程,其中定義了一個項目構建要經歷的不同階段
- 站點管理生命周期(Site Lifecycle): site生命周期的目的是建立和發布項目站點,Maven能夠基於POM所包含的信息,自動生成一個友好的站點
clean
該生命周期主要是對項目編譯生成的文件進行清理,清理的話主要是清理編譯後項目中的target文件夾,清理后還可以通過編譯指令重新生成。
- 命令:
mvn clean
default
該生命周期的主要目的是項目的
編譯 -> 測試 -> 打包 -> 發布
- 命令:
mvn deploy- 其中default生命周期分為23個階段,如下列舉比較重要的幾個階段
- validate:驗證工程是否正確,所有需要的資源是否可用。
- compile:編譯項目的源代碼。
- test:使用合適的單元測試框架來測試已編譯的源代碼。這些測試不需要已打包和布署。
- Package:把已編譯的代碼打包成可發布的格式,比如jar。
- integration-test:如有需要,將包處理和發布到一個能夠進行集成測試的環境。
- verify:運行所有檢查,驗證包是否有效且達到質量標準。
- install:把包安裝到maven本地倉庫,可以被其他工程作為依賴來使用。
- Deploy:在集成或者發布環境下執行,將最終版本的包拷貝到遠程的repository,使得其他的開發者或者工程可以共享。
site
該生命周期的主要是建立和發布項目站點,Maven能夠基於POM所包含的信息,自動生成一個友好的站點
- 命令:
mvn site注意: 低版本的site插件可能引發失敗現象!升級高版本site插件即可!
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
maven命令是操作maven項目的重要方式,但是我們要知道maven命令只是支配maven插件工作的一個方式,其工作核心主要還是maven插件。maven內嵌了項目操作的插件,我們只需要通過執行命令來調用插件來完成項目的編譯、測試、發布等工作
注意: 執行一次命令可能會觸發多個插件工作
假如有Maven項目A,項目B依賴A,項目C依賴B。那麼我們可以說 C依賴A。也就是說,依賴的關係為:C – > B – > A, 那麼我們執行項目C時,會自動把B、A都下載導入到C項目的jar包文件夾中,這就是依賴的傳遞性。
依賴衝突我在上文中也提到過,依賴衝突是當直接引用或者間接引用出現了相同的jar包擁有不同版本的時候。
舉個例子:A依賴於B,B依賴於C,此時C的版本為V1.0;如果此時引入的C依賴還有一個V2.0,那麼我們的A傳遞依賴於C,此時C的版本為V2.0。這時候就是一個衝突,直接或間接的都引用了C,而C版本有兩個!
如果我不想在C依賴中出現B,那麼就可以主動的使用依賴排除技術,排除B依賴的引用,如下操作需要添加排除依賴的配置信息(<exclusions>標籤和其中信息,其中兩個id標籤是需要排除依賴的id):
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.12.RELEASE</version>
<!--手動排除依賴-->
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
自動解決依賴通途問題的兩個途徑分為:
短路優先原則和先聲明優先原則
首先,先看如下依賴關係
- A – > B – > C – > D – > E(V1.0)
- A – > F – > E(V2.0)
解釋: 1中,A依賴於B,B依賴於C,C依賴於D,D依賴於E,此時E的版本為V1.0版本(2中解釋基本相似)
所謂短路優先,就是路徑段的依賴有限被加載使用,這裏我們可以看到2中的路徑是最短的路徑,所以maven在加載依賴的時候,是使用2中的這一條依賴和版本
針對依賴路徑長度相同的情況,則使用
先聲明優先原則,看如下依賴關係
- A – > B – > C(V1.0)
- A – > D – > C(V2.0)
此時路徑優先原則不能解決問題時,maven需要判斷在A項目的<depencies>標籤內,B和D的哪個依賴聲明在前面,如果B依賴聲明早於D依賴,那麼就使用1中的這一條依賴和版本
微信公眾號 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司“嚨底家”!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新
.Net Core為我們提供了一套強大的Configuration配置系統,使用簡單擴展性強。通過這套配置系統我們可以將Json、Xml、Ini等數據源加載到程序中,也可以自己擴展其他形式的存儲源。今天我們要做的就是通過自定義的方式為其擴展Etcd數據源操作。
在使用etcd之前我們先介紹一下Etcd,我相信很多同學都早有耳聞。Etcd是一款高可用、強一致的分佈式KV存儲系統,它內部採用raft協議作為一致性算法,本身也是基於GO語言開發的,最新版本為v3.4.9,具體版本下載地址可參閱官方GitHub地址。相信了解過K8S的同學對這個肯定不陌生,它是K8S的數據管理系統。官方地址為https://etcd.io/。
在此之前,我相信大家已經了解過很多存儲系統了,Etcd到底能實現了什麼功能呢?其一用於配置中心和服務發現,再者也可以實現分佈式鎖和消息系統。它本身就是基於目錄型存儲,並且內部有一套強大的Watch機制可以監聽針對節點和數據的操作變化,每次對節點的事務操作都會有對於的版本信息。
通過上面的介紹是不是感覺和Zookeeper有點類似呢,網上有很多很多關於Etcd和Zookeeper的對比文章,大致如下可以得到以下結論
| 功能 | Etcd | Zookeeper |
|---|---|---|
| 分佈式鎖 | 有(採用節點版本號信息) | 有(採用臨時節點和順序臨時節點) |
| watcher | 有 | 有 |
| 一致性算法 | raft | zab |
| 選舉 | 有 | 有 |
| 元數據(metadata)存儲 | 有 | 有 |
| 應用場景 | Etcd | Zookeeper |
|---|---|---|
| 發布與訂閱(配置中心) | 有(不限次Watch) | 有(一次性觸發的,需要重新註冊Watch) |
| 軟負載均衡 | 有 | 有 |
| 命名服務(Naming Service) | 有 | 有 |
| 服務發現 | 有(基於租約節點) | 有(基於臨時節點) |
| 分佈式通知/協調 | 有 | 有 |
| 集群管理與Master選舉 | 有 | 有 |
| 分佈式鎖 | 有 | 有 |
| 分佈式隊列 | 有 | 有 |
說白了就是Zookeeper能幹的活,Etcd也能幹。那既然有了Zookeeper為啥還要選擇Etcd,主要基於以下原因
一言以蔽之,就是不僅實現了Zookeeper的功能,還在很多方面吊打Zookeeper,這麼強大的東西忍不住都要試一試。
在Nuget上可以搜索到很多.Net Core的Etcd客戶端驅動程序,我使用了下載量最多的一個名字叫dotnet-etcd的驅動包,順便找到了它在GayHub上,不好意思手滑打錯了GitHub上的項目地址,大概學習了一下基本的使用方式。其實我們結合Configuration配置這一塊,只需要兩個功能。一個是Get獲取數據,另一個是Watch節點變化(更新數據會用到)。個人認為,前期有目有邊界的學習還是非常重要的。
前面我們講到過自定義擴展Configuration是非常方便的,相信了解過Configuration相關源碼的小夥伴們已經非常熟悉了,大致總結一下分為三步:
因為微軟已經給我們提供了一部分便利,所以編寫起來還是非常的簡單的。好了,接下來我們開始編寫具體的實現代碼,重點的地方我會在代碼中註釋說明。
首先是定義擴展類EtcdConfigurationExtensions,這個類是針對IConfigurationBuilder的擴展方法,實現如下
public static class EtcdConfigurationExtensions
{
/// <summary>
/// AddEtcd擴展方法
/// </summary>
/// <param name="serverAddress">Etcd地址</param>
/// <param name="path">讀取路徑</param>
/// <returns></returns>
public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress,string path)
{
return AddEtcd(builder, serverAddress:serverAddress, path: path,reloadOnChange: false);
}
/// <summary>
/// AddEtcd擴展方法
/// </summary>
/// <param name="serverAddress">Etcd地址</param>
/// <param name="path">讀取路徑</param>
/// <param name="reloadOnChange">如果數據發送改變是否刷新</param>
/// <returns></returns>
public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress, string path, bool reloadOnChange)
{
return AddEtcd(builder,options => {
options.Address = serverAddress;
options.Path = path;
options.ReloadOnChange = reloadOnChange;
});
}
public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, Action<EtcdOptions> options)
{
EtcdOptions etcdOptions = new EtcdOptions();
options.Invoke(etcdOptions);
return builder.Add(new EtcdConfigurationSource { EtcdOptions = etcdOptions });
}
}
這裏我還定義了一個EtcdOptions的POCO,用於承載讀取Etcd的配置屬性
public class EtcdOptions
{
/// <summary>
/// Etcd地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// Etcd訪問用戶名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Etcd訪問密碼
/// </summary>
public string PassWord { get; set; }
/// <summary>
/// Etcd讀取路徑
/// </summary>
public string Path { get; set; }
/// <summary>
/// 數據變更是否刷新讀取
/// </summary>
public bool ReloadOnChange { get; set; }
}
接下來我們定義EtcdConfigurationSource,這個類非常簡單就是返回一個配置提供對象
public class EtcdConfigurationSource : IConfigurationSource
{
public EtcdOptions EtcdOptions { get; set; }
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new EtcdConfigurationProvider(EtcdOptions);
}
}
真正的讀取操作都在EtcdConfigurationProvider里
public class EtcdConfigurationProvider : ConfigurationProvider
{
private readonly string _path;
private readonly bool _reloadOnChange;
private readonly EtcdClient _etcdClient;
public EtcdConfigurationProvider(EtcdOptions options)
{
//實例化EtcdClient
_etcdClient = new EtcdClient(options.Address,username: options.UserName,password: options.PassWord);
_path = options.Path;
_reloadOnChange = options.ReloadOnChange;
}
/// <summary>
/// 重寫加載方法
/// </summary>
public override void Load()
{
//讀取數據
LoadData();
//數據發生變化是否重新加載
if (_reloadOnChange)
{
ReloadData();
}
}
private void LoadData()
{
//讀取Etcd里的數據
string result = _etcdClient.GetValAsync(_path).GetAwaiter().GetResult();
if (string.IsNullOrEmpty(result))
{
return;
}
//轉換一下數據結構,這裏我使用的是json格式
//讀取的數據只要賦值到Data屬性上即可,IConfiguration真正讀取的數據就是存儲到Data的字典數據
Data = ConvertData(result);
}
private IDictionary<string,string> ConvertData(string result)
{
byte[] array = Encoding.UTF8.GetBytes(result);
MemoryStream stream = new MemoryStream(array);
//JsonConfigurationFileParser是將json數據轉換為Configuration可讀取的結構(複製JsonConfiguration類庫里的)
return JsonConfigurationFileParser.Parse(stream);
}
private void ReloadData()
{
WatchRequest request = new WatchRequest()
{
CreateRequest = new WatchCreateRequest()
{
//需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
Key = ByteString.CopyFromUtf8(_path)
}
};
//監聽Etcd節點變化,獲取變更數據,更新配置
_etcdClient.Watch(request, rsp =>
{
if (rsp.Events.Any())
{
var @event = rsp.Events[0];
//需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
Data = ConvertData(@event.Kv.Value.ToStringUtf8());
//需要調用ConfigurationProvider的OnReload方法觸發ConfigurationReloadToken通知
//這樣才能對使用Configuration的類發送數據變更通知
//比如IOptionsMonitor就是通過ConfigurationReloadToken通知變更數據的
OnReload();
}
});
}
}
使用方式如下
builder.AddEtcd("http://127.0.0.1:2379", "service/mydemo", true);
順便給大家推薦一個Etcd可視化管理工具ETCD Manager,以便更好的學習Etcd。
到這裏,基本上就結束了,是不是非常簡單。主要還是Configuration本身的設計思路比較清晰,所以實現起來也不費勁。
以上代碼都已經上傳了我的GitHub,該倉庫還擴展了其他數據源的讀取比如Consul、Properties文件、Yaml文件的讀取,實現思路也都大致相似,有興趣的同學可以自行查閱。由於主要是講解實現思路,可能許多細節並未做處理還望見諒。如果有疑問或者更好的建議,歡迎評論區交流指導。
歡迎掃碼關注 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※教你寫出一流的銷售文案?
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※回頭車貨運收費標準
※別再煩惱如何寫文案,掌握八大原則!
※超省錢租車方案
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新
摘錄自2018年9月12日新華網報導
美國《國家科學院學報》前(10)日刊載的一項研究顯示,如把一氧化二氮排放考慮在內,水稻種植對全球變暖的影響可能比此前估計水平高出近一倍。
然而,包括中國、美國、印度在內的多數水稻生産國,目前都沒有將與水稻種植有關的一氧化二氮排放計入向聯合國提交的國家溫室氣體排放清單中。
美國環境保護基金組織的研究稱,近年來,水資源短缺導致越來越多的地區採用間歇性淹水法種植水稻,但在分析稻田對氣候的影響時,間歇性淹水稻田釋放的高水平一氧化二氮此前並未被計算在內,導致水稻種植對全球變暖的影響被嚴重低估。
一氧化二氮,又稱氧化亞氮,是重要的長效溫室氣體。在20年到100年時段中,其捕獲大氣熱量的能力是甲烷的數倍。最新研究顯示,間歇性淹水稻田釋放的一氧化二氮水平高達持續性淹水稻田的30到45倍,後者釋放的主要溫室氣體是甲烷。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司“嚨底家”!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※聚甘新