標籤: iphone維修

  • xlua中lua對象到c#對象的轉型

    xlua中lua對象到c#對象的轉型

    lua中的類型

    基礎類型

    #define LUA_TNIL		0
    #define LUA_TBOOLEAN		1
    #define LUA_TLIGHTUSERDATA	2
    #define LUA_TNUMBER		3
    #define LUA_TSTRING		4
    #define LUA_TTABLE		5
    #define LUA_TFUNCTION		6
    #define LUA_TUSERDATA		7
    #define LUA_TTHREAD		8
    

    變體(或者說子類型)

    /*
    ** tags for Tagged Values have the following use of bits:
    ** bits 0-3: actual tag (a LUA_T* value)
    ** bits 4-5: variant bits
    ** bit 6: whether value is collectable
    */
    
    /*
    ** LUA_TFUNCTION variants:
    ** 0 - Lua function
    ** 1 - light C function
    ** 2 - regular C function (closure)
    */
    
    /* Variant tags for functions */
    #define LUA_TLCL	(LUA_TFUNCTION | (0 << 4))  /* Lua closure */
    #define LUA_TLCF	(LUA_TFUNCTION | (1 << 4))  /* light C function */
    #define LUA_TCCL	(LUA_TFUNCTION | (2 << 4))  /* C closure */
    
    
    /* Variant tags for strings */
    #define LUA_TSHRSTR	(LUA_TSTRING | (0 << 4))  /* short strings */
    #define LUA_TLNGSTR	(LUA_TSTRING | (1 << 4))  /* long strings */
    
    
    /* Variant tags for numbers */
    #define LUA_TNUMFLT	(LUA_TNUMBER | (0 << 4))  /* float numbers */
    #define LUA_TNUMINT	(LUA_TNUMBER | (1 << 4))  /* integer numbers */
    
    
    /* Bit mark for collectable types */
    #define BIT_ISCOLLECTABLE	(1 << 6)
    

      lua中的對象都是用TValue來描述的,TValue中的tt_成員變量代表着這個TValue的類型。關於類型的具體定義,上面貼的代碼中的註釋中已經講的比較清楚了。
      一個lua對象的類型是由一個7位的bits描述的。比如一個整數,這個對象的類型就是0011000(24)表示這個對象是数字類型中的整形,是一個不可回收對象。

    C#如何獲取lua對象

      和c語言和lua交互其實沒啥本質區別,就是通過lua提供的c函數操作lua棧,直接從棧中取就可以了。區別在於如何把取到的值轉換為c#認識的值。

    如何在C#端描述這些類型

    簡介

      lua的類型中boolean、string、number這幾個類型是clr所認識的類型,所以clr就可以直接把這些類型拿過來用。具體就是直接調用Lua提供的lua_tonumber之類的c接口。
      lightUserData、table、function、userData、thread是C#不認識的類,需要通過某種標識(lua自帶的reference系統)來表示。

    boolean、string、number類

      這三個類上面已經說過了,直接用提供的接口轉就可以,下面寫幾個需要注意的點:

    1. string雖然也是一個引用類型,但是clr在拿到這個string的指針時,還需要將這個string的數據直接複製進clr中才算轉型結束(xlua也已經封裝好了,不用我們自己去複製)。
    2. 大部分類型轉型失敗的時候都不會報錯,而是會返回一個默認值。就拿將一個lua對象轉為int來說,最終是通過lua_tointegerx函數調用的,當lua對象不是number類型時,返回0:
    LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
      lua_Integer res;
      const TValue *o = index2addr(L, idx);
      int isnum = tointeger(o, &res);
      if (!isnum)
        res = 0;  /* call to 'tointeger' may change 'n' even if it fails */
      if (pisnum) *pisnum = isnum;
      return res;
    }
    
    1. 當一個number類型是浮點數時,轉型整數不會進行取整操作,而是會直接返回0。因為lua默認對float轉int的操作模式LUA_FLOORN2I是0,代表碰見float轉int時返回0。
    /*
    ** try to convert a value to an integer, rounding according to 'mode':
    ** mode == 0: accepts only integral values
    ** mode == 1: takes the floor of the number
    ** mode == 2: takes the ceil of the number
    */
    int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
      TValue v;
     again:
      if (ttisfloat(obj)) {
        lua_Number n = fltvalue(obj);
        lua_Number f = l_floor(n);
        if (n != f) {  /* not an integral value? */
          if (mode == 0) return 0;  /* fails if mode demands integral value */
          else if (mode > 1)  /* needs ceil? */
            f += 1;  /* convert floor to ceil (remember: n != f) */
        }
        return lua_numbertointeger(f, p);
      }
      else if (ttisinteger(obj)) {
        *p = ivalue(obj);
        return 1;
      }
      else if (cvt2num(obj) &&
                luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
        obj = &v;
        goto again;  /* convert result from 'luaO_str2num' to an integer */
      }
      return 0;  /* conversion failed */
    }
    

    userData

      userData主要是lua對c#對象的引用,這裏只簡單說一下。
      代表c#對象的userData主要分兩種。

    1. 把c#對象存在ObjectTranslator中,用下標作為引用(類似於lua中的reference)。
    2. 經過GC優化的結構體和枚舉,不存在ObjectTranslator中,而是把所有內容都打包到userdata中一起傳入lua中。比如一個Vector3,那麼xlua會把這個Vector3的x、y、z作為3個連續的float一起打包到userdata中。這樣就避免了c#層的裝箱、拆箱和gc操作。

    對table與function的引用簡介

      這兩個類型都是通過lua的reference系統來讓c#持有對lua對象的引用。

    lua reference系統

      c#就是通過這個系統來持有不認識的lua對象的。
      一共就兩個接口:

    1. luaL_ref:把棧頂元素加入一個lua的表中,並返回下標。
    2. luaL_unref:把一個下標所代表元素從表中刪除。

      這樣就可以用一個整數來讓lua外的環境持有這個lua對象。
    具體可以看下官方說明lua References

    luaBase類

      所有lua對象在c#中的基類,在初始化時通過luaL_ref生成lua對象的引用,在析構時通過luaL_unref移除引用。

    對table的引用

    LuaTable

      一般情況下table在C#中被包裝為LuaTable類,沒啥特別的,只是在LuaBase的基礎上增加了幾個常用的函數。比如Get、Set之類的,讓開發者可以避開一些不直觀的棧操作。

    Array、List、Dictionary

      這幾個都差不多。都是把table中的key和value全部拿出來,組成Array或Dictionaray。

    接口、其他類

      這兩種轉型是嘗試把這個table看作對應的接口或類。
      比如將一個table轉為IEnumberator就是把table轉為SystemCollectionsIEnumeratorBridge類(繼承了LuaBase、實現了IEnumerator的類,由Xlua生成),這個類實現了MoveNext和Reset。實現方法就是調用一下table中對應名稱的函數。

    對function的引用

      lua函數在c#中有兩種表示:

    LuaFunction

      LuaFunction和luaTable差不多,也是在LuaBase的基礎上增加了幾個常用函數,Call、Action之類的。

    DelegateBridge

      為什麼已經有LuaFunction還要一個DelegateBridge類?
      因為我們在c#中拿到一個lua函數時,大多數時候是要作為一個委託來時用的。DelegateBridge就是用來化簡這個轉型操作的。
      DelegateBridge的功能就是在持有lua函數引用的同時,將這個函數包裝成各種各樣的委託,讓整個轉型過程對開發人員無感知。
      下面是一個不使用DelegateBridge,自己轉型的例子,比較繁瑣:

    //將一個LuaFunction作為一個Action<int>使用
    //其實LuaFunction.Cast就是干這個的,這裏只是用簡單的方式表達出來
    public static Action<int> LuaFunctionToActionInt(XLua.LuaFunction luaFunction)
    {
        //由於luaFunction已經提供了Call操作封裝了函數調用的各種棧操作,所以我們這裏只需要用一個Action<int>把這個操作包裝起來即可
        return (x) =>
        {
            luaFunction.Call(x);
        };
    }
    
    public static void Test()
    {
        XLua.LuaEnv luaEnv = new XLua.LuaEnv();
        object[] rets = luaEnv.DoString("return function(x) CS.UnityEngine.Debug.LogError(\"print x: \"..x) end");
        var luaFunction = (XLua.LuaFunction)rets[0];
        Action<int> actionInt = LuaFunctionToActionInt(luaFunction);
        actionInt(10);
    }
    

    DelegateBridge重要成員

    xlua在將lua函數轉型的時候做了什麼

    Tips

    1. 通過ObjectTranslator.getDelegateUsingGeneric生成委託時,會對返回值和參數進行不為值類型的約束。因為值類型在il2cpp下會有jit異常。這也是為什麼我們發現有的委託類型不用註冊也可以使用,但是有的就不行。
    2. 在編輯器模式下,沒有進行代碼生成時,會通過Emit直接生成一個XLuaGenDelegateImplx類,內容和通過代碼生成后的DelegateBridge一樣,而不是全部通過反射來進行轉型。讓沒有進行代碼生成時的環境和真機環境更接近。
    3. DelegateBridge一般不會被直接引用,而是被bindto中的委託生成的閉包引用和被delegate_bridges作為弱引用持有。當一個DelegateBridge的bindto中的委託沒有被任何對象引用時,這個DelegateBridge就會在下次gc時被gc掉。

    其他

      這裏主要寫了常用lua類型轉型的簡介和一些關鍵點。可能不夠全面和細節。
      如果有什麼錯誤或者問題可以在下面留言。

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

    【其他文章推薦】

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

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

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

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

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

  • 繼續等還是放棄?那麼多人愛的帝豪GS究竟值不值得等

    繼續等還是放棄?那麼多人愛的帝豪GS究竟值不值得等

    全景天窗真的太贊了,雖然不能打開,但是這種採光在傍晚以及晚上的時候,超有高檔車的感覺。最不滿意的地方:後備箱容積感覺上是比較小的,不過畢竟車身也不是很大的樣子。另外就是中控屏是電阻屏的,操作起來不是非常靈敏。

    前言

    帝豪GS,在尚未上市的時候就已經引起了不少人關注。不俗的顏值加上較高的配置,即使是和着價位相差不遠的合資緊湊型轎車相比也沒有太大的差距。但是,這款車在實際銷售上是供不應求的,提車需要等待很長的時候,不少人想要年前提車,那麼它是否真的值得購買呢?還是應該早點退訂金,換成別的車型?

    吉利帝豪GS

    官方指導價:7.78-10.88萬

    編者意見:顏值高,還有着同級中罕見的自動剎車以及ACC自適應巡航,就內飾來說是在該價位國產汽車的前列。

    車主:放羊買飛機

    購買車型:帝豪GS 2016款 運動版 1.3T 自動臻尚型

    裸車購買價:10.88 萬元

    綜合油耗:7.5L

    最滿意的地方:外觀以及配置,外觀非常時尚開出去有面子,而且內飾無論是做工還是設計都是不錯的,所以朋友們經常以為這是20多萬的車型。這個比較高的車身還有着比轎車好一點的視野,女士開起來也不費勁。

    最不滿意的地方:底盤太硬了,不是很舒服,過一些坑窪的地方的時候非常明顯。另外就是隔音水平是比較一般的,在高速上可以聽到胎噪以及風噪,在80km/h以上就出現了。

    車主:大山

    購買車型帝豪GS 2016款 運動版 1.3T 自動臻尚型

    裸車購買價:10.88 萬元

    綜合油耗:8L

    最滿意的地方:ACC自適應巡航在高速的時候真的非常好用,覺得自己選擇頂配是正確的,這樣的主動安全配置在這個價位真的是罕見的,關鍵給了不少的安全感。全景天窗真的太贊了,雖然不能打開,但是這種採光在傍晚以及晚上的時候,超有高檔車的感覺。

    最不滿意的地方:後備箱容積感覺上是比較小的,不過畢竟車身也不是很大的樣子。另外就是中控屏是電阻屏的,操作起來不是非常靈敏。

    車主:四年又四年

    購買車型:帝豪GS 2016款 運動版 1.8L 自動領尚型

    裸車購買價:9.48 萬元

    綜合油耗:9.5L

    最滿意的地方:運動版的外觀,真的非常好看,看起來非常協調。配置也是很高,這個價位的緊湊型SUV,還要有电子手剎、自動大燈、自動空調、定速巡航的真的沒有多少輛,而且自動駐車這個功能非常實用,解放了我的右腳刷新了我對開車的體驗。

    最不滿意的地方:可能是因為我的是1.8L自動擋的原因,感覺油耗真的是有點高。其次還是後備箱小以及底盤是比較硬。最後是個人覺得儲物空間比較少,想要放些東西都是比較困難。

    編者總結:

    根據車主反映,1.3T版本是明顯要比1.8L的省油,而且無論是手動擋還是自動擋油耗都相差無幾,所以我們建議選擇1.3T自動擋車型。帝豪GS有着超高的配置水平以及顏值,加上1.3T油耗表現不俗,所以這輛車是非常值得等的。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

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

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

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

  • 潤滑油巨頭強勢發布——雪佛龍金富力

    潤滑油巨頭強勢發布——雪佛龍金富力

    產品在抗腐蝕和抗磨損性,減少油泥與積碳,提升發動機性能和燃油經濟性這幾大方面均優於潤滑油行業最嚴格的標準。新品系列也採用了針對中國市場度身定製的配方和技術,滿足中國消費者對潤滑油產品的更高要求。”雪弗龍在發布會上展示產品的測試結果显示:金富力機油提供卓越的抗磨損保護和抗腐蝕保護,分別比ApI標準高出80%與90%。

    2016年12月8日,世界500強、世界領先的一體化能源企業雪弗龍,在浙江嘉興舉行了旗下金富力品牌全系潤滑油的新品發布會。

    這次發布會上,雪弗龍為消費者帶來了金富力全新系列產品,包括金富力全合成潤滑油、金富力合成型潤滑油及金富力方程式潤滑油三種。

    雪弗龍金富力在此次新品發布會主推油泥防禦盾™技術,雪佛龍(中國)投資有限公司產品技術專家,王琴女士表示:“因為雪佛龍是一家比較獨特的潤滑油生產商,它是目前全球為數不多的一家既有既具備基礎油生產能力,又具備添加劑生產能力的潤滑油生產廠商。所以在研發方面,雪佛龍一直都是比較領先的。而油泥防禦盾™是雪佛龍獨有的科技,它給消費者帶來最大的好處,第一個就是保護性能很強,它能夠很好地防止發動機內部磨損,保護髮動機。另外它能夠延長發動機的使用壽命,因為金富力的抗氧化性能很好,在整個潤滑油的使用過程中,它都能像新油一樣保護髮動機。最後油泥防禦盾™也能很好地提高發動機的燃油經濟性。”

    發布會上,雪佛龍潤滑油亞太區技術專家,Joyce女士介紹到:“此次上市的雪佛龍金富力全系產品,擁有包括油泥防禦盾
    TM科技在內的很多創新技術。產品在抗腐蝕和抗磨損性,減少油泥與積碳,提升發動機性能和燃油經濟性這幾大方面均優於潤滑油行業最嚴格的標準。新品系列也採用了針對中國市場度身定製的配方和技術,滿足中國消費者對潤滑油產品的更高要求。”

    雪弗龍在發布會上展示產品的測試結果显示:金富力機油提供卓越的抗磨損保護和抗腐蝕保護,分別比ApI標準高出80%與90%。在減少機油濾網上的油泥方面,金富力機油的性能比GM Dexos1標準要求高出 10%。採用油泥防禦盾配方的金富力機油的粘度保持性能比GM Dexos1 標準所要 求的高出70%。

    雪佛龍一直秉承着專業的研發態度,追求精湛的工藝,力求將產品做到極致。這次發布會上新產品,針對中國消費習慣與獨特的路況問題,提出了可行性的解決方案,為打開中國市場做好鋪墊。隨着雪佛龍金富力的發布,雪佛龍將為中國消費者及合作夥伴帶來全球領導的品牌,一流的產品。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

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

  • 實測傳說中的最強斯柯達SUV!如果定價十來萬肯定要賣瘋…

    實測傳說中的最強斯柯達SUV!如果定價十來萬肯定要賣瘋…

    高配車型還有電動尾門,實用性非常出色。至於它的第三排座椅,在看來更多的是應急使用。進入第三排仍然會有些困難,對於家裡的一些上了年紀的家人來說,還是安安分分坐在第二排吧,較高的離地間隙也是一個硬傷。因此7座的柯迪亞克更多是讓消費者有更多的選擇,5座的車型仍然廠家宣傳的主力車型。

    作為整篇的開頭,可以下一個結論了;試完柯迪亞克之後,我的心裏已經有一個答案了,看厭了大眾千篇一律的設計造型,如今的年輕人是時候換一台具有大眾品質但外觀與空間都表現更加出色的SUV了。

    作為大眾旗下的一個子公司,斯柯達一直受到的關注相對來說還是少了一點。但作為一家公司而言,斯柯達肯定不會一直甘於人下,被所有人都認為是大眾小弟的。於是斯柯達在醞釀已久之後,開始在全世界展示這台充滿北歐風情,但卻符合大眾消費者審美的SUV車型。

    犀利的外觀造型,人性化的設計

    之前得知柯迪亞克要在廣州車展做展示的消息,尋思着在車展期間好好欣賞一下這款出自斯柯達首款7座SUV,無奈是由於眾多媒體的圍觀,雖然對它非常感興趣,但能觸摸到的時間真的不多。如今不遠萬里來到充滿熱情的西班牙,我仍然按捺住自己心裏的躁動,只想靜靜品味它獨特的外觀造型。

    柯迪亞克這個有點拗口的名字是來源自身形龐大的棕熊,第一次看到它時候覺得這個名字改得相當貼切。龐大的車身採用凌厲的線條勾勒出動感的車身造型,飽滿之餘卻不臃腫。極富張力的前臉設計給人的印象相當深刻,粗壯的直瀑式進氣格柵與犀利的LED前大燈營造出的前臉氣場很足,一如它的名字。

    從大燈延伸要車尾的三維腰線使得車身具有不錯的立體感,C柱與D柱之間的小舷窗的設計使得車身的造型非常協調,配合外擴式輪罩設計,使得車身充滿力量感。簡潔的車尾卻不缺少變化,標誌性的C型LED尾燈造型與視覺效果相當出色。

    除了出色的外觀造型,柯迪亞克也變得相當的人性化,設計師有時候觀念的轉變最後受益是我們消費者。這個從它的一些設計小細節就可以看出。開門的時候,由於很多人都非常擔心碩大的車門會碰到隔壁的牆壁或者車,而柯迪亞克則設計了一套可伸縮的防擦條,開門的時候自動車身,很巧妙的設計卻不會影響美觀。之前在速派出現過的門板處設計摺疊傘存放槽,這在柯迪亞克也有看到,而且正副駕駛都有,是非常貼心的裝置。

    熟悉的內飾,貼心的配置

    進入車內,依然是熟悉的大眾設計風格,卻擁有斯柯達自家的基因,一切以實用為主。規整的中控造型配上仿木紋的裝飾面板,相當具有檔次。應用多年的老氣多輻式方向盤終於壽終正寢,換裝了一個手感良好大小適中的三輻式方向盤。

    8英寸的觸摸屏显示效果比較清晰,配合觸摸式的按鍵,上手比較簡單,由於海外版本搭載是谷歌地圖,在試駕途中沒有好好體驗。分區明確的中控台無論做工還是按鍵的手感都都相當出色,符合一款旗艦SUV的身價。中控下方的儲物格空間很大,能放置I7 plus,還有無線充電功能,希望到時國內上市時還有這個提升逼格的配置。

    讓驚喜是它的副駕駛後方設置了一個小桌板與手機支架,可以讓後排乘客在旅途當中不僅看看自己喜歡的電影,還能就着電影吃零食。後排頭枕兩側還有貼心護翼,後排乘客看累了電影還能舒服地睡個覺。

    五座為主,7座為輔

    進入車內,前排空間就不用多說了,雖然身材不算很高,但頭部空間與腿部空間都非常充裕。得益於2791mm的軸距,它的第二排空間非常寬敞,雖然坐墊有些短,但對這些身高一米7多點還是足夠的,舒適性不差。配合碩大的全景天窗,後排乘客體驗非常出色。後排整體放倒比較規整,後備箱的空間非常寬敞;高配車型還有電動尾門,實用性非常出色。

    至於它的第三排座椅,在看來更多的是應急使用。進入第三排仍然會有些困難,對於家裡的一些上了年紀的家人來說,還是安安分分坐在第二排吧,較高的離地間隙也是一個硬傷。因此7座的柯迪亞克更多是讓消費者有更多的選擇,5座的車型仍然廠家宣傳的主力車型。

    這是一台年輕人的SUV

    聊完最基礎的外觀、內飾與空間,剩下來的肯定就是好好試駕一番這台身材不少的SUV了。它的尺寸比目前剛上市的進口途觀還要大點,這樣的龐大的身軀,看到需要比較強勁的動力總成了,因此那款1.4T的發動機不會搭載在柯迪亞克身上。

    雖然歐洲是柴油車的天下,但為了更好與國內市場相一致,捨棄了試駕柴油版的柯迪亞克,選擇了一台搭載了2.0T發動機,可是號稱7.5秒能把柯迪亞克從0加速到100Km/h的車型。至於1.8T車型,想留着到時國內上市之後再來試駕。

    只要你開過斯柯達,那麼柯迪亞克是相當的容易上手。相比其他斯柯達車型,它有着更高的坐姿與更出色的視野,當然它的調校與其他斯柯達的車型還是有所區別的,那就是整體會更硬朗一些,很貼合它的名字與造型。

    在試駕的過程中,這台2.0T的發動機動力輸出非常直接,與其匹配的DQ500平順性做得相當出色,只是一路試駕的途中基本沒有體驗頓挫的酸爽感,換擋的非常积極聰明。如今唯一的念想就是希望國產之後仍然是這台出色的變速箱了。硬朗的懸挂調校,讓人在行駛當中非常踏實。雖然在試駕過程中路面不算很好,但柯迪亞克在靜音水平做得比較出色,相比途觀真的進步很大。

    試駕的這台車型還是四驅版本,車尾的4×4出賣了它的身份。它搭載的這台四驅系統與Tiguan相差不大,是一台適時四驅系統,通過多片離合器式限滑差速器來分配動力,但主要還是以前驅為主,對於操控有一定的提升,千萬不要以為能進行極限越野。

    合理的定價,將會是斯柯達的雄起之作

    從最近這幾年斯柯達的發展來說,已經有了很大的進步了;在明銳與晶銳身上可以逐漸看到全新的設計元素,以前比較老氣造型已經被丟進博物館了。再到最新的速派,採用MQB平台生產的中級車,雖然銷量仍然比不上帕薩特,但已經上了不止一個台階了。那麼未來的成績要想更上一層樓的話,就肯定需要一個非常切合年輕人的定價。

    柯迪亞克擁有着出眾的外觀顏值,非常實用的空間體驗,這些優勢已經吸引了許多消費者的關注,但是如果真的要賣到我們手中,恐怕差的只是一個合適的價格了。這個從它亮相以來不斷的有網友跟說,只要它性價比不錯,首選SUV一定是它了。既然這樣,就來猜測一下,假如定一個比較低的起步價的話,例如18萬的起步價格、同時爭取上市的時間比國產途觀更早,相信一定有很多年輕人會把它收入囊中的。如今消費者已經出好題目了,就看斯柯達會不會給個令人滿意的答案了。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※回頭車貨運收費標準

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

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

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

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

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

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

  • Spring AOP學習筆記02:如何開啟AOP

    Spring AOP學習筆記02:如何開啟AOP

      上文簡要總結了一些AOP的基本概念,並在此基礎上敘述了Spring AOP的基本原理,並且輔以一個簡單例子幫助理解。從本文開始,我們要開始深入到源碼層面來一探Spring AOP魔法的原理了。

      要使用Spring AOP,第一步是要將這一功能開啟,一般有兩種方式:

    • 通過xml配置文件的方式;
    • 通過註解的方式;

     

    1. 配置文件開啟AOP功能

      我們先來看一下配置文件的方式,這個上文也提到過,在xml文件中加上對應的標籤,而且別忘了加上對應的名稱空間(即下面的xmlns:aop。。。):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xmlns:aop = "http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
         
         <aop:aspectj-autoproxy/>
    
    </beans>

      這裡是通過標籤<aop:aspectj-autoproxy/>來完成開啟AOP功能,這是一個自定義標籤,需要自定義其解析,而這些spring都已經實現好了,前面專門寫過一篇文章講述spring是如何解析自定義xml標籤的,我們這裏大致回顧一下解析流程:

    • 定義一個XML文件來描述你的自定義標籤元素;
    • 創建一個Handler,擴展自NamespaceHandlerSupport,用於註冊下面的parser;
    • 創建若干個BeanDefinitionParser的實現,用來解析XML文件中的定義;
    • 將上述文件註冊到Spring中,這裏其實是做一下配置;

      我們就不照着這個步驟來了,我們直接參考spring對這個自定義標籤的解析過程,上面的4個步驟只是作為參考,在整個解析過程中都會涉及到。

      前面講解析自定義xml標籤時候提到過,解析的流程大致如下:

    • 首先會去獲取自定義標籤對應的名稱空間;
    • 然後根據名稱空間找到對應的NamespaceHandler;
    • 調用自定義的NamespaceHandler進行解析;

    1.1 獲取名稱空間

      這裏<aop:aspectj-autoproxy/>對應的名稱空間是什麼呢?在上面的開啟aop的配置文件裏面名稱空間那裡給出了一些線索,其實就是下面這個:

    http://www.springframework.org/schema/aop

      至於名稱空間的獲取,也無甚好說的,其實就是直接調用org.w3c.dom.Node提供的相應方法來完成名稱空間的提取。

    1.2 獲取handler

      然後又是如何根據名稱空間找到對應的NamespaceHandler呢?之前也說到過,在找對應的NamespaceHandler時會去META-INF/spring.handlers這個目錄下加載資源文件,我們來找一下spring.handlers這個文件看看(需要去spring-aop對應的jar報下找):

    http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

      看到沒,這裡是以key-value的形式維護着名稱空間和對應handler的關係的,所以對應的handler就是這個AopNamespaceHandler。spring根據名稱空間找到這個handler之後,會通過反射的方式將這個類加載,並緩存起來。

    1.3 解析標籤

      上面的handler只有一個自定義的方法:

    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

      這是一個初始化方法,在加載的時候會執行,主要作用就是註冊一些解析器,這裏我們主要關注AspectJAutoProxyBeanDefinitionParser,這就是我們要找的,它的作用就是解析<aop:aspectj-autoproxy/>標籤的。主要流程就是,spring會調用上一步拿到的AopNamespaceHandler的parse()方法,在這個方法裏面,會將解析的工作委託給AspectJAutoProxyBeanDefinitionParser來完成具體解析工作,我們就來看一下具體幹了啥吧。

      開始解析的工作從這裏開始:

    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

      此時我們拿到的handler其實是我們自定義的AopNamespaceHandler了,但是它並沒有實現parse()方法,所以這裏這個應該是調用的父類(NamespaceHandlerSupport)中的parse()方法:

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        // 尋找解析器並進行解析操作
        return findParserForElement(element, parserContext).parse(element, parserContext);
    }
    
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        // 獲取元素名稱,也就是<aop:aspectj-autoproxy/>中的aspectj-autoproxy
        String localName = parserContext.getDelegate().getLocalName(element);
        // 根據aspectj-autoproxy找到對應的解析器,也就是在registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        // 註冊的解析器
        BeanDefinitionParser parser = this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        }
        return parser;
    }

      首先是尋找元素對應的解析器,然後調用其parse()方法。結合我們前面的示例,其實就是首先獲取在AopNamespaceHandler類中的init()方法中註冊對應的AspectJAutoProxyBeanDefinitionParser實例,並調用其parse()方法進行進一步解析:

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }
    
    // 下面的代碼在AopConfigUtils中
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
    
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
    
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }
    
    private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

      上面這一堆代碼最核心的部分就在後兩個方法中,就是完成了對AnnotationAwareAspectJAutoProxyCreator類的註冊,到這裏對自定義標籤<aop:aspectj-autoproxy/>的解析也就完成了,可以看到其最核心的部分就是完成了對AnnotationAwareAspectJAutoProxyCreator類的註冊,那為什麼註冊了這個類就開啟了aop功能呢?這裏先賣個關子,後面詳細說。

      這裏再回過頭來看一下上面說到的spring對自定義標籤解析的4個步驟,其實第一步的schema對應的是在org.springframework.aop.config路徑下的spring-aop-3.0.xsd文件,其映射關係是維護在META-INF/spring.schemas文件中的,而spring-aop-3.0.xsd的主要作用就是描述自定義標籤。

      當通過META-INF/spring.handlers找到對應的AopNamespaceHandler,並通過在其加載后執行init()方法過程中完成了AspectJAutoProxyBeanDefinitionParser的註冊,有這個parser再來完成對自定義標籤的解析工作,這對應上面4個步驟中的第二步和第三部。至於第四步的配置工作,無非就是將spring.schemas和spring.handlers這兩個配置文件放在META-INF/目錄下罷了。

      關於這部分解析過程,寫得不是非常詳細,如果有不明白,可以參考之前一篇文章,講spring是如何解析自定義xml標籤。

     

    2. 註解方式開啟aop

      另一種開啟spring aop的方式是通過註解的方式,使用的註解是@EnableAspectJAutoProxy,可以通過配置類的方式完成註冊:

    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
    
    }

       也可以在啟動類上直接加上這個註解,這在springboot中比較常見,其實質也是上面的方式。通過這種方式配置之後,就開啟了aop功能,那具體又是如何實現的呢?我們看一下這個註解:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
        /**
         * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
         * to standard Java interface-based proxies. The default is {@code false}.
         */
        boolean proxyTargetClass() default false;
    
        /**
         * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
         * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
         * Off by default, i.e. no guarantees that {@code AopContext} access will work.
         * @since 4.3.1
         */
        boolean exposeProxy() default false;
    
    }

      這裏我們的關注點是其通過@Import(AspectJAutoProxyRegistrar.class)引入了AspectJAutoProxyRegistrar,那這又是什麼?

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
        /**
         * Register, escalate, and configure the AspectJ auto proxy creator based on the value
         * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
         * {@code @Configuration} class.
         */
        @Override
        public void registerBeanDefinitions(
                AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    
            AnnotationAttributes enableAspectJAutoProxy =
                    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    
    }

      看到這裏,是不是有點眼熟了呢?是的,其實它也是和上面說的xml配置使用的方式一樣,通過AopConfigUtils來完成AnnotationAwareAspectJAutoProxyCreator類的註冊。是不是比xml配置文件的方式方便許多呢。

     

    4. 開啟aop的魔法

      通過前面的學習我們了解了可以通過Spring自定義配置完成對AnnotationAwareAspectJAutoProxyCreator類型的自動註冊,而這個類到底是做了什麼工作來實現AOP的操作呢?這裏還是先來看一下AnnotationAwareAspectJAutoProxyCreator的類層次結構:

      這裡有一個很重要的點,就是AnnotationAwareAspectJAutoProxyCreator實現了BeanPostProcessor接口。在IOC部分的文章中有詳細說過,Spring在加載Bean的過程中會在實例化bean前後調用BeanPostProcessor的相關方法(相關邏輯是在initializeBean方法中,調用postProcessBeforeInitialization、postProcessAfterInitialization方法),而AOP的魔法就是從這裏開始的。

      每次看到這裏,我內心對spring的軟件架構設計都是湧現出無比的佩服,通過後處理器的方式來做擴展,對原有模塊是沒有任何改動,也不會產生耦合,spring親自踐行着對修改關閉,對擴展開放的原則。

     

    3. 總結

       本文我們學習了spring是如何開啟aop功能的,無論是通過xml配置文件方式,還是通過Java config這種註解的方式,其最終都是完成了將AnnotationAwareAspectJAutoProxyCreator這個類註冊到spring容器當中,那這個類又有什麼魔法,可以達到將其註冊到容器即達到開啟aop的功效,其實其繼承自BeanPostProcessor接口,通過後處理器的方式擴展出了開啟spring aop的功能。

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

    【其他文章推薦】

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

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

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

    ※回頭車貨運收費標準

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

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

  • 印度猴群闖醫學院「毆打研究員」 下秒洗劫待驗的武肺檢體

    印度猴群闖醫學院「毆打研究員」 下秒洗劫待驗的武肺檢體

    摘錄自2020年05月30日三立新聞網印度報導

    武漢肺炎(COVID-19)仍持續在印度延燒,然29日卻發生一起「搶劫事件」,一群猴子突闖入北方省勒克瑙(Lucknow)一處醫學院、出手攻擊醫事人員,並將多個待檢驗新冠病毒的血液檢體劫走;消息一出,附近居民紛表擔憂,害怕病毒會因檢體洩漏而進一步擴散。

    醫學院領導人賈格(S. K. Garg)指出,現在沒有證據顯示人會傳染病毒給猴子,但不知道若猴子接觸有病毒的血液之後,是否會遭受感染。有關單位也表示,目前還沒掌握到猴子是否有把血液灑出來,但附近居民得知消息後,都很擔心若猴子將檢體帶到住宅區,恐會造成病毒擴散。

    猴子闖入人類居住區、造成騷亂甚至攻擊人類的事件近來在印度頻傳,環保人士對此表示,主要原因是猴子的棲息地遭破壞,而牠們為了尋找食物才會闖入人類的居住空間。

    ※ 本文與 行政院農業委員會 林務局   合作刊登

    國際新聞
    印度
    武漢肺炎
    猴子
    公共衛生
    處變不驚──與野生動物相遇
    人與動物衝突事件簿

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

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

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

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

  • 躲過大火又來疫情 無尾熊面臨斷炊危機

    摘錄自2020年05月31日TVBS新聞網澳洲報導

    澳洲在去年年底,發生世紀森林大火,至少造成8,000隻無尾熊喪命,沒想到躲過大火,現在澳洲無尾熊卻因為疫情,可能面臨斷炊危機。以澳洲雪梨郊區的野生動物園來說,因為七成以上收入是靠外國觀光客,現在因為疫情根本沒有收入,現在只能期待澳洲政府紓困,才能讓園內50隻無尾熊的飼料費有著落。

    費瑟代爾野生動物園公關:「就像大家知道的,夏天的時候,森林大火燒到動物園附近,剛想說逃過一劫,這下沒問題了,結果又遇到新冠病毒疫情。」

    這家野生動物園的無尾熊,儘管躲過了大火奪命,如今卻可能因為疫情,面臨斷炊危機,原來每頭無尾熊,每年的飼料費是1萬9000澳幣,現在沒了觀光客,業者只能期待澳洲政府救濟。

    生態保育
    物種保育
    生物多樣性
    國際新聞
    澳洲
    無尾熊
    動物與大環境變遷

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

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

  • 歐企推環保轉型 呼應下一代歐盟計劃

    摘錄自2020年05月31日台灣醒報歐洲報導

    面對疫情歐洲企業提倡環保轉型,配合歐盟永續發展新計劃。歐洲最大的時裝網購平台Zalando日前宣佈,將要求其合作品牌在2023年前達到永續發展的環保目標。如果不能符合規定將會強制下架該公司所有商品。

    目前約有2000個時尚品牌經由Zalando的平台銷售,包括Nike、Gucci、Ted Baker等。各界認為,此舉不僅提升環保意識,也能讓時尚圈有更明確的未來目標。

    據《科學人》報導,歐盟日前公佈一項金額高達7500億歐元,名為「下一代歐盟」的經濟復甦計劃,內容特別強調阻止氣候變遷的重要性。歐盟執委會主席馮德萊恩向媒體表示:「我們必須確保企業在疫情期間進行產業轉型時,也要符合環保的大方向。」

    環境哲學
    生活環境
    綠色消費
    全球變遷
    氣候變遷
    循環經濟
    國際新聞
    歐洲
    環境正義

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

    【其他文章推薦】

    ※回頭車貨運收費標準

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

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

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

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

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

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

  • 能兼顧到家用還開着爽 這幾款車只需要10萬起!

    能兼顧到家用還開着爽 這幾款車只需要10萬起!

    6L、1。8L以及2。0L三款發動機,傳動系統配備5擋手動以及大家最熟悉的CVT變速箱。CVT變速箱動力輸出十分平順,也非常適合在日常城市道路駕馭。硬朗的底盤以及韌性不錯的懸挂,加上ASC車身穩定系統,能給駕駛者足夠的信心。一汽-大眾-速騰指導價:13。

    前言

    對於80後部分朋友已成家立室,上有老下有小,買車必須要考慮到家用,而心中存在着一份激情,開着也能讓自己爽。所以對於這部分朋友來說,選擇操控好,還能兼顧到家用,也是他們首要的目標。

    長安馬自達-馬自達3 Axela昂克賽拉

    指導價:11.49-15.99萬

    昂克賽拉沿用了馬自達最新“魂動”家族化設計, 前臉造型如同獵豹,視覺感受更加富有攻擊性以及活力的風格,尾部設計較為簡潔,整體設計風格時尚年輕。

    內飾正是昂克賽拉的創新所在,雖然簡潔,但整體內飾氛圍更具運動感,車廂做工用料方面,比較厚道!

    昂克賽拉更有兩個版本可選,三廂以及兩廂車型,空間方面,能夠滿足日常出行,三廂版/兩廂版行李箱的容積為419L、350L,長途駕駛三廂版實用性更高。

    昂克賽拉搭載了1.5L以及2.0L兩款自然吸氣發動機,也是馬自達最新“創馳藍天”發動機,我相信大家也非常了解這款發動機,其優點就是能擁有相對低的油耗還能兼顧到充沛的動力輸出,傳動系統配備了6擋手動、6擋手自一體變速箱。底盤的質感高級,從容紮實,懸挂的調校偏運動,能有很好的操控性還能兼顧舒適性。

    東南汽車-翼神

    指導價:9.58-13.98萬

    翼神外觀採用了三菱經典的鯊魚嘴仿生學造型設計,黑色的大嘴結合成一體,尾部設計較為驚艷,有層次感。翼神整體的設計更加霸氣有力!

    翼神內飾主要以黑色為主,中控設計布局簡潔以及在物理按鍵上很到位,整體車廂氛圍很有戰鬥感。

    翼神車身長寬高為4570*1760*1490mm,軸距為2635mm,空間表現,寬敞也能輕鬆翹個二郎腿,座椅填充物軟硬適中,包裹性也很足。

    動力方面,翼神搭載了1.6L、1.8L以及2.0L三款發動機,傳動系統配備5擋手動以及大家最熟悉的CVT變速箱。CVT變速箱動力輸出十分平順,也非常適合在日常城市道路駕馭。硬朗的底盤以及韌性不錯的懸挂,加上ASC車身穩定系統,能給駕駛者足夠的信心。

    一汽-大眾-速騰

    指導價:13.18-21.88萬

    速騰外觀設計依然還是很大眾,家族式設計並沒有太多的亮點,圓滑的車身造型以及流暢動感線條,速騰依然不失時尚感。

    內飾設計依然還是大眾風格,雖然是大眾風格,但其整體設計風格很耐看,甚至會有那麼一絲高級感,做工用料上採用了些許硬質材料,視覺效果並不差,依然簡潔。

    速騰車身長寬高為4655*1780*1453mm,軸距為2651mm,空間表現,可以說是速騰最引以為傲的地方,蹺二郎腿毫無壓力。

    動力方面,速騰搭載了1.2T、1.4T.1.6T以及2.0T四款發動機,可供消費者選擇較多,傳動系統方面配備5擋手動、6擋手自一體、7擋雙離合變速箱,購買雙離合車型的消費者也無需擔心其的耐用性以及平順性,大眾也做了特別多的優化。底盤依然是大眾一貫的風格調校,紮實,速騰懸挂調校也偏向舒適。

    全文總結

    整體來說,這三款車都有運動基因的底子,能兼顧到家用以及在操控性方面也不錯,產品力也很強!加上現在優惠幅度也比較大,也值得入手。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

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

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

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

  • 別再重複造輪子了,幾個值得應用到項目中的 Java 開源庫送給你

    別再重複造輪子了,幾個值得應用到項目中的 Java 開源庫送給你

    我是風箏,公眾號「古時的風箏」。文章會收錄在 JavaNewBee 中,更有 Java 後端知識圖譜,從小白到大牛要走的路都在裏面。公眾號回復『666』獲取高清大圖。

    風箏我作為一個野路子開發者,直到遇見下面的這幾個工具庫,才知道之前重複造了不少輪子,而且輪子還不一定有人家的圓。相信跟我一樣,沒事兒造輪子的人還不在少數,有些人就是對造輪子感興趣,這個咱也無話可說,但是,比如我,我是造輪子之前不知道這世上已經有好用的輪子了,害,無知限制了我的想象力。

    比如我們在拿到一個 List 集合之後,要對這個集合進行判空操作,以前我一直是這樣寫的:

    List<String> list = getList();
    if (list != null && list.size() > 0) {
        //do something
    }
    

    雖然這樣也沒什麼問題,但是,我懶啊,每次敲這麼多代碼,也挺累啊。有同學說,那你包裝成一個方法不就行了,每次調用個方法就 OK 啦。這不,同學,你就在造輪子了,已經有人幫你寫好了這樣類似的一系列方法了。

    來讓我們認識認識這些輪子吧。

    Java 8 Stream

    Stream 不算是工具庫,但是通過 stream 提供的一系列方法,可以實現集合的過濾、分組、集合轉換等諸多操作。

    例如下面的方法,實現列表元素根據某個字段去重的功能。

    List<User> userList = new ArrayList();
    //添加元素
    userList =  userList.stream().filter(distinctByKey(user->user.getUserId())).collect(Collectors.toList());
    
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
          Map<Object,Boolean> seen = new ConcurrentHashMap<>();
          return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
    

    apache commons

    官方地址:http://commons.apache.org/

    這不是一個庫,而是一系列的工具庫。

    由於包含的庫過多,我就不一一列舉了,可以到官網一探。有集合處理的、數學計算的、IO 操作的等等,其中最常用的莫過於 Apache Commons Lang 和 Apache Commons Collections 這兩個。

    Apache Commons Lang 包括一系列工具類,有字符串相關的、時間處理的、反射的、併發包的等等,Apache Commons Collections 專門用作集合處理。

    下面舉幾個例子說明一下,更詳細的內容可以到官網查看文檔。

    字符串判空操作

    String s = "";
    Boolean isEmpty = StringUtils.isEmpty(s);
    

    獲取類的全名稱

    ClassUtils.getName(ClassUtils.class);
    

    判斷集合是否為空

    Boolean isNotEmpty = CollectionUtils.isNotEmpty(list);
    

    反射獲取某個類的所有 Field

    Field[] fields = FieldUtils.getAllFields(User.class);
    

    Google Guava

    官方地址:https://github.com/google/guava

    和 Apache Commons 有點兒類似,它也是包含了一系列的比如字符串、集合、反射、數學計算等的操作封裝,還可以用作 JVM 緩存。

    舉幾個例子說明:

    New 各種對象

    List<String> list = Lists.newArrayList();
    Set<String> set = Sets.newHashSet();
    Map<String,Object> map = Maps.newConcurrentMap();
    
    // 不可變集合
    ImmutableList<String> immutableList = ImmutableList.of("1", "2", "3");
    

    列錶轉符號分隔的字符串

    List<String> list = new ArrayList<String>();
    list.add("1");
    list.add("2");
    list.add("3");
    String result = Joiner.on("-").join(list);
    
    > 1-2-3
    

    求交集、並集、差集等

    例如下面代碼求 set1 和 set2 的交集

    Set<Integer> set1 = Sets.newHashSet(1, 2, 3, 4, 5, 6);
    Set<Integer> set2 = Sets.newHashSet(1,2,3,4);
           
    Sets.SetView<Integer> intersection = Sets.intersection(set1, set2);
    

    Joda Time

    官方地址:https://www.joda.org/joda-time/

    一個日期、時間處理的工具庫。如果你不是經常做日期處理,那差不多每次需要的時候都需要查詢相關的 API,而有了工具類就不一樣了,只要一個 “.”,你想要的方法就出現了,而 Joda Time 就是一款好用的工具庫。

    比如下面這個方法,計算到新年還有多少天。

    public Days daysToNewYear(LocalDate fromDate) {
      LocalDate newYear = fromDate.plusYears(1).withDayOfYear(1);
      return Days.daysBetween(fromDate, newYear);
    }
    

    OkHttp3

    官方地址:https://square.github.io/okhttp/

    一個 HTTP 客戶端,使用簡單,性能良好,是時候放棄 HttpClient 了。

    一個 get 請求:

    OkHttpClient client = new OkHttpClient();
    
    String run(String url) throws IOException {
      Request request = new Request.Builder()
          .url(url)
          .build();
    
      try (Response response = client.newCall(request).execute()) {
        return response.body().string();
      }
    }
    

    一個 post 請求:

    public static final MediaType JSON
        = MediaType.get("application/json; charset=utf-8");
    
    OkHttpClient client = new OkHttpClient();
    
    String post(String url, String json) throws IOException {
      RequestBody body = RequestBody.create(json, JSON);
      Request request = new Request.Builder()
          .url(url)
          .post(body)
          .build();
      try (Response response = client.newCall(request).execute()) {
        return response.body().string();
      }
    }
    

    Json 系列

    Jackson

    Spring 默認的 Json 序列化工具,其實已經足夠用了。

    Gson

    Google 出品,功能齊全。

    FastJson

    阿里出品,算法良好,性能最優。

    EasyExcel

    官方地址:https://www.yuque.com/easyexcel/doc/easyexcel

    阿里開源的 Excel 操作工具庫,可以看做是 Apache POI 的增強封裝版、優化版。

    如果你的數據量很大,那用 EasyExcel 可以節省內存,提升效率,並且沒有併發風險。

    如果你的 Excel 足夠複雜,那用 EasyExcel 會比你直接用 POI 少些很多代碼。

    比如我實現了下面這個 Excel 動態導出,包括動態表頭、動態合併單元格的功能,只用了很少的代碼,如果是使用 POI 的話,那可能代碼量增加不止一倍啊。

    TinyPinyin

    官方地址:https://github.com/promeG/TinyPinyin

    中文轉拼音,把你輸入的中文轉換成拼音。比如搜索功能要實現這樣的功能,輸入 “fengzheng” 搜索,會匹配到 “風箏”這個詞語,這就需要中文轉拼音了。

    有的同學說了,這不是拼音轉英文嗎?當然不是在輸入“fengzheng”的時候轉換了,而是在包含“風箏”的這條記錄中有一個拼音的額外字段,這樣搜索的時候直接匹配拼音那個字段。

    chinese_name pinyin_name
    風箏 fengzheng

    反射工具庫 – jOOR

    官方地址:https://github.com/jOOQ/jOOR

    它是 JDK 反射包的友好封裝,通過一系列簡單友好的鏈式操作實現反射調用。比如下面這個例子

    public interface StringProxy {
      String substring(int beginIndex);
    }
    
    String substring = on("java.lang.String")
                        .create("Hello World")
                        .as(StringProxy.class)
                        .substring(6);    
    

    簡單的代碼實現 JDK 動態代理,節省了不少代碼。

    MyBatis-Plus

    官方地址:https://mp.baomidou.com/

    只要你的項目中有數據庫訪問,那你肯定用過或者至少聽說過 MyBatis ,但是如果你只用 MyBatis 需要針對每個DAO方法寫對應的 SQL Statement(也就是 mapper.xml 中的代碼塊),當然有一些自動生成的工具,MyBatis 就有它提供的 MyBatis Generator,比如我也稍做加工,做過一個web 版的 MyBatis Generator,開發效率是提高了,但是每個 mapper.xml 文件的代碼量很大,於是 MyBatis-Plus 就要出場了。

    官網上對他的定義如下:

    1. 只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑。
    2. 只需簡單配置,即可快速進行 CRUD 操作,從而節省大量時間。
    3. 熱加載、代碼生成、分頁、性能分析等功能一應俱全。

    最後,在配上 MybatisX IDEA 插件,也是可以了。

    vjtools

    官方地址:https://github.com/vipshop/vjtools

    這是唯品會的開源工具包,這裏主要介紹其中的 vjkit 模塊,是關於文本,集合,併發等基礎功能的核心類庫。這個庫是我很早之前搜索日期操作的時候偶然發現的,我發現裏面日期處理的 API 相當全面而且很實用,還在我的項目中用過一段時間。

    最後

    好用的工具庫可以提高我們的開發效率,而且也是我們學習源碼的好去處,和其他的開源框架(比如 Spring、Dubbo)一樣,看看優秀的代碼是如何實現的。

    如果你還知道什麼好用、強大的開源工具包,歡迎在留言區分享,好東西不能獨享,讓更多的人受益。

    各位大佬,給個推薦,讓我奮發圖強

    我是風箏,公眾號「古時的風箏」。一個兼具深度與廣度的程序員鼓勵師,一個本打算寫詩卻寫起了代碼的田園碼農!你可選擇現在就關注我,或者看看歷史文章再關注也不遲。

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

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

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

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