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/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

圖解Elasticsearch的核心概念

本文講解大綱,分8個核心概念講解說明:

  • NRT
  • Cluster
  • Node
  • Document&Field
  • Index
  • Type
  • Shard
  • Replica

Near Realtime(NRT)近實時

Elasticsearch的核心優勢就是(Near Real Time NRT)近乎實時,我們稱之為近實時。
NRT有兩個意思,下面舉例說明下:

  • 從寫入索引數據到數據可以被搜索到有一個小延遲(大概1秒);

舉個例子:電商平台新上架一個新商品,1秒後用戶就可搜索到這個商品信息,這就是近實時。

  • 基於Elasticsearch執行搜索和分析可以達到秒級查詢

也舉個例子說明,比如我現在想查詢我在淘寶,最近一年都買過幾件商品,總共花了多少錢,最貴的商品多少錢,哪個月買到東西最多,什麼類型的商品買的最多這樣的信息,如果淘寶說,你要等待10分鐘才能出結果,你是不是很崩潰,這個延遲的時間就不是近實時,如果淘寶可以秒級別返回給你,就是近實時了。

下面畫一個圖,解釋下三個基本概念的

Cluster:集群

包含多個節點,每個節點屬於哪個集群是通過一個配置(集群名稱,默認是elasticsearch)來決定的,對於中小型應用來說,剛開始一個集群就一個節點很正常。集群的目的為了提供高可用和海量數據的存儲以及更快的跨節點查詢能力。

Node:節點

集群中的一個節點,節點也有一個名稱(默認是隨機分配的),節點名稱很重要(在執行運維管理操作的時候),默認節點會去加入一個名稱為“elasticsearch”的集群,如果直接啟動一堆節點,那麼它們會自動組成一個elasticsearch集群,當然一個節點也可以組成一個elasticsearch集群

Document&field:文檔和字段

document 是es中的最小數據單元,一個document可以是一條客戶數據,一條商品分類數據,一條訂單數據,通常用JSON數據結構表示,每個index下的type中,都可以去存儲多個document。一個document裏面有多個field,每個field就是一個數據字段。

相當於mysql里的行,可以簡單這麼理解,舉個例子。一個商品的文檔數據一條如下:

product document
{
  "product_id": "1000",
  "product_name": "mac pro 2019 款筆記本",
  "product_desc": "高性能,高分辨率,編程必備神器",
  "category_id": "2",
  "category_name": "电子產品"
}

Index:索引

包含一堆有相似結構的文檔數據,比如可以有一個客戶索引,商品分類索引,訂單索引,索引有一個名稱。
一個index包含很多document,一個index就代表了一類類似的或者相同的document。比如說建立一個product index,商品索引,裏面可能就存放了所有的商品數據,所有的商品document。

Type:類型

每個索引里都可以有一個或多個type,type是index中的一個邏輯數據分類,一個type下的document,都有相同的field,比如博客系統,有一個索引,可以定義用戶數據type,博客數據type,評論數據type。

商品index,裏面存放了所有的商品數據,商品document

但是商品分很多種類,每個種類的document的field可能不太一樣,比如說電器商品,可能還包含一些諸如售後時間範圍這樣的特殊field;生鮮商品,還包含一些諸如生鮮保質期之類的特殊field

type,日化商品type,電器商品type,生鮮商品type

日化商品type:product_id,product_name,product_desc,category_id,category_name
電器商品type:product_id,product_name,product_desc,category_id,category_name,service_period
生鮮商品type:product_id,product_name,product_desc,category_id,category_name,eat_period

每一個type裏面,都會包含一堆document

{
“product_id”: “2”,
“product_name”: “長虹電視機”,
“product_desc”: “4k高清”,
“category_id”: “3”,
“category_name”: “電器”,
“service_period”: “1年”
}

{
“product_id”: “3”,
“product_name”: “基圍蝦”,
“product_desc”: “純天然,冰島產”,
“category_id”: “4”,
“category_name”: “生鮮”,
“eat_period”: “7天”
}

Shard 分片,也稱 Primary Shard

單台機器無法存儲大量數據,es可以將一個索引中的數據切分為多個shard,分佈在多台服務器上存儲。有了shard就可以橫向擴展,存儲更多數據,讓搜索和分析等操作分佈到多台服務器上去執行,提升吞吐量和性能。

每個shard都是一個lucene index。

Replica 副本,也稱 Replica Shard

任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,因此可以為每個shard創建多個replica副本。replica可以在shard故障時提供備用服務,保證數據不丟失,多個replica還可以提升搜索操作的吞吐量和性能。

primary shard(建立索引時一次設置,不能修改,默認5個),

replica shard(隨時修改數量,默認1個),

默認每個索引10個shard,5個primary shard,5個replica shard,最小的高可用配置,是2台服務器。

相關索引解釋說明:

  • index包含多個shard
  • 每個shard都是一個最小工作單元,承載部分數據,lucene實例,完整的建立索引和處理請求的能力
  • 增減節點時,shard會自動在nodes中負載均衡
  • primary shard和replica shard,每個document肯定只存在於某一個primary shard以及其對應的replica shard中,不可能存在於多個primary shard
  • replica shard是primary shard的副本,負責容錯,以及承擔讀請求負載
  • primary shard的數量在創建索引的時候就固定了,replica shard的數量可以隨時修改
  • primary shard的默認數量是5,replica默認是1,默認有10個shard,5個primary shard,5個replica shard
  • primary shard不能和自己的replica shard放在同一個節點上(否則節點宕機,primary shard和副本都丟失,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節點上

索引在集群中分配圖:

本文由博客一文多發平台 發布!

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

※帶您來了解什麼是 USB CONNECTOR  ?

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

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

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

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

學習算法課程之後的第一次記錄,漸漸的,程序設計考慮的因素增多,程序=數據結構+算法,這個等式讓我深有體會。從開始簡單的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 是電子產業重要的元件?

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

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

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

記錄工作遇到的死鎖問題(Lock wait timeout exceeded; try restarting transaction)

1.問題背景

剛來新公司不久,對業務還不太熟悉,所以領導先安排我維護原有系統。大概介紹下項目背景,項目分為核心業務部分在項目A中,與第三方交互的業務在項目B中,前端發起請求調用A項目接口,並在A項目中調用B項目接口,並在B項目中調用第三方獲取數據(原有系統這樣設計的)。

獲取到第三方數據后判斷數據庫中是否有該記錄(有唯一鍵),如有則執行更新操作,沒有則新增。並且如果第三方認為該數據已失效,需要從數據庫中刪除(邏輯刪除),並返回第三方刪除成功回調,後續便不會再查到已失效的數據。

對應流程圖如下

在代碼處理中對整個過程加事務@Transactional註解,即在對數據進行刪除(邏輯刪除,實際執行update語句)時會根據唯一索引對該行加鎖。在生成環境B項目頻繁出現Lock wait timeout exceeded; try restarting transaction 異常,經排查定位到該功能代碼,排查代碼發現該功能有如下代碼

有經驗的同學應該已經看出問題所在,這裏將全局異常捕獲,記錄錯誤日誌,但問題就出在catch這裏,由於異常被catch吞噬,@Transactional無法拿到異常,所以不會執行rollback回滾,導致一直佔用數據庫行鎖。(這裏的異常是調用第三方接口失敗,由於調用太頻繁,第三方接口崩潰,這裏後續也做了併發控制) 所以後續事務在執行更新該行記錄時由於得不到鎖而等待失敗,就報了Lock wait timeout exceeded; try restarting transaction 異常。知道了問題出在什麼地方,解決起來也就簡單了,在catch中再將異常主動拋出即可 。即 throw e

  

2.問題影響

由於該接口是在核心項目A中有客戶端發起調用,並在A項目中調用B項目,由於B項目死鎖無法返回結果,導致A項目前端大量請求阻塞,由於tomcat支持的請求線程數有限,該問題直接導致A服務宕機。影響較為嚴重。

 

3.如何解決

下面說下該問題解決思路,由於A項目宕機,在服務器日誌中可以看到大量上述異常信息,Lock wait說明出現了鎖問題。

  a.使用 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;查看當前事務,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;查看當前鎖定的事務,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;查看當前等鎖的事務。使用以上三個sql基本能定位到代碼所在位置。

  b.定位到代碼后,就要看具體的代碼問題了,導致異常沒有回滾的原因很多。這裏說一個注意事項,使用@Transactional註解,默認只會對RuntimeException進行回滾,而對IOException和SQLException不會觸發回滾。如果要對兩個非運行時異常進行回滾,需要在@Transactional中加入@Transactional( rollbackForClassName = {“IOException”,”SQLException”})或對全局異常Exception做回滾,配置為@Transactional(rollbackFor = Exception.class)。又或者捕獲IOException後手動拋出一個RuntimeException

  

總結

  以上為博主在實際工作中遇到的問題,這裏記錄一下方便以後遇到類似問題可以快速定位並解決問題。也希望能對大家有幫助。

 

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

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

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

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

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

 

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

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

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

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

PL真有意思(二):程序設計語言語法

前言

雖然標題是程序語言的語法,但是講的是對詞法和語法的解析,其實關於這個前面那個寫編譯器系列的描述會更清楚,有關語言語法的部分應該是穿插在整個設計當中的,也看語言設計者的心情了

和英語漢語這些自然語言不一樣,計算機語言必須是精確的,它們的語法和語義都必須保證沒有歧義,這當然也讓語法分析更加簡單

所以對於編譯器一項很重要的任務就是時別程序設計語言的結構規則,要完成這個目標就需要兩個要求:

  • 完成對語法規則的描述
  • 確定給定程序是否按照這些規則構造起來,也就是符合語法規則

第一個要求主要由正則表達式和上下文無關文法來描述完成,而第二個要求就是由編譯器來完成,也就是語法分析了

描述語法:正則表達式和上下文無關語法

對於詞法,都可以用三種規則描述出來:

  1. 拼接
  2. 選擇
  3. Kleene(也就是重複任意多次)

比如一個整數常量就可以是多個数字重複任意多次,也叫做正則語言。如果對於一個字符串,我們再加入遞歸定義即可以描述整個語法,就可以稱作上下文無關語法

單詞正則表達式

對於程序語言,單詞的類型不外乎關鍵字、標識符、符合和各種類型的常量

對於整數常量就可以用這樣的正則表達式來表示

integer -> digit digit* digit -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

上下文無關文法

一般正則表達式只適用於描述單詞,因為正則表達式無法描述嵌套結構,一般正則表達式的實現都是用有限狀態自動機,之前用Python實現了一個簡單的也是這樣,但是對於匹配任意深度的嵌套結構就需要有一個任意大的狀態機,顯然不符合。而定義嵌套結構對於描述語法非常有用,所以就有了上下文無關文法

expr := id | number | - expr | ( expr ) | expr or expr

op := + | - | * | /

對於上下文無關文法,每條規則叫做一個產生式,產生式左部的符合稱為非終結符,而右部則是多個終結符或者非終結符,最後所有規則都會推到至終結符上,而終結符就是正則表達式定義的單詞

推導和語法樹

一個正確的上下文無關文法,就可以指導我們如何生成一個合乎語法的終結符串

最簡單的就是從開始符號開始,用這個產生式的右部取代開始符合,再從得到的串選擇一個非終結符繼續進行推導,直到沒有剩下的非終結符,這個過程就像遞歸構造一個樹的過程

expr := expr op expr
     := expr op id
     := expr + id
     := expr op expr + id
     := expr op id + id
     := expr * id + id
     := id * id + id

但是對於給定的上下文語法有可能會推導出不止一顆語法分析樹,我們就說這個上下文語法是存在歧義性的。所以對於上面的上下文無關語法還有更好的文法

掃描

掃描也就是詞法分析,詞法分析完全可以不需要什麼正則表達式、自動機什麼的,徒手擼出來,現在業界為了更好的生成錯誤信息,應該很多也是手工的詞法分析器

手工的詞法分析器,無非就是一直讀入字符,到能判斷出它的token在送入語法分析器

有限狀態自動機

使用有限狀態機的詞法分析一般都是這樣的幾個步驟

  • 給出詞法的正則表達式

  • 將正則表達式轉換為非確定有限自動機(NFA)

其實對於任意的正則表達式都可以用拼接、選擇和Kleene閉包來表示

而同樣的,有限自動機也可以通過這三種方式來表示,圖就不畫了,這個在之前寫Python正則表達式引擎的文章里都畫過了(溜了

  • 將NFA轉換為確定性有限狀態自動機(DFA)

將NFA轉換到DFA可以採用的是子集構造法,主要思想就是,在讀入給定輸入之後所到達的DFA狀態,表示的是原來NFA讀入同樣輸入之後可能澳大的所有狀態

  • 最小化DFA

對於最小化DFA的主要思想是,我們把DFA所有狀態分為兩個等價類,終止態狀態和非終止狀態。然後我們就反覆搜索等價類X和輸入符合c,使得當給定C作為輸入時,X的狀態能轉換到位於k>1個不同等價類中的狀態。之後我們就把X劃分為k個類,使得類中所有轉檯對於C都會轉移到同一個老類的成員。直到無法再按這種方式找到劃分的類時,我們就完成了

這四個步驟在之前的寫的正則表達式引擎中都完成了,在那三篇文章里會更詳細一點

語法分析

一般語法分析器的輸入是token流,而輸出是一顆語法分析樹。其中分析方法一般可以分為自上而下和自下而上兩類,這些類中最重要的兩個分別稱為LL和LR

LL表示從左向右,最左推導,LR表示從左向右,最右推導。這兩類文法都是從左到右的順序讀取輸入,然後語法分析器試圖找出輸入的推導結果

自上而下的方式

一般自上而下的語法分析器比較符合之前的推導方法,從根節點開始像恭弘=叶 恭弘節點反覆的遞歸推導,直到當前的恭弘=叶 恭弘節點都是終結符

  • 遞歸下降

遞歸下降很符合上面說的從根節點出發進行推導,一般用於一些相對簡單一些的語言

read A
read B
sum := A + B
write sum
write sum / 2

比如對於這個程序的遞歸下降,語法分析器一開始調用program函數,在讀入第一個單詞read后,program將調用stmt_list,再接着調用stmt才真正開始匹配read A。以這種方式繼續下去,語法分析器執行路徑將追溯出語法分析樹的從左向右、自上而下的遍歷

  • 表格驅動的LL自上而下

表格驅動的LL是基於一個語法分析表格和一個棧

分析流程是

  1. 初始化一個棧
  2. 將開始符號壓入棧
  3. 彈出棧頂,然後根據棧頂的符號和當前的輸入符號查表
  4. 如果彈出的是非終結符,將會繼續查表來確定下一個壓入棧中的產生式
  5. 如果是終結符將進行匹配

預測集合

從上面可以看出來最重要的就是那個語法分析表格了,語法分析表格其實就是根據當前輸入字符對下一個產生式的預測,這裏就要用到一個概念:預測集合,也就是First和Follow集合。這個在之前寫編譯器系列講的比較詳細,在這裏就不寫了

當然LL語法也會有很多處理不了的文法,所以也才會有其它的語法分析方法

自下而上的方式

在實踐中,自下而上的語法分析都是表格驅動的,這種分析器在一個棧中保存所有部分完成的子樹的根。當它從掃描器中得到一個新的單詞時,就會將這個單詞移入棧。當它發現位於棧頂的若干符號組成一個右部時,它就會將這些符號歸約到對應的左部。

一個自底向上的語法分析過程對應為一個輸入串構造語法分析書的過程,它從恭弘=叶 恭弘子節點開始,通過shift和reduce操作逐漸向上到達根節點

自底向上的語法分析需要一個堆棧來存放解析的符號,例如對於如下語法:

0.  statement -> expr
1.  expr -> expr + factor
2.           | factor
3.  factor ->  ( expr )
4.           | NUM

來解析1+2

stack input
null 1 + 2
NUM + 2 開始讀入一個字符,並把對應的token放入解析堆棧,稱為shift操作
factor + 2 根據語法推導式,factor -> NUM,將NUM出棧,factor入棧,這個操作稱為reduce
expr + 2 這裏繼續做reduce操作,但是由於語法推導式有兩個產生式,所以需要向前看一個符合才能判斷是進行shift還是reduce,也就是語法解析的LA
expr + 2 shift操作
expr + NUM null shift操作
expr + factor null 根據fator的產生式進行reduce
expr null reduce操作
statement null reduce操作

此時規約到開始符號,並且輸入串也為空,代表語法解析成功

有限狀態自動機的構建

0.  s -> e
1.  e -> e + t
2.  e -> t
3.  t -> t * f
4.  t -> f
5.  f -> ( e )
6.  f -> NUM
  • 對起始推導式做閉包操作

先在起始產生式->右邊加上一個.

s -> .e

對.右邊的符號做閉包操作,也就是說如果 . 右邊的符號是一個非終結符,那麼肯定有某個表達式,->左邊是該非終結符,把這些表達式添加進來

s -> . e
e -> . e + t
e -> . t

對新添加進來的推導式反覆重複這個操作,直到所有推導式->右邊是非終結符的那個所在推導式都引入

  • 對引入的產生式進行分區

把 . 右邊擁有相同非終結符的表達式划入一個分區,比如

e -> t .
t -> t . * f

就作為同一個分區。最後把每個分區中的表達式中的 . 右移動一位,形成新的狀態節點

  • 對所有分區節點構建跳轉關係

根據每個節點 . 左邊的符號來判斷輸入什麼字符來跳入該節點

比如, . 左邊的符號是 t, 所以當狀態機處於狀態0時,輸入時 t 時, 跳轉到狀態1。

  • 對所有新生成的節點重複構建

最後對每個新生成的節點進行重複的構建,直到完成所有所有的狀態節點的構建和跳轉

小結

這一篇主要是提了對詞法和語法的分析過程,因為想要結合語言設計和實踐,更詳細的應該去看前面的寫一個編譯器系列

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

※帶您來了解什麼是 USB CONNECTOR  ?

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

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

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

算法導論

  

一.算法

  非形式地說,算法【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 正式環境必不可少的外部化配置

前言

中有讀者反應:

部署后運維很不方便,比較修改一個 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 領域知識的深入學習,從源碼到原理,系統有序的學習)

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

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

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

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

特斯拉需求大!住友金屬追加擴產電池材料、增至2.5倍

 

日本住友金屬礦山(Sumitomo Metal Mining)28日發布新聞稿宣布,該公司雖已於去年10月27日表示將砸下180億日圓於2018年1月將鋰離子電池正極材料「鎳酸鋰(見附圖)」月產能擴增至3,550噸,不過因電動車(EV)用鋰離子電池需求擴大,因此決議對「鎳酸鋰」進行追加增產措施,計畫投入40億日圓於磯浦工廠進行增產工程,目標在2018年6月將整體「鎳酸鋰」月產能擴增至4,550噸、將達現行的2.5倍。

住友金屬礦山指出,該公司正持續擴大與Panasonic攜手研發的高性能鎳酸鋰產能,此次為了因應Panasonic擴大鋰離子電池產能、故決定對鎳酸鋰進行追加增產投資。

據日經新聞指出,住友金屬礦山追加增產「鎳酸鋰」主要是因應美國EV廠特斯拉(Tesla)增產所需。據報導,住友金屬礦山目前透過Panasonic供應特斯拉電動車所需的大部分車用電池正極材料。

根據嘉實XQ全球贏家系統報價,截至台北時間31日上午8點50分為止,住友金屬礦山上揚1.34%至1,660.5日圓,稍早最高漲至1,664.5日圓創約5個月來(2月16日以來)新高水準。

特斯拉平價電動車「Model 3」於7月28日正式交車。Business Insider、The Motley Fool、Electrek等外電報導,Model 3售價35,000美元,特斯拉原本計畫要在2020年底前,將Model 3年產量提升至50萬台,但去(2016)年該公司把目標提前兩年、移至2018年。不過,Model 3目前的生產年率還只有10萬台,特斯拉想要達標、產速勢必得快速拉升。

富士經濟6月22日公布調查報告指出,預估2030年時EV年銷售量將增至407萬台、超越HV(油電混合車、2030年銷售量預估為391萬台),且之後雙方的差距將持續擴大。富士經濟預估,在中國需求增加加持下,2035年EV全球銷售量將擴大至630萬台、將達2016年的13.4倍(較2016年增加12.4倍)。

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

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

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

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

燃料電池車緩不濟急,豐田擬2019年量產電動車

中國擅長以政策引導經濟發展,據日經新聞報導,豐田為符合中國新能源車規定,可能於2019年開始在中國量產電動車。

報導指出,有鑒於美國、中國與其它地區汽車排放規定轉嚴,豐田已要求同集團的汽車零件廠Denso、愛信精機(Aisin Seiki)合力成立子公司,務求加速電動車的開發作業。

就新能源車而言,以氫氣驅動的「燃料電池車」才是豐田首選,然而「燃料電池車」需要廣建加氫站曠日廢時,而中國新能源車最快於2018年上路,迫使豐田退而求其次。

豐年2012年就曾推出RAV4 EV電動休旅車,採用特斯拉製鋰電池,但市場反應不佳,僅賣出2500輛,豐田隨後也宣布停產。在中國政策引導下,豐田第二次做電動車是否會產生不一樣的結果,有待觀察。

吉利汽車旗下的Volvo日前已宣布從2019年起,旗下所有新車都會是純電動或油電混合驅動,象徵純汽油車將走入歷史。

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

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

【其他文章推薦】

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

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

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

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