<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    from:http://mingxinglai.com/cn/2015/12/material-of-mysql/

    我這里推薦幾本MySQL的好書,應(yīng)該能夠有效避免學(xué)習(xí)MySQL的彎路,并且達(dá)到一個不錯的水平。 我這里推薦的書或材料分為兩個部分,分別是MySQL的使用和MySQL的源碼學(xué)習(xí)。在介紹的過程中,我會穿插簡單的評語或感想。

    1.MySQL的使用

    1.1 MySQL技術(shù)內(nèi)幕:InnoDB存儲引擎

    學(xué)習(xí)MySQL的使用,首推姜承堯的《MySQL技術(shù)內(nèi)幕:InnoDB存儲引擎》,當(dāng)然不是因?yàn)榻猻ir是我的經(jīng)理才推薦這本書。這本書確實(shí)做到了由漸入深、深入淺出,是中國人寫的最贊的MySQL技術(shù)書籍,符合國人的思維方式和閱讀習(xí)慣,而且,這本書簡直就是面試寶典,對于近期有求職MySQL相關(guān)崗位的朋友,可以認(rèn)真閱讀,對找工作有很大的幫助。當(dāng)然,也有人說這本書入門難度較大,這個就自己取舍了,個人建議就以這本書入門即可,有不懂的地方可以求助官方手冊和google。

    MySQL技術(shù)內(nèi)幕

    1.2 MySQL的官方手冊

    我剛開始學(xué)習(xí)MySQL的時候誤區(qū)就是,沒有好好閱讀MySQL的官方手冊。例如,我剛開始很難理解InnoDB的鎖,尤其是各個情況下如何加鎖,這個問題在我?guī)煹苓M(jìn)入百度做DBA時,也困擾了他一陣子,我們兩還討論來討論去,其實(shí),MySQL官方手冊已經(jīng)寫得清清楚楚,什么樣的SQL語句加什么樣的鎖,當(dāng)然,MySQL的官方手冊非常龐大,一時半會很難看完,建議先看InnoDB相關(guān)的部分。

    http://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html

    1.3 MySQL排錯指南

    MySQL排錯指南》是2015年夏天引入中國的書籍,這本書可以說是DBA速成指南,介紹的內(nèi)容其實(shí)比較簡單,但是也非常實(shí)用,對于DBA這個講究經(jīng)驗(yàn)的工種,這本書就是傳授經(jīng)驗(yàn)的,可能對有較多工作經(jīng)驗(yàn)的DBA來說,這本書基本沒有什么用,但是,對于剛?cè)肼殘龅男氯?,或?qū)W校里的學(xué)生,這本書會有較大的幫助,非常推薦。

    MySQL排錯指南

    1.4 高性能MySQL

    高性能MySQL》是MySQL領(lǐng)域的經(jīng)典之作,擁有廣泛的影響力,學(xué)習(xí)MySQL的朋友都應(yīng)該有所耳聞,所以我就不作過多介紹,唯一的建議就是仔細(xì)看、認(rèn)真看、多看幾遍,我每次看都會有不小的收獲。這就是一本雖然書很厚,但是需要一頁一頁、一行一行都認(rèn)真看的書。

    高性能MySQL

    1.5 數(shù)據(jù)庫索引設(shè)計與優(yōu)化

    如果認(rèn)真學(xué)習(xí)完前面幾本書,基本上都已經(jīng)對MySQL掌握得不錯了,但是,如果不了解如何設(shè)計一個好的索引,仍然不能成為牛逼的DBA,牛逼的DBA和不牛逼的DBA,一半就是看對索引的掌握情況,《數(shù)據(jù)庫索引設(shè)計與優(yōu)化》就是從普通DBA走向牛逼DBA的捷徑,這本書在淘寶內(nèi)部非常推崇,但是在中國名氣卻不是很大,很多人不了解。這本書也是今年夏天剛有中文版本的,非常值得入手以后跟著練習(xí),雖然知道的人不多,豆瓣上也幾乎沒有什么評價,但是,強(qiáng)烈推薦、吐血推薦!

    數(shù)據(jù)庫索引設(shè)計與優(yōu)化

    1.6 Effective MySQL系列

    Effective MySQL系列》是指:

    • Effective MySQL Replication Techniques in Depth
    • Effective MySQL之SQL語句最優(yōu)化
    • Effective MySQL之備份與恢復(fù)

    effective

    這一系列并不如前面推薦的好,其中,我只看了前兩本,這幾本書只能算是小冊子,如果有時間可以看看,對某一個”模塊”進(jìn)入深入了解。

    2.MySQL的源碼

    關(guān)于MySQL源碼的書非常少,還好現(xiàn)在市面上有兩本不錯的書,而且剛好一本講server層,一本講innodb存儲引擎層,對于學(xué)習(xí)MySQL源碼會很有幫助,至少能夠更加快速地了解MySQL的原理和宏觀結(jié)構(gòu),然后再深入細(xì)節(jié)。此外,還有一些博客或PPT將得也很不錯,這里推薦最好的幾份材料。

    2.1 InnoDB - A journey to the core

    InnoDB - A journey to the core》 是MySQL大牛Jeremy Cole寫的PPT,介紹InnoDB的存儲模塊,即表空間、區(qū)、段、頁的格式、記錄的格式、槽等等。是學(xué)習(xí)Innodb存儲的最好的材料。感謝Jeremy Cole!

    2.2 深入MySQL源碼

    登博的分享《深入MySQL源碼》,相信很多想了解MySQL源碼的朋友已經(jīng)知道這份PPT,就不過多介紹,不過,要多說一句,登博的參考資料里列出的幾個博客,都要關(guān)注一下,干貨滿滿,是學(xué)習(xí)MySQL必須關(guān)注的博客。

    2.3 深入理解MySQL核心技術(shù)

    深入理解MySQL核心技術(shù)》是第一本關(guān)于MySQL源碼的書,著重介紹了MySQL的Server層,重點(diǎn)介紹了宏觀架構(gòu),對于剛開始學(xué)習(xí)MySQL源碼的人,相信會有很大的幫助,我在學(xué)習(xí)MySQL源碼的過程中,反復(fù)的翻閱了幾遍,這本書剛開始看的時候會很痛苦,但是,對于研究MySQL源碼,非常有幫助,就看你是否需要,如果沒有研究MySQL源碼的決心,這本書應(yīng)該會被唾棄。

    深入理解MySQL核心技術(shù)

    2.4 MySQL內(nèi)核:InnoDB存儲引擎

    我們組的同事寫的《MySQL內(nèi)核:InnoDB存儲引擎》,可能宇宙范圍內(nèi)這本書就數(shù)我學(xué)得最認(rèn)真了,雖然書中有很多編輯錯誤,但是,平心而論,還是寫得非常好的,相對于《深入理解MySQL核心技術(shù)》,可讀性更強(qiáng)一些,建議研究Innodb存儲引擎的朋友,可以了解一下,先對Innodb有一個宏觀的概念,對大致原理有一個整體的了解,然后再深入細(xì)節(jié),肯定會比自己從頭開始研究會快很多,這本書可以幫助你事半功倍。

    MySQL內(nèi)核

    2.5 MySQL Internals Manual

    MySQL Internals Manual》相對于MySQL Manual來說,寫的太粗糙,誰讓人家是官方文檔呢,研究MySQL源碼的時候可以簡單地參考一下,但是,還是不要指望文檔能夠回答你的問題,還需要看代碼才行。

    http://dev.mysql.com/doc/internals/en/

    2.6 MariaDB原理與實(shí)現(xiàn)

    評論里提到的《MariaDB原理與實(shí)現(xiàn)》我也買了一本,還不錯,MariaDB講的并不多,重點(diǎn)講了Group Commit、線程池和復(fù)制的實(shí)現(xiàn),都是MySQL Server層的知識,對MySQL Server層感興趣的可以參考一下。

    MariaDB

    3. 后記

    希望這里推薦的材料對學(xué)習(xí)MySQL的同學(xué)、朋友有所幫助,也歡迎推薦靠譜的學(xué)習(xí)材料,大家共同進(jìn)步。

    posted @ 2018-12-03 15:54 小馬歌 閱讀(325) | 評論 (0)編輯 收藏
     
         摘要: from:https://yq.aliyun.com/articles/69520?utm_content=m_10360#6摘要: # 我的問題排查工具箱 ## 前言 平時的工作中經(jīng)常碰到很多疑難問題的處理,在解決問題的同時,有一些工具起到了相當(dāng)大的作用,在此書寫下來,一是作為筆記,可以讓自己后續(xù)忘記了可快速翻閱,二是分享,希望看到此文的同學(xué)們可以拿出自己日常覺得幫助很大的工具,大家一...  閱讀全文
    posted @ 2018-11-23 10:47 小馬歌 閱讀(279) | 評論 (0)編輯 收藏
     
         摘要: from:https://www.cnblogs.com/Anker/p/3271773.html1、前言  之前在看《unix環(huán)境高級編程》第八章進(jìn)程時候,提到孤兒進(jìn)程和僵尸進(jìn)程,一直對這兩個概念比較模糊。今天被人問到什么是孤兒進(jìn)程和僵尸進(jìn)程,會帶來什么問題,怎么解決,我只停留在概念上面,沒有深入,倍感慚愧。晚上回來google了一下,再次參考APUE,認(rèn)真總結(jié)一下,加深理解。2、基本概念  我...  閱讀全文
    posted @ 2018-09-03 19:53 小馬歌 閱讀(218) | 評論 (0)編輯 收藏
     
    from:http://blog.csdn.net/vfush/article/details/51086274

    最近做了個Web項(xiàng)目, 架構(gòu)上使用了 Nginx +tomcat 集群, 且全站HTTPS,用nginx 做負(fù)載,nginx和tomcat 使用內(nèi)網(wǎng)http通信,遇到http css,js靜態(tài)資源被瀏覽器攔截問題,網(wǎng)上搜索到的很多文章在描述 Nginx + Tomcat 啟用 HTTPS 支持的時候,都必須在 Nginx 和 Tomcat 兩邊同時配置 SSL 支持,今天做個總結(jié)。

    遇到問題

    1. nginx強(qiáng)制使用https訪問(http跳轉(zhuǎn)到https)
    2. http的js,css 等靜態(tài)資源被瀏覽器攔截(http不被信任)

    最后的解決方案

    首先解決第一個問題全站https 
    參考 
    三種方式,跟大家共享一下

    nginx的rewrite方法

    server {   listen  192.168.1.111:80;   server_name test.com;   rewrite ^(.*)$  https://$host$1 permanent; }   

    nginx的497狀態(tài)碼,我選擇了這種方式

    server {       listen       192.168.1.11:443;  #ssl端口       listen       192.168.1.11:80;   #用戶習(xí)慣用http訪問,加上80,后面通過497狀態(tài)碼讓它自動跳到443端口       server_name  test.com;       #為一個server{......}開啟ssl支持       ssl                  on;       #指定PEM格式的證書文件        ssl_certificate      /etc/nginx/test.pem;        #指定PEM格式的私鑰文件       ssl_certificate_key  /etc/nginx/test.key;        #讓http請求重定向到https請求        error_page 497  https://$host$uri?$args;   }   

    index.html刷新網(wǎng)頁

    <html>   <meta http-equiv="refresh" content="0;url=https://test.com/">   </html>  

    當(dāng)http訪問到index.html時候自動跳轉(zhuǎn)到https


    接下來解決第二個問題 
    如果tomcat 和nginx 雙方?jīng)]有配置X-Forwarded-Proto tomcat就不能正確區(qū)分實(shí)際用戶是http 還是https,導(dǎo)致tomcat 里配置的靜態(tài)資源被認(rèn)為是http而被瀏覽器攔截,request.getScheme()總是 http,而不是實(shí)際的http或https

    分別配置一下 Nginx 和 Tomcat ,果然好了。 
    配置 Nginx 的轉(zhuǎn)發(fā)選項(xiàng):

     proxy_set_header       Host $host;       proxy_set_header  X-Real-IP  $remote_addr;       proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;       proxy_set_header X-Forwarded-Proto  $scheme;  
    • 1
    • 2
    • 3
    • 4

    配置Tomcat server.xml 的 Engine 模塊下配置一個 Valve:

    <Valve className="org.apache.catalina.valves.RemoteIpValve"   remoteIpHeader="X-Forwarded-For"   protocolHeader="X-Forwarded-Proto"   protocolHeaderHttpsValue="https"/>  
    • 1
    • 2
    • 3
    • 4

    非80端口配置 
    Nginx增加以下配置 
    proxy_set_header Host $host:$server_port; 非80端口 ,用80端口時 不需要$server_port 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header X-Forwarded-Proto $scheme; 

    Tomcat server.xml配置 
    <Engine name="Catalina" defaultHost="localhost"> 
    <Valve className="org.apache.catalina.valves.RemoteIpValve" 
    remoteIpHeader="X-Forwarded-For" 
    protocolHeader="X-Forwarded-Proto" 
    protocolHeaderHttpsValue="https" httpsServerPort="7001"/> 非80端口時,必須增加httpsServerPort配置,不然request.getServerPort()方法返回 443. 
    </Engine>

    關(guān)于 RemoteIpValve,可以閱讀下 doc

    http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html

    posted @ 2017-10-12 11:02 小馬歌 閱讀(404) | 評論 (0)編輯 收藏
     
    gerrit還是輕易不要嘗試引入,它的權(quán)限管理,真是復(fù)雜極了。對于小型團(tuán)隊(duì),初期這將是個噩夢,但是對于像OpenStack,安卓這種大型team,又是一把利器。
    下面嘗試測試了兩個用戶的簡單情況,很多配置都是系統(tǒng)默認(rèn),沒有進(jìn)行啥復(fù)雜配置,即使這樣也是錯誤百出,光一個commit就要折騰半天,而且還有些機(jī)制沒搞清楚。
    首先要做的準(zhǔn)備工作就是準(zhǔn)備兩個gerrit用戶,user1和user2,并且分別把user1和user2的ssh pub-key通過gerrit setting添加好。
    1. 首先user1創(chuàng)建一個叫HelloWord的project。
       如何創(chuàng)建project請參考前期博客或者官方文檔。
    2. user1在自己的工作環(huán)境中把HelloWord clone下來
    [user1@jenkins ~]$ git clone ssh://user1@gerrit.example.com:29418/HelloWorld.git
    Initialized empty Git repository in /home/user1/HelloWorld/.git/
    remote: Counting objects: 2, done
    remote: Finding sources: 100% (2/2)
    remote: Total 2 (delta 0), reused 0 (delta 0)
    Receiving objects: 100% (2/2), done.
    加入user1沒有添加ssh pubkey的話,這一步會出permission deny

    clone后,創(chuàng)建一個README文件并add,commit
    [user1@jenkins ~]$ cd HelloWorld
    [user1@jenkins HelloWorld]$ ls
    [user1@jenkins HelloWorld]$ touch README
    [penxiao@jenkins test]$ git add README 
    [penxiao@jenkins test]$ git commit -m add README
    這里注意一點(diǎn),在下面要push之前,一定要配置好git config的 username和email
    可以通過命令行或者直接編輯 ~/.gitconfig文件實(shí)現(xiàn),而且email一定要和gerrit里注冊的email一致,否者push也會出錯。
    [user1@jenkins HelloWorld]$ git push origin master
    Counting objects: 3, done.
    Writing objects: 100% (3/3), 213 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: refs: 1, done    
    To ssh://user1@gerrit.example.com:29418/HelloWorld.git
     * [new branch]      master -> master
    [user1@jenkins HelloWorld]$

    在gerrit的gitweb鏈接可以查看push的文件。
    3. user2加入
    [user2@jenkins ~]$ git clone ssh://user1@gerrit.example.com:29418/HelloWorld.git
    Initialized empty Git repository in /home/user2/HelloWorld/.git/
    remote: Counting objects: 3, done
    remote: Finding sources: 100% (3/3)
    remote: Total 3 (delta 0), reused 3 (delta 0)
    Receiving objects: 100% (3/3), done.
    [user2@jenkins ~]$ cd HelloWorld
    [user2@jenkins HelloWorld]$ ls
    README
    [user2@jenkins HelloWorld]$ 
    user2對README文件進(jìn)行修改,然后要commit,push
    ?。?!也同樣注意,user2的git config,username和email的配置,email要和gerrit setting里的一致。
    commit完以后可以看到
    [user2@jenkins HelloWorld]$ git log
    commit 7959fe47bc2d2f53539a1861aa6b0d71afe0a531
    Author: user2 <user2@gerrit.com>
    Date:   Thu Dec 12 00:24:53 2013 -0500
        edit README
    commit 98099fc0de3ba889b18cf36f9a5af267b3ddb501
    Author: user1 <user@gerrit.com>
    Date:   Thu Dec 12 00:15:08 2013 -0500
        add README
    [user2@jenkins HelloWorld]$
    現(xiàn)在user2要把這次的改變push到gerrit,可以么?
    不行的,可以看到
    [user2@jenkins HelloWorld]$ git push origin master
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 249 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Branch refs/heads/master:
    remote: You are not allowed to perform this operation.
    remote: To push into this reference you need 'Push' rights.
    remote: User: user2
    remote: Please read the documentation and contact an administrator
    remote: if you feel the configuration is incorrect
    remote: Processing changes: refs: 1, done    
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     ! [remote rejected] master -> master (prohibited by Gerrit)
    error: failed to push some refs to 'ssh://user2@gerrit.example.com:29418/HelloWorld.git'
    [user2@jenkins HelloWorld]$ 
    這就是gerrit的精髓所在了。原因是gerrit不允許直接將本地修改同步到遠(yuǎn)程倉庫。客戶機(jī)必須先push到遠(yuǎn)程倉庫的refs/for/*分支上,等待審核。這也是為什么我們需要使用gerrit的原因。gerrit本身就是個代碼審核工具。

    接下來更該push的地址:  
    [user2@jenkins HelloWorld]$git config remote.origin.push refs/heads/*:refs/for/*  
    此命令實(shí)際是更改的是本地倉庫test_project/.git/config文件。 
    再次push   
    [user2@jenkins HelloWorld]$git push origin  
    這次不要加master
    [user2@jenkins HelloWorld]$ git push origin
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 249 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: refs: 1, done    
    remote: ERROR: missing Change-Id in commit message footer
    remote: Suggestion for commit message:
    remote: edit README
    remote: 
    remote: Change-Id: I7959fe47bc2d2f53539a1861aa6b0d71afe0a531
    remote: 
    remote: Hint: To automatically insert Change-Id, install the hook:
    remote:   gitdir=$(git rev-parse --git-dir); scp -p -P 29418 user2@gerrit.example.com:hooks/commit-msg ${gitdir}/hooks/
    remote: 
    remote: 
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     ! [remote rejected] master -> refs/for/master (missing Change-Id in commit message footer)
    error: failed to push some refs to 'ssh://user2@gerrit.example.com:29418/HelloWorld.git'
    尼瑪,還是不行,說缺change-Id,為了能讓每次commit能自己insert 這個change-id,需要從gerrit server上下載一個腳本
    [user2@jenkins HelloWorld] scp -p 29418 user2@gerrit.example.com:hooks/commit-msg <local path to your git>/.git/hooks/
    然后重新commit
    [user2@jenkins HelloWorld]$ git commit --amend
    再次查看git log
    [user2@jenkins HelloWorld]$ git log
    commit f6b5919170875b5b4870fca2ab906c516c97006e
    Author: user2 <user2@gerrit.com>
    Date:   Thu Dec 12 00:24:53 2013 -0500
        edit by user2
        
        Change-Id: Ieac68bebefee7c6d4237fa5c058386bf7c4f66b7
    commit 98099fc0de3ba889b18cf36f9a5af267b3ddb501
    Author: user1 <user1@gerrit.com>
    Date:   Thu Dec 12 00:15:08 2013 -0500
        add README
    [user2@jenkins HelloWorld]$ 
    這次就有了change id
    然后再次push
    [user2@jenkins HelloWorld]$ git push origin
    Counting objects: 5, done.
    Writing objects: 100% (3/3), 289 bytes, done.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: Processing changes: new: 1, refs: 1, done    
    remote: 
    remote: New Changes:
    remote:   http://gerrit.example.com:8080/1
    remote: 
    To ssh://user2@gerrit.example.com:29418/HelloWorld.git
     * [new branch]      master -> refs/for/master
    [user2@jenkins HelloWorld]$ 
    posted @ 2017-08-11 11:23 小馬歌 閱讀(256) | 評論 (0)編輯 收藏
     

    from:http://blog.csdn.net/acmman/article/details/50848595

    版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

    目前,業(yè)內(nèi)關(guān)于OSGI技術(shù)的學(xué)習(xí)資源或者技術(shù)文檔還是很少的。我在某寶網(wǎng)搜索了一下“OSGI”的書籍,結(jié)果倒是有,但是種類少的可憐,而且?guī)缀鯖]有人購買。
    因?yàn)楣ぷ鞯脑蛭倚枰獙W(xué)習(xí)OSGI,所以我不得不想盡辦法來主動學(xué)習(xí)OSGI。我將用文字記錄學(xué)習(xí)OSGI的整個過程,通過整理書籍和視頻教程,來讓我更加了解這門技術(shù),同時也讓需要學(xué)習(xí)這門技術(shù)的同志們有一個清晰的學(xué)習(xí)路線。

    我們需要解決一下幾問題:
    1.如何正確的理解和認(rèn)識OSGI技術(shù)?

    我們從外文資料上或者從翻譯過來的資料上看到OSGi解釋和定義,都是直譯過來的,但是OSGI的真實(shí)意義未必是中文直譯過來的意思。OSGI的解釋就是Open Service Gateway Initiative,直譯過來就是“開放的服務(wù)入口(網(wǎng)關(guān))的初始化”,聽起來非常費(fèi)解,什么是服務(wù)入口初始化?

    所以我們不去直譯這個OSGI,我們換一種說法來描述OSGI技術(shù)。

    我們來回到我們以前的某些開發(fā)場景中去,假設(shè)我們使用SSH(struts+spring+hibernate)框架來開發(fā)我們的Web項(xiàng)目,我們做產(chǎn)品設(shè)計和開發(fā)的時候都是分模塊的,我們分模塊的目的就是實(shí)現(xiàn)模塊之間的“解耦”,更進(jìn)一步的目的是方便對一個項(xiàng)目的控制和管理。
    我們對一個項(xiàng)目進(jìn)行模塊化分解之后,我們就可以把不同模塊交給不同的開發(fā)人員來完成開發(fā),然后項(xiàng)目經(jīng)理把大家完成的模塊集中在一起,然后拼裝成一個最終的產(chǎn)品。一般我們開發(fā)都是這樣的基本情況。

    那么我們開發(fā)的時候預(yù)計的是系統(tǒng)的功能,根據(jù)系統(tǒng)的功能來進(jìn)行模塊的劃分,也就是說,這個產(chǎn)品的功能或客戶的需求是劃分的重要依據(jù)。

    但是我們在開發(fā)過程中,我們模塊之間還要彼此保持聯(lián)系,比如A模塊要從B模塊拿到一些數(shù)據(jù),而B模塊可能要調(diào)用C模塊中的一些方法(除了公共底層的工具類之外)。所以這些模塊只是一種邏輯意義上的劃分。

    最重要的一點(diǎn)是,我們把最終的項(xiàng)目要去部署到tomcat或者jBoss的服務(wù)器中去部署。那么我們啟動服務(wù)器的時候,能不能關(guān)閉項(xiàng)目的某個模塊或功能呢?很明顯是做不到的,一旦服務(wù)器啟動,所有模塊就要一起啟動,都要占用服務(wù)器資源,所以關(guān)閉不了模塊,假設(shè)能強(qiáng)制拿掉,就會影響其它的功能。

    以上就是我們傳統(tǒng)模塊式開發(fā)的一些局限性。

    我們做軟件開發(fā)一直在追求一個境界,就是模塊之間的真正“解耦”、“分離”,這樣我們在軟件的管理和開發(fā)上面就會更加的靈活,甚至包括給客戶部署項(xiàng)目的時候都可以做到更加的靈活可控。但是我們以前使用SSH框架等架構(gòu)模式進(jìn)行產(chǎn)品開發(fā)的時候我們是達(dá)不到這種要求的。

    所以我們“架構(gòu)師”或頂尖的技術(shù)高手都在為模塊化開發(fā)努力的摸索和嘗試,然后我們的OSGI的技術(shù)規(guī)范就應(yīng)運(yùn)而生。

    現(xiàn)在我們的OSGI技術(shù)就可以滿足我們之前所說的境界:在不同的模塊中做到徹底的分離,而不是邏輯意義上的分離,是物理上的分離,也就是說在運(yùn)行部署之后都可以在不停止服務(wù)器的時候直接把某些模塊拿下來,其他模塊的功能也不受影響。

    由此,OSGI技術(shù)將來會變得非常的重要,因?yàn)樗趯?shí)現(xiàn)模塊化解耦的路上,走得比現(xiàn)在大家經(jīng)常所用的SSH框架走的更遠(yuǎn)。這個技術(shù)在未來大規(guī)模、高訪問、高并發(fā)的Java模塊化開發(fā)領(lǐng)域,或者是項(xiàng)目規(guī)范化管理中,會大大超過SSH等框架的地位。

    現(xiàn)在主流的一些應(yīng)用服務(wù)器,Oracle的weblogic服務(wù)器,IBM的WebSphere,JBoss,還有Sun公司的glassfish服務(wù)器,都對OSGI提供了強(qiáng)大的支持,都是在OSGI的技術(shù)基礎(chǔ)上實(shí)現(xiàn)的。有那么多的大型廠商支持OSGI這門技術(shù),我們既可以看到OSGI技術(shù)的重要性。所以將來OSGI是將來非常重要的技術(shù)。

    但是OSGI仍然脫離不了框架的支持,因?yàn)镺SGI本身也使用了很多spring等框架的基本控件(因?yàn)橐獙?shí)現(xiàn)AOP依賴注入等功能),但是哪個項(xiàng)目又不去依賴第三方j(luò)ar呢?



    2.OSGI技術(shù)對我們項(xiàng)目的開發(fā)有什么幫助?

    (1)項(xiàng)目展示
    接下來我們同過項(xiàng)目代碼來展示一下OSGI的魅力:
    我們先不要去急著理解如何使用OSGI,我們通過一個項(xiàng)目先來看一下OSGI的效果。
    (以下工程代碼是網(wǎng)上教學(xué)視頻中的樣例,源碼我這里是沒有的)
    (提前說一下:我們要學(xué)習(xí)的重點(diǎn)就是我們這個購物網(wǎng)站如何結(jié)合OSGI技術(shù),使得項(xiàng)目更加的靈活可控,而購物網(wǎng)站本身并不是重點(diǎn)。)


    首先在Eclipse中先打開我們的單服務(wù)器版本的項(xiàng)目:

    啟動成功:




    這是一個Web項(xiàng)目,我們打開瀏覽器看一下效果:

    可以看出是一個網(wǎng)上購物的項(xiàng)目。

    我們來看一下我們基于OSGI技術(shù)的項(xiàng)目和我們一般的項(xiàng)目有什么區(qū)別。
    首先介紹一下這個項(xiàng)目的模塊:

    1.大類展示


    2.小類展示(大類的子產(chǎn)品)

    點(diǎn)進(jìn)去之后就是產(chǎn)品的具體信息



    3.購物車
    沒買東西是空的:

    買完之后:



    4.商品管理(上架、下架)



    可以看到,這個項(xiàng)目和我們平常開發(fā)的項(xiàng)目沒有什么不同(我知道界面很簡陋= =),重點(diǎn)是它的啟動和加載過程。


    (2)關(guān)于服務(wù)器
    我們是通過動態(tài)加載,也就是“熱部署”來啟動我們的項(xiàng)目的。就是說,我們這個項(xiàng)目把它放在Web容器中之后,我們可以將某些功能給它拿下來,而且拿下來的時候不會對其他模塊造成影響。

    我們以前運(yùn)行tomcat的時候,啟動一下服務(wù)器,將Web項(xiàng)目一次性裝載完畢,控制臺會出現(xiàn)類似這種信息:


    但是我們啟動這個項(xiàng)目的時候并不是這樣:


    那么我們沒有用tomcat和jBoss,那是如何部署和啟動Web項(xiàng)目的呢?不可能沒有Web服務(wù)器中間件的???這里告訴大家,OSGI技術(shù)里面也是內(nèi)嵌了一個Web服務(wù)器的,就是jetty。


    我們打開這個項(xiàng)目的Run Configuration配置窗口,看一下運(yùn)行這個項(xiàng)目所需要的插件包:


    可以看到,除了一些Web項(xiàng)目需要的jar包,還是有jetty的存在的。所以用到的服務(wù)器是jetty,不再是tomcat。


    大家可能還是比較熟悉tomcat,對于jetty不是太熟悉,那么我們簡單介紹一下jetty:
    jetty也是一個比較優(yōu)秀的Web容器,在某些性能方面要比tomcat強(qiáng)大的多(如高并發(fā),長連接)。而且它的整個結(jié)構(gòu)比tomcat輕巧很多(tomcat更臃腫),具體區(qū)別大家可以去網(wǎng)上自己看一下。


    (3)運(yùn)行模式和插件
    我們接下來正式看一下此項(xiàng)目在OSGI下的運(yùn)行模式:
    我們在啟動的時候,加載了四個模塊,分別是:

    按照模塊化的思想他們就是四個對應(yīng)的功能模塊。
    他們對應(yīng)的四個功能模塊的工程代碼我們可以在Eclipse中看到:



    我們看一下我們的啟動配置(依然打開是Run Configuration配置窗口):


    配置分為“WorkSpace”和“Target Platform”,分別是我們工作空間(我們自己寫的項(xiàng)目模塊和工具類)的插件和運(yùn)行平臺(一些依賴jar的配置)的插件,兩者結(jié)合啟動我們的項(xiàng)目就會正常運(yùn)行。

    我們啟動項(xiàng)目之后,在控制臺輸入指令“ss”,就會出現(xiàn)我們所有加載的插件的運(yùn)行情況:


    一啟動的時候,它會首先加載Eclipse的OSGI插件(Eclipse本身也是一種OSGI的容器):

    我們打開我們的Eclipse安裝目錄,然后找到plugins文件夾,可以看到Eclipse所有的插件:

    可以看到有文件夾形式的,有jar形式的插件。

    我們怎么去理解插件呢?
    插件其實(shí)就是被開發(fā)工具或OSGI容器管理和配置起來的jar包。  

    我們隨便打開一個文件夾類型的插件,可以看到:

    可以看到里面除了lib之外還有其它東西,然后有一個“OSGI-INF”文件夾。且不管它是什么,這都足以說明我們的Eclipse就是一個OSGI容器。

    (4)熱部署和熱啟動
    我們接下來回到重點(diǎn),在我們啟動的過程中,我們不停止運(yùn)行,然后去停掉其中的一個模塊:

    假如我們要停掉“管理”模塊:

    也就是停掉id為22的插件

    結(jié)果:


    然后刷新我們的網(wǎng)站主頁面:

    發(fā)現(xiàn)我們的“管理”模塊消失了!

    這個模塊的消失并不是javascript的技術(shù),而是一種服務(wù)器技術(shù),我們是通過服務(wù)器內(nèi)部把它動態(tài)卸載掉的。

    我們的管理模塊去掉之后,網(wǎng)站的其它功能不受任何影響。至此我們的服務(wù)器沒有進(jìn)行任何的暫停或關(guān)閉。

    我們再停掉“購物車”模塊:

    效果:

    其它模塊依舊不受影響。

    我們關(guān)閉了兩個模塊,現(xiàn)在輸入ss看一下所有插件和模塊的運(yùn)行情況:

    可以看到我們的兩個模塊處于RESOLVED狀態(tài),也就是待解決狀態(tài)。

    當(dāng)然我們也可以將我們的模塊在服務(wù)器開啟狀態(tài)下部署上去:
    如我們啟動購物車模塊:


    發(fā)現(xiàn)購物車回來了:


    這就是所謂的熱部署,即是這個項(xiàng)目把它放在Web容器中之后,我們可以將某些功能給它拿下來,而且拿下來的時候不會對其他模塊造成影響。


    通過購物網(wǎng)站這個項(xiàng)目讓大家真實(shí)的感受一下OSGI這個技術(shù)在項(xiàng)目開發(fā)和管理的一些強(qiáng)大的功能。

    想進(jìn)一步了解更多關(guān)于OSGI的知識可以查看以后的總結(jié)文章。

    轉(zhuǎn)載請注明出處:http://blog.csdn.net/acmman/article/details/50848595

    20
    posted @ 2017-08-10 15:57 小馬歌 閱讀(297) | 評論 (0)編輯 收藏
     
    from:http://www.jianshu.com/p/ccadc2bdb6d7

    第5章 Spring Boot自動配置原理

    5.1 SpringBoot的核心組件模塊

    首先,我們來簡單統(tǒng)計一下SpringBoot核心工程的源碼java文件數(shù)量:

    我們cd到spring-boot-autoconfigure工程根目錄下。執(zhí)行

    $ tree | grep -c .java$
    模塊 java文件數(shù)
    spring-boot 551
    spring-boot-actuator 423
    spring-boot-autoconfigure 783
    spring-boot-devtools 169
    spring-boot-cli 180
    spring-boot-tools 355

    我們可以看到有783個java文件。spring-boot核心工程有551個java文件。從上面的java文件數(shù)量大致可以看出,SpringBoot技術(shù)框架的核心組成部分:

    spring-boot-autoconfigure spring-boot spring-boot-tools

    我們把SpringBoot源碼導(dǎo)入IntelliJ IDEA,查看artifact的全部依賴關(guān)系。

    IDEA有個Maven Projects窗口,一般在右側(cè)能夠找到,如果沒有可以從菜單欄打開:View>Tool Windows>Maven Projects;

    選擇要分析的maven module(idea的module相當(dāng)于eclipse的project),右擊show dependencies,會出來該module的全部依賴關(guān)系圖,非常清晰細(xì)致。

    例如,spring-boot-starter-freemarker的依賴圖分析如下:


    在spring-boot-build 的pom中,我們可以看到:

               <modules>                 <module>spring-boot-dependencies</module>                 <module>spring-boot-parent</module>                 <module>spring-boot-tools</module>                 <module>spring-boot</module>                 <module>spring-boot-test</module>                 <module>spring-boot-autoconfigure</module>                 <module>spring-boot-test-autoconfigure</module>                 <module>spring-boot-actuator</module>                 <module>spring-boot-devtools</module>                 <module>spring-boot-docs</module>                 <module>spring-boot-starters</module>                 <module>spring-boot-actuator-docs</module>                 <module>spring-boot-cli</module>             </modules>

    其中,在spring-boot-dependencies中,SpringBoot項(xiàng)目維護(hù)了一份龐大依賴。這些依賴的版本都是經(jīng)過實(shí)踐,測試通過,不會發(fā)生依賴沖突的。就這樣一個事情,就大大減少了Spring開發(fā)過程中,出現(xiàn)jar包沖突的概率。spring-boot-parent依賴spring-boot-dependencies。

    下面我們簡要介紹一下SpringBoot子modules。

    spring-boot

    SpringBoot核心工程。

    spring-boot-starters

    是SpringBoot的啟動服務(wù)工程。

    spring-boot-autoconfigure

    是SpringBoot實(shí)現(xiàn)自動配置的核心工程。

    spring-boot-actuator

    提供SpringBoot應(yīng)用的外圍支撐性功能。 比如:

    • Endpoints,SpringBoot應(yīng)用狀態(tài)監(jiān)控管理
    • HealthIndicator,SpringBoot應(yīng)用健康指示表
    • 提供metrics支持
    • 提供遠(yuǎn)程shell支持

    spring-boot-tools

    提供了SpringBoot開發(fā)者的常用工具集。諸如,spring-boot-gradle-plugin,spring-boot-maven-plugin就是這個工程里面的。

    spring-boot-cli

    是Spring Boot命令行交互工具,可用于使用Spring進(jìn)行快速原型搭建。你可以用它直接運(yùn)行Groovy腳本。如果你不喜歡Maven或Gradle,Spring提供了CLI(Command Line Interface)來開發(fā)運(yùn)行Spring應(yīng)用程序。你可以使用它來運(yùn)行Groovy腳本,甚至編寫自定義命令。

    5.2 SpringBoot Starters

    Spring boot中的starter概念是非常重要的機(jī)制,能夠拋棄以前繁雜的配置,統(tǒng)一集成進(jìn)starter,應(yīng)用者只需要引入starter jar包,spring boot就能自動掃描到要加載的信息。

    starter讓我們擺脫了各種依賴庫的處理,需要配置各種信息的困擾。Spring Boot會自動通過classpath路徑下的類發(fā)現(xiàn)需要的Bean,并織入bean。

    例如,如果你想使用Spring和用JPA訪問數(shù)據(jù)庫,你只要依賴 spring-boot-starter-data-jpa 即可。

    目前,github上spring-boot項(xiàng)目的最新的starter列表spring-boot/spring-boot-starters如下:

    spring-boot-starter spring-boot-starter-activemq spring-boot-starter-actuator spring-boot-starter-amqp spring-boot-starter-aop spring-boot-starter-artemis spring-boot-starter-batch spring-boot-starter-cache spring-boot-starter-cloud-connectors spring-boot-starter-data-cassandra spring-boot-starter-data-couchbase spring-boot-starter-data-elasticsearch spring-boot-starter-data-jpa spring-boot-starter-data-ldap spring-boot-starter-data-mongodb spring-boot-starter-data-mongodb-reactive spring-boot-starter-data-neo4j spring-boot-starter-data-redis spring-boot-starter-data-rest spring-boot-starter-data-solr spring-boot-starter-freemarker spring-boot-starter-groovy-templates spring-boot-starter-hateoas spring-boot-starter-integration spring-boot-starter-jdbc spring-boot-starter-jersey spring-boot-starter-jetty spring-boot-starter-jooq spring-boot-starter-jta-atomikos spring-boot-starter-jta-bitronix spring-boot-starter-jta-narayana spring-boot-starter-log4j2 spring-boot-starter-logging spring-boot-starter-mail spring-boot-starter-mobile spring-boot-starter-mustache spring-boot-starter-parent spring-boot-starter-reactor-netty spring-boot-starter-security spring-boot-starter-social-facebook spring-boot-starter-social-linkedin spring-boot-starter-social-twitter spring-boot-starter-test spring-boot-starter-thymeleaf spring-boot-starter-tomcat spring-boot-starter-undertow spring-boot-starter-validation spring-boot-starter-web spring-boot-starter-web-services spring-boot-starter-webflux spring-boot-starter-websocket

    (源代碼目錄執(zhí)行shell:l|awk '{print $9}', l|awk '{print $9}'|grep -c 'starter')

    共52個。每個starter工程里面的pom描述有相應(yīng)的介紹。具體的說明,參考官網(wǎng)文檔[1]。關(guān)于這些starters的使用例子,可以參考spring-boot/spring-boot-samples

    比如說,spring-boot-starter是:

    Core starter, including auto-configuration support, logging and YAML

    這是Spring Boot的核心啟動器,包含了自動配置、日志和YAML。它的項(xiàng)目依賴圖如下:



    可以看出,這些starter只是配置,真正做自動化配置的代碼的是在spring-boot-autoconfigure里面。同時spring-boot-autoconfigure依賴spring-boot工程,這個spring-boot工程是SpringBoot的核心。

    SpringBoot會基于你的classpath中的jar包,試圖猜測和配置您可能需要的bean。

    例如,如果你的classpath中有tomcat-embedded.jar,你可能會想要一個TomcatEmbeddedServletContainerFactory Bean (SpringBoot通過獲取EmbeddedServletContainerFactory來啟動對應(yīng)的web服務(wù)器。常用的兩個實(shí)現(xiàn)類是TomcatEmbeddedServletContainerFactory和JettyEmbeddedServletContainerFactory)。

    其他的所有基于Spring Boot的starter都依賴這個spring-boot-starter。比如說spring-boot-starter-actuator的依賴樹,如下圖:


    5.3 @EnableAutoConfiguration自動配置原理

    通過@EnableAutoConfiguration啟用Spring應(yīng)用程序上下文的自動配置,這個注解會導(dǎo)入一個EnableAutoConfigurationImportSelector的類,而這個類會去讀取一個spring.factories下key為EnableAutoConfiguration對應(yīng)的全限定名的值。

    這個spring.factories里面配置的那些類,主要作用是告訴Spring Boot這個stareter所需要加載的那些xxxAutoConfiguration類,也就是你真正的要自動注冊的那些bean或功能。然后,我們實(shí)現(xiàn)一個spring.factories指定的類,標(biāo)上@Configuration注解,一個starter就定義完了。

    如果想從自己的starter種讀取應(yīng)用的starter工程的配置,只需要在入口類上加上如下注解即可:

    @EnableConfigurationProperties(MyProperties.class)

    讀取spring.factories文件的實(shí)現(xiàn)

    是通過org.springframework.core.io.support.SpringFactoriesLoader實(shí)現(xiàn)。

    SpringFactoriesLoader的實(shí)現(xiàn)類似于SPI(Service Provider Interface,在java.util.ServiceLoader的文檔里有比較詳細(xì)的介紹。java SPI提供一種服務(wù)發(fā)現(xiàn)機(jī)制,為某個接口尋找服務(wù)實(shí)現(xiàn)的機(jī)制。有點(diǎn)類似IOC的思想,就是將裝配的控制權(quán)移到程序之外,在模塊化設(shè)計中這個機(jī)制尤其重要[3])。

    SpringFactoriesLoader會加載classpath下所有JAR文件里面的META-INF/spring.factories文件。

    其中加載spring.factories文件的代碼在loadFactoryNames方法里:

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";  ....      public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {         String factoryClassName = factoryClass.getName();         try {             Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :                     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));             List<String> result = new ArrayList<>();             while (urls.hasMoreElements()) {                 URL url = urls.nextElement();                 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));                 String factoryClassNames = properties.getProperty(factoryClassName);                 result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));             }             return result;         }         catch (IOException ex) {             throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +                     "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);         }     }

    通過org.springframework.boot.autoconfigure.AutoConfigurationImportSelector里面的getCandidateConfigurations方法,獲取到候選類的名字List<String>。該方法代碼如下:

        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,             AnnotationAttributes attributes) {         List<String> configurations = SpringFactoriesLoader.loadFactoryNames(                 getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());         Assert.notEmpty(configurations,                 "No auto configuration classes found in META-INF/spring.factories. If you "                         + "are using a custom packaging, make sure that file is correct.");         return configurations;     }

    其中,getSpringFactoriesLoaderFactoryClass()方法直接返回的是EnableAutoConfiguration.class, 代碼如下:

        protected Class<?> getSpringFactoriesLoaderFactoryClass() {         return EnableAutoConfiguration.class;     }

    所以,getCandidateConfigurations方法里面的這段代碼:

    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(                 getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

    會過濾出key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名對應(yīng)的值。全限定名都使用如下命名方法:

    包名.外部類名 包名.外部類名$內(nèi)部類名  e.g:  org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration

    SpringBoot中的META-INF/spring.factories(完整路徑:spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories)中關(guān)于EnableAutoConfiguration的這段配置如下:

    # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.ReactiveMongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\ org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\ org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\ org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\ org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\ org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\ org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\ org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.ReactiveMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\ org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\ org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\ org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.WebFluxAnnotationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

    當(dāng)然了,這些AutoConfiguration不是所有都會加載的,會根據(jù)AutoConfiguration上的@ConditionalOnClass等條件,再進(jìn)一步判斷是否加載。我們下文通過FreeMarkerAutoConfiguration實(shí)例來分析整個自動配置的過程。

    5.4 FreeMarkerAutoConfiguration自動配置的實(shí)例分析

    我們首先看spring-boot-starter-freemarker工程,目錄結(jié)構(gòu)如下:

    . ├── pom.xml ├── spring-boot-starter-freemarker.iml └── src     └── main         └── resources             └── META-INF                 └── spring.provides  4 directories, 3 files

    我們可以看出,這個工程沒有任何Java代碼,只有兩個文件:pom.xml跟spring.provides。starter本身在你的應(yīng)用程序中實(shí)際上是空的。

    其中,
    spring.provides文件

    provides: freemarker,spring-context-support

    主要是給這個starter起個好區(qū)分的名字。

    Spring Boot 通過starter對項(xiàng)目的依賴進(jìn)行統(tǒng)一管理. starter利用了maven的傳遞依賴解析機(jī)制,把常用庫聚合在一起, 組成了針對特定功能而定制的依賴starter。

    我們可以使用IDEA提供的maven依賴圖分析的功能(如下圖),得到spring-boot-starter-freemarker依賴的module。


    IDEA提供的maven依賴圖分析

    spring-boot-starter-freemarker依賴的module

    從上面的依賴圖,我們可以清晰看出其間依賴關(guān)系。

    當(dāng)Spring Boot Application中自動配置EnableAutoConfiguration的相關(guān)類執(zhí)行完畢之后,Spring Boot會進(jìn)一步解析對應(yīng)類的配置信息。如果我們配置了spring-boot-starter-freemarker ,maven就會通過這個starter所依賴的spring-boot-autoconfigure,自動傳遞到spring-boot-autoconfigure工程中。

    我們來簡單分析一下spring-boot-autoconfigure工程的架構(gòu)。

    其中,F(xiàn)reeMarker的自動配置類是org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration。

    下面我們來簡要分析一下FreeMarkerAutoConfiguration這個類。

    在FreeMarkerAutoConfiguration類上面有四行注解:

    @Configuration @ConditionalOnClass({ freemarker.template.Configuration.class,         FreeMarkerConfigurationFactory.class }) @AutoConfigureAfter(WebMvcAutoConfiguration.class) @EnableConfigurationProperties(FreeMarkerProperties.class) public class FreeMarkerAutoConfiguration {     ... }

    其中,
    (1)@Configuration,是org.springframework.context.annotation包里面的注解。這么說吧,用@Configuration注解該類,等價 與XML中配置beans;用@Bean標(biāo)注方法等價于XML中配置bean。

    (2)@ConditionalOnClass,org.springframework.boot.autoconfigure.condition包里面的注解。意思是當(dāng)類路徑下有指定的類的條件下,才會去注冊被標(biāo)注的類為一個bean。在上面的代碼中的意思就是,當(dāng)類路徑中有freemarker.template.Configuration.class,FreeMarkerConfigurationFactory.class兩個類的時候,才會實(shí)例化FreeMarkerAutoConfiguration這個Bean。

    (3)@AutoConfigureAfter,org.springframework.boot.autoconfigure包里面的注解。這個通過注解的名字意思就可以知道,當(dāng)WebMvcAutoConfiguration.class這個類實(shí)例化完畢,才能實(shí)例化FreeMarkerAutoConfiguration(有個先后順序)。SpringBoot使用@ AutoConfigureBefore、@AutoConfigureAfter注解來定義這些配置類的載入順序。

    (4)@EnableConfigurationProperties,表示啟動對FreeMarkerProperties.class的內(nèi)嵌配置支持,自動將FreeMarkerProperties注冊為一個bean。這個FreeMarkerProperties類里面就是關(guān)于FreeMarker屬性的配置:

    @ConfigurationProperties(prefix = "spring.freemarker") public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {      public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";      public static final String DEFAULT_PREFIX = "";      public static final String DEFAULT_SUFFIX = ".ftl";      /**      * Well-known FreeMarker keys which will be passed to FreeMarker's Configuration.      */     private Map<String, String> settings = new HashMap<>();      /**      * Comma-separated list of template paths.      */     private String[] templateLoaderPath = new String[] { DEFAULT_TEMPLATE_LOADER_PATH };      /**      * Prefer file system access for template loading. File system access enables hot      * detection of template changes.      */     private boolean preferFileSystemAccess = true;      public FreeMarkerProperties() {         super(DEFAULT_PREFIX, DEFAULT_SUFFIX);     }      public Map<String, String> getSettings() {         return this.settings;     }      public void setSettings(Map<String, String> settings) {         this.settings = settings;     }      public String[] getTemplateLoaderPath() {         return this.templateLoaderPath;     }      public boolean isPreferFileSystemAccess() {         return this.preferFileSystemAccess;     }      public void setPreferFileSystemAccess(boolean preferFileSystemAccess) {         this.preferFileSystemAccess = preferFileSystemAccess;     }      public void setTemplateLoaderPath(String... templateLoaderPaths) {         this.templateLoaderPath = templateLoaderPaths;     }  }

    綜上,當(dāng)(1)(2)兩個條件滿足時,才會繼續(xù)(3)(4)的動作,同時注冊FreeMarkerAutoConfiguration這個Bean。該類的結(jié)構(gòu)如下圖:


    我們來看其內(nèi)部類FreeMarkerWebConfiguration的代碼:

        @Configuration     @ConditionalOnClass(Servlet.class)     @ConditionalOnWebApplication(type = Type.SERVLET)     public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration {          @Bean         @ConditionalOnMissingBean(FreeMarkerConfig.class)         public FreeMarkerConfigurer freeMarkerConfigurer() {             FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();             applyProperties(configurer);             return configurer;         }          @Bean         public freemarker.template.Configuration freeMarkerConfiguration(                 FreeMarkerConfig configurer) {             return configurer.getConfiguration();         }          @Bean         @ConditionalOnMissingBean(name = "freeMarkerViewResolver")         @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true)         public FreeMarkerViewResolver freeMarkerViewResolver() {             FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();             this.properties.applyToViewResolver(resolver);             return resolver;         }          @Bean         @ConditionalOnMissingBean         @ConditionalOnEnabledResourceChain         public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {             return new ResourceUrlEncodingFilter();         }      }

    其中,
    (1)@ConditionalOnWebApplication(type = Type.SERVLET), 是當(dāng)該應(yīng)用是基于Servlet的Web應(yīng)用時。

    (2)@ConditionalOnMissingBean(name = "freeMarkerViewResolver"),是當(dāng)Spring容器中不存在freeMarkerViewResolver的Bean時。

    (3)@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true),指定的spring.freemarker.enabled屬性是否有。如果沒有(IfMissing),設(shè)為true。

    當(dāng)(1)(2)(3)三個條件都滿足,則注冊freeMarkerViewResolver這個Bean。

    我們也可以自定義我們自己的my-starter,以及實(shí)現(xiàn)對應(yīng)的@MyEnableAutoConfiguration。SpringBoot有很多第三方starter,其自動配置的原理基本都是這樣,比如mybatis-spring-boot-starter的MybatisAutoConfiguration,閱讀源碼https://github.com/mybatis/spring-boot-starter[4]。

    上面文字描述了這么多,再用一張形象生動的圖來說明[5]:


    SpringBoot Autoconfigure 工作原理圖

    5.5 spring.factories與定義應(yīng)用程序的初始化行為

    上面說了這么多,講的都是讀取properties文件中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定名對應(yīng)的值。SpringBoot內(nèi)部還有許多其他的key用于過濾得到需要加載的類。

    # Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer  # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer  # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener  # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnClassCondition  # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer  # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\ org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

    這些key仍然是定義在spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories文件中。

    還有對應(yīng)的用于測試的自動配置,在
    spring-boot/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories文件中定義。

    另外,我們使用spring.factories里還可以定制應(yīng)用程序的初始化行為。這樣我們就可以在應(yīng)用程序載入前操縱Spring的應(yīng)用程序上下文ApplicationContext。

    例如,可以使用ConfigurableApplicationContext類的addApplicationListener()方法,在應(yīng)用上下文ApplicationContext中創(chuàng)建監(jiān)聽器。

    自動配置運(yùn)行日志報告功能就是這么實(shí)現(xiàn)的。我們來看在spring.factories中,Initializers一段的配置:

    # Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

    其中,AutoConfigurationReportLoggingInitializer監(jiān)聽到系統(tǒng)事件時,比如上下文刷新ContextRefreshedEvent或應(yīng)用程序啟動故障ApplicationFailedEvent之類的事件,Spring Boot可以做一些事情。這里說的代碼在AutoConfigurationReportLoggingInitializer.AutoConfigurationReportListener里面。關(guān)于支持的事件類型supportsEventType的如下:

        private class AutoConfigurationReportListener implements GenericApplicationListener {  ...         @Override         public boolean supportsEventType(ResolvableType resolvableType) {             Class<?> type = resolvableType.getRawClass();             if (type == null) {                 return false;             }             return ContextRefreshedEvent.class.isAssignableFrom(type)                     || ApplicationFailedEvent.class.isAssignableFrom(type);         }          @Override         public boolean supportsSourceType(Class<?> sourceType) {             return true;         }          @Override         public void onApplicationEvent(ApplicationEvent event) {     AutoConfigurationReportLoggingInitializer.this.onApplicationEvent(event);         }      }

    要以調(diào)試模式啟動應(yīng)用程序,可以使用-Ddebug標(biāo)識,或者在application.properties文件這添加屬性debug= true。這樣,當(dāng)我們以調(diào)試模式啟動應(yīng)用程序時,SpringBoot就可以幫助我們創(chuàng)建自動配置的運(yùn)行報告。對于每個自動配置,通過報告我們可以看到它啟動或失敗的原因。 這個報告內(nèi)容格式大致如下:

    ========================= AUTO-CONFIGURATION REPORT =========================   Positive matches: -----------------     DataSourceAutoConfiguration matched:       - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)     DataSourceAutoConfiguration#dataSourceInitializer matched:       - @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer; SearchStrategy: all) did not find any beans (OnBeanCondition)     DataSourceAutoConfiguration.PooledDataSourceConfiguration matched:       - AnyNestedCondition 2 matched 0 did not; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.PooledDataSourceAvailable PooledDataSource found supported DataSource; NestedCondition on DataSourceAutoConfiguration.PooledDataSourceCondition.ExplicitType @ConditionalOnProperty (spring.datasource.type) matched (DataSourceAutoConfiguration.PooledDataSourceCondition)       - @ConditionalOnMissingBean (types: javax.sql.DataSource,javax.sql.XADataSource; SearchStrategy: all) did not find any beans (OnBeanCondition)     ...  Exclusions: -----------      None   Unconditional classes: ----------------------      org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration      org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration      org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration      org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration

    除了SpringBoot官方提供的starter外,還有社區(qū)貢獻(xiàn)的很多常用的第三方starter,列表可參考[2]。

    另外,國內(nèi)很多公司使用RPC框架dubbo,關(guān)于SpringBoot集成dubbo,可參考:https://github.com/linux-china/spring-boot-dubbo。

    參考資料:

    1.http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter
    2.https://github.com/spring-projects/spring-boot/tree/master/spring-boot-starters
    3.http://www.cnblogs.com/javaee6/p/3714719.html
    4.https://github.com/mybatis/spring-boot-starter
    5.https://afoo.me/posts/2015-07-09-how-spring-boot-works.html



    作者:華夏商周秦漢唐宋元明清中華民國
    鏈接:http://www.jianshu.com/p/ccadc2bdb6d7
    來源:簡書
    著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
    posted @ 2017-08-02 16:35 小馬歌 閱讀(1742) | 評論 (0)編輯 收藏
     
         摘要: from:http://blog.csdn.net/lylwo317/article/details/52163304序言注解在Java中到底是什么樣的東西?具體是如何實(shí)現(xiàn)的? 本文將一層一層深入探究注解的實(shí)現(xiàn)原理。為了盡可能的將分析的過程呈現(xiàn)出來,所以文章包含了大量的截圖和代碼。(ps:如果圖片看不清楚,請將網(wǎng)頁放大來看,chrome可以通過ctrl+鼠標(biāo)滾輪放大)前期準(zhǔn)備知識方面開始...  閱讀全文
    posted @ 2017-08-02 11:15 小馬歌 閱讀(592) | 評論 (1)編輯 收藏
     

    如果沒有用來讀取注解的方法和工作,那么注解也就不會比注釋更有用處了。使用注解的過程中,很重要的一部分就是創(chuàng)建于使用注解處理器。Java SE5擴(kuò)展了反射機(jī)制的API,以幫助程序員快速的構(gòu)造自定義注解處理器。


    注解處理器類庫(java.lang.reflect.AnnotatedElement):

      Java使用Annotation接口來代表程序元素前面的注解,該接口是所有Annotation類型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,該接口代表程序中可以接受注解的程序元素,該接口主要有如下幾個實(shí)現(xiàn)類:

      Class:類定義
      Constructor:構(gòu)造器定義
      Field:累的成員變量定義
      Method:類的方法定義
      Package:類的包定義

      java.lang.reflect 包下主要包含一些實(shí)現(xiàn)反射功能的工具類,實(shí)際上,java.lang.reflect 包所有提供的反射API擴(kuò)充了讀取運(yùn)行時Annotation信息的能力。當(dāng)一個Annotation類型被定義為運(yùn)行時的Annotation后,該注解才能是運(yùn)行時可見,當(dāng)class文件被裝載時被保存在class文件中的Annotation才會被虛擬機(jī)讀取。
      AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了某個類的AnnotatedElement對象之后,程序就可以調(diào)用該對象的如下四個個方法來訪問Annotation信息:

      方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定類型的注解,如果該類型注解不存在,則返回null。
      方法2:Annotation[] getAnnotations():返回該程序元素上存在的所有注解。
      方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的注解,存在則返回true,否則返回false.
      方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上,則返回長度為零的一個數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。

      一個簡單的注解處理器:  

    復(fù)制代碼
    /***********注解聲明***************/  /**  * 水果名稱注解  * @author peida  *  */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitName {     String value() default ""; }  /**  * 水果顏色注解  * @author peida  *  */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitColor {     /**      * 顏色枚舉      * @author peida      *      */     public enum Color{ BULE,RED,GREEN};          /**      * 顏色屬性      * @return      */     Color fruitColor() default Color.GREEN;  }  /**  * 水果供應(yīng)者注解  * @author peida  *  */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitProvider {     /**      * 供應(yīng)商編號      * @return      */     public int id() default -1;          /**      * 供應(yīng)商名稱      * @return      */     public String name() default "";          /**      * 供應(yīng)商地址      * @return      */     public String address() default ""; }  /***********注解使用***************/  public class Apple {          @FruitName("Apple")     private String appleName;          @FruitColor(fruitColor=Color.RED)     private String appleColor;          @FruitProvider(id=1,name="陜西紅富士集團(tuán)",address="陜西省西安市延安路89號紅富士大廈")     private String appleProvider;          public void setAppleColor(String appleColor) {         this.appleColor = appleColor;     }     public String getAppleColor() {         return appleColor;     }          public void setAppleName(String appleName) {         this.appleName = appleName;     }     public String getAppleName() {         return appleName;     }          public void setAppleProvider(String appleProvider) {         this.appleProvider = appleProvider;     }     public String getAppleProvider() {         return appleProvider;     }          public void displayName(){         System.out.println("水果的名字是:蘋果");     } }  /***********注解處理器***************/  public class FruitInfoUtil {     public static void getFruitInfo(Class<?> clazz){                  String strFruitName=" 水果名稱:";         String strFruitColor=" 水果顏色:";         String strFruitProvicer="供應(yīng)商信息:";                  Field[] fields = clazz.getDeclaredFields();                  for(Field field :fields){             if(field.isAnnotationPresent(FruitName.class)){                 FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);                 strFruitName=strFruitName+fruitName.value();                 System.out.println(strFruitName);             }             else if(field.isAnnotationPresent(FruitColor.class)){                 FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);                 strFruitColor=strFruitColor+fruitColor.fruitColor().toString();                 System.out.println(strFruitColor);             }             else if(field.isAnnotationPresent(FruitProvider.class)){                 FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);                 strFruitProvicer=" 供應(yīng)商編號:"+fruitProvider.id()+" 供應(yīng)商名稱:"+fruitProvider.name()+" 供應(yīng)商地址:"+fruitProvider.address();                 System.out.println(strFruitProvicer);             }         }     } }  /***********輸出結(jié)果***************/ public class FruitRun {      /**      * @param args      */     public static void main(String[] args) {                  FruitInfoUtil.getFruitInfo(Apple.class);              }  }  ====================================  水果名稱:Apple  水果顏色:RED  供應(yīng)商編號:1 供應(yīng)商名稱:陜西紅富士集團(tuán) 供應(yīng)商地址:陜西省西安市延安路89號紅富士大廈
    復(fù)制代碼

       Java注解的基礎(chǔ)知識點(diǎn)(見下面導(dǎo)圖)基本都過了一遍,下一篇我們通過設(shè)計一個基于注解的簡單的ORM框架,來綜合應(yīng)用和進(jìn)一步加深對注解的各個知識點(diǎn)的理解和運(yùn)用。

     

     


    分類: java
    posted @ 2017-08-02 11:07 小馬歌 閱讀(227) | 評論 (0)編輯 收藏
     
    http://blog.csdn.net/coslay/article/details/43458907
    1. 我們需要知道的是找到默認(rèn)值的方法,掌握默認(rèn)值的大概量級,在不同的版本下哪些是常用的默認(rèn)參數(shù),哪些是必須設(shè)置的參數(shù),哪些是可以選擇的、盡量不要去碰的設(shè)置。  
    1. 參數(shù)設(shè)置同一個類型會有多種參數(shù),而且都有默認(rèn)值,大家不要混用噢,混用的結(jié)果很多時候難以預(yù)料,雖然在某種情況下可能得到了一個測試結(jié)果,但如果你沒有真正了解JVM的內(nèi)核源碼,是不可能知道所有細(xì)節(jié)的,即測試結(jié)果不能當(dāng)成任何場景下的一個結(jié)論,只能作為一種參考。  

    本篇文章基于Java 6update 21oder 21之后)版本, HotSpot JVM 提供給了兩個新的參數(shù),在JVM啟動后,在命令行中可以輸出所有XX參數(shù)和值。

    1. -XX:+PrintFlagsFinal and -XX:+PrintFlagsInitial  

    讓我們現(xiàn)在就了解一下新參數(shù)的輸出。以 -client 作為參數(shù)的 -XX:+PrintFlagsFinal   的結(jié)果是一個按字母排序的590個參數(shù)表格(注意,每個release版本參數(shù)的數(shù)量會不一樣)

    1. $ java -client -XX:+PrintFlagsFinal Benchmark  
    2. [Global flags]  
    3. uintx AdaptivePermSizeWeight               = 20               {product}  
    4. uintx AdaptiveSizeDecrementScaleFactor     = 4                {product}  
    5. uintx AdaptiveSizeMajorGCDecayTimeScale    = 10               {product}  
    6. uintx AdaptiveSizePausePolicy              = 0                {product}[...]  
    7. uintx YoungGenerationSizeSupplementDecay   = 8                {product}  
    8. uintx YoungPLABSize                        = 4096             {product}  
    9.  bool ZeroTLAB                             = false            {product}  
    10.  intx hashCode                             = 0                {product}  

    (校對注:你可以嘗試在命令行輸入上面的命令,親自實(shí)現(xiàn)下)

    表格的每一行包括五列,來表示一個XX參數(shù)。第一列表示參數(shù)的數(shù)據(jù)類型,第二列是名稱,第四列為值,第五列是參數(shù)的類別。第三列”=”表示第四列是參數(shù)的默認(rèn)值,而”:=” 表明了參數(shù)被用戶或者JVM賦值了。

    注意對于這個例子我只是用了Benchmark類,因?yàn)檫@個系列前面的章節(jié)也是用的這個類。甚至沒有一個主類的情況下你能得到相同的輸出,通過運(yùn)行Java 帶另外的參數(shù) -version.現(xiàn)在讓我們檢查下 server VM提供了多少個參數(shù)。我們也能指定參數(shù)-XX:+UnlockExperimentalVMOptions 和-XX:+UnlockDiagnosticVMOptions ;來解鎖任何額外的隱藏參數(shù)。

    1. $ java -server -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal Benchmark  
    724個參數(shù),讓我們看一眼那些已經(jīng)被賦值的參數(shù)。
    1. $ java -server -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal Benchmark | grep ":"  
    2. uintx InitialHeapSize                     := 57505088         {product}  
    3. uintx MaxHeapSize                         := 920649728        {product}  
    4. uintx ParallelGCThreads                   := 4                {product}  
    5.  bool PrintFlagsFinal                     := true             {product}  
    6.  bool UseParallelGC                       := true             {product}  

    (校對注:這個命令非常有用)我們僅設(shè)置一個自己的參數(shù) -XX:+PrintFlagsFinal。其他參數(shù)通過server VM基于系統(tǒng)設(shè)置的,以便以合適的堆大小和GC設(shè)置運(yùn)行。

    如果我們只想看下所有XX參數(shù)的默認(rèn)值,能夠用一個相關(guān)的參數(shù),-XX:+PrintFlagsInitial  。 用 -XX:+PrintFlagsInitial, 只是展示了第三列為“=”的數(shù)據(jù)(也包括那些被設(shè)置其他值的參數(shù))。

    然而,注意當(dāng)與-XX:+PrintFlagsFinal 對比的時候,一些參數(shù)會丟失,大概因?yàn)檫@些參數(shù)是動態(tài)創(chuàng)建的。

    研究表格的內(nèi)容是很有意思的,通過比較client和server VM的行為,很明顯了解哪些參數(shù)會影響其他的參數(shù)。有興趣的讀者,可以看一下這篇不錯文章Inspecting HotSpot JVM Options。這個文章主要解釋了第五列的參數(shù)類別。

    -XX:+PrintCommandLineFlags

    讓我們看下另外一個參數(shù),事實(shí)上這個參數(shù)非常有用: -XX:+PrintCommandLineFlags。這個參數(shù)讓JVM打印出那些已經(jīng)被用戶或者JVM設(shè)置過的詳細(xì)的XX參數(shù)的名稱和值。

    換句話說,它列舉出 -XX:+PrintFlagsFinal的結(jié)果中第三列有":="的參數(shù)。以這種方式,我們可以用-XX:+PrintCommandLineFlags作為快捷方式來查看修改過的參數(shù)??聪旅娴睦?。

    1. $ java -server -XX:+PrintCommandLineFlags Benchmark   

    1. -XX:InitialHeapSize=57505088 -XX:MaxHeapSize=920081408 -XX:ParallelGCThreads=4 -XX:+PrintCommandLineFlags -XX:+UseParallelGC  

    現(xiàn)在如果我們每次啟動java 程序的時候設(shè)置 -XX:+PrintCommandLineFlags 并且輸出到日志文件上,這樣會記錄下我們設(shè)置的JVM 參數(shù)對應(yīng)用程序性能的影響。類似于 -showversion(見 Part1),我建議 –XX:+PrintCommandLineFlags 這個參數(shù)應(yīng)該總是設(shè)置在JVM啟動的配置項(xiàng)里。因?yàn)槟銖牟恢滥闶裁磿r候會需要這些信息。

    奇怪的是在這個例子中,通過 -XX:+PrintCommandLineFlags 列出堆的最大值會比通過-XX:+PrintFlagsFinal列舉出的相應(yīng)值小一點(diǎn)。如果誰知道兩者之間不同的原因,請告訴我。

    轉(zhuǎn)載自:http://ifeve.com/useful-jvm-flags-part-3-printing-all-xx-flags-and-their-values/



       Java程序員有時候需要了解JVM相關(guān)的參數(shù),不管是出于好奇或者工作需要。Oracle的文檔中列出了一些,(點(diǎn)擊這里),單并不是全部,而且有些參數(shù)的設(shè)置會默認(rèn)啟用或者關(guān)閉其他一些參數(shù),而在某些情況下設(shè)置某個參數(shù)是不會生效的。還有些時候你想讓JVM做某些事情,但是你不知道那個參數(shù)可以用。下面介紹一些辦法用以列出所有參數(shù),這樣你在研究或者Google的時候也比較有明確的目標(biāo)。

        如果你想查看一下線上正在運(yùn)行的JVM到底設(shè)置了那些參數(shù),生效的是那些,可能用到的方法:

        1. 在Linux下用ps命令找到啟動Java應(yīng)用時的參數(shù)

    1. ps -ef | grep "your java app name"    

        這個命令會打出你啟動Java應(yīng)用時傳給java命令的所有參數(shù),你可以看到里面的JVM參數(shù)。

        2.直接看啟動腳本,或者參數(shù)配置

        你未必能找到所有設(shè)置這JVM參數(shù)的地方,容易遺漏。

        一般來講以上兩種辦法都需要對JVM了如指掌或者非常熟悉,至少對特定的參數(shù)。

        

        其實(shí)JVM中有一個參數(shù)-XX:+PrintFlagsFinal,可以打印出幾乎所有的JVM支持的參數(shù)以及他們的默認(rèn)值。如果你想要查看你的Java應(yīng)用到底使用了那些參數(shù),只要在啟動的時候加上這個參數(shù)就可以了。

        1.查看你使用的JDK支持的參數(shù)

    1. java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version    

        2.打印Java應(yīng)用啟用的JVM參數(shù)

    1. java -XX:+PrintFlagsFinal -classpath=/path/to/your/libs MainClass    

        3.如果你的Java應(yīng)用已經(jīng)是運(yùn)行狀態(tài)了,你想查看某個JVM參數(shù)生效沒有可以使用jinfo這個工具。比如說大名鼎鼎的G1垃圾回收器,在JDK7update3中不論是客戶端(-client)還是服務(wù)器(-server)模式下都不是默認(rèn)啟動的。

        jinfo是隨JDK一起發(fā)布的,使用時先用jps找到Java應(yīng)用的pid。直接運(yùn)行jinfo可以查看使用說明。

    1. jinfo -flag UseParallelOldGC 31072    

        3.如果你的Java應(yīng)用已經(jīng)是運(yùn)行狀態(tài)了,你想查看某個JVM參數(shù)生效沒有可以使用jinfo這個工具。比如說大名鼎鼎的G1垃圾回收器,在JDK7update3中不論是客戶端(-client)還是服務(wù)器(-server)模式下都不是默認(rèn)啟動的。

        jinfo是隨JDK一起發(fā)布的,使用時先用jps找到Java應(yīng)用的pid。直接運(yùn)行jinfo可以查看使用說明。

    1. jinfo -flag UseParallelOldGC 31072  <span style="color: rgb(0, 204, 0); line-height: 18px; font-family: Consolas, 'Courier New', Courier, mono, serif; background-color: inherit;"> </span>  
    1. -XX:+UseParallelOldGC    
        JDK中實(shí)用的工具還很多,可以逐個的體驗(yàn)一下${JAVA_HOME}/bin目錄中的每個命令,有驚喜。


    參考:http://blog.csdn.net/redhat456/article/details/7360249

    0
    posted @ 2017-07-28 11:01 小馬歌 閱讀(423) | 評論 (0)編輯 收藏
    僅列出標(biāo)題
    共95頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
     
    主站蜘蛛池模板: 亚洲人成电影网站| 中文字幕无码日韩专区免费| 67194成手机免费观看| 亚洲国产小视频精品久久久三级| 亚洲中文字幕久久精品无码2021| a级毛片高清免费视频| 免费看小12萝裸体视频国产| 亚洲av永久综合在线观看尤物| 日本免费一区二区久久人人澡| 成人亚洲综合天堂| 亚洲欧美aⅴ在线资源| 中文字幕免费观看| 国产精品亚洲а∨无码播放| 理论秋霞在线看免费| 97人伦色伦成人免费视频| 久久狠狠高潮亚洲精品| 国产一级a毛一级a看免费视频| 四虎永久免费地址在线网站| 亚洲a级片在线观看| 足恋玩丝袜脚视频免费网站| 亚洲成AV人在线观看天堂无码| 一级人做人爰a全过程免费视频| 日本高清免费中文字幕不卡| 久久精品国产亚洲AV久| 最近免费中文字幕大全高清大全1| 亚洲妇熟XXXX妇色黄| www免费黄色网| 亚洲国产成人精品女人久久久| 亚洲a∨国产av综合av下载 | 2022年亚洲午夜一区二区福利| 在线观看片免费人成视频播放| 亚洲毛片av日韩av无码| 国产一区二区三区亚洲综合| 日本视频免费在线| 亚洲依依成人亚洲社区| 无码国产精品一区二区免费I6| 亚洲国产成+人+综合| 曰批视频免费30分钟成人| 91亚洲一区二区在线观看不卡| 99在线视频免费| 久久亚洲国产成人精品性色|