PIXNET Logo登入

互聯網 - 大數據

跳到主文

本部落格為互聯網熱門頭條訊息管理中心

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 3月 07 週二 201721:15
  • jvm系列(八):jvm知識點總覽-高級Java工程師面試必備


Source: http://www.cnblogs.com/ityouknow/p/6482464.html
在江湖中要練就絕世武功必須內外兼備,精妙的招式和深厚的內功,武功的基礎是內功。對于武功低(就像江南七怪)的人,招式更重要,因為他們不能靠內功直接去傷人,只能靠招式,利刃上優勢來取勝了,但是練到高手之后,內功就更主要了。一個內功低的人招式在奇妙也打不過一個內功高的人。比如,你劍法再厲害,一劍刺過來,別人一掌打斷你的劍,你還怎么使劍法,你一掌打到一個武功高的人身上,那人沒什么事,卻把你震傷了,你還怎么打。同樣兩者也是相輔相成的,內功深厚之后,原來普通的一招一式威力也會倍增。
對于搞開發的我們其實也是一樣,現在流行的框架越來越多,封裝的也越來越完善,各種框架可以搞定一切,幾乎不用關注底層的實現,初級程序員只要熟悉基本的使用方法,便可以快速的開發上線;但對于高級程序員來講,內功的修煉卻越發的重要,比如算法、設計模式、底層原理等,只有把這些基礎熟練之后,才能在開發過程中知其然知其所以然,出現問題時能快速定位到問題的本質。
對于Java程序員來講,spring全家桶幾乎可以搞定一切,spring全家桶便是精妙的招式,jvm就是內功心法很重要的一塊,線上出現性能問題,jvm調優更是不可回避的問題。因此JVM基礎知識對于高級程序員的重要性不必言語,我司在面試高級開發的時候,jvm相關知識也必定是考核的標準之一。本篇文章會根據之前寫的jvm系列文章梳理出jvm需要關注的所有考察點。
jvm 總體梳理
jvm體系總體分四大塊:
  • 類的加載機制

  • jvm內存結構

  • GC算法 垃圾回收

  • GC分析 命令調優

  • 當然這些知識點在之前的文章中都有詳細的介紹,這里只做主干的梳理
    這里畫了一個思維導圖,將所有的知識點進行了陳列,因為圖比較大可以點擊右鍵下載了放大查看。
    類的加載機制
    主要關注點:
  • 什么是類的加載

  • 類的生命周期

  • 類加載器

  • 雙親委派模型

  • 什么是類的加載
    類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然后在堆區創建一個java.lang.Class對象,用來封裝類在方法區內的數據結構。類的加載的最終產品是位于堆區中的Class對象,Class對象封裝了類在方法區內的數據結構,并且向Java程序員提供了訪問方法區內的數據結構的接口。
    類的生命周期
    類的生命周期包括這幾個部分,加載、連接、初始化、使用和卸載,其中前三部是類的加載的過程,如下圖;
  • 加載,查找并加載類的二進制數據,在Java堆中也創建一個java.lang.Class類的對象

  • 連接,連接又包含三塊內容:驗證、準備、初始化。1)驗證,文件格式、元數據、字節碼、符號引用驗證;2)準備,為類的靜態變量分配內存,并將其初始化為默認值;3)解析,把類中的符號引用轉換為直接引用

  • 初始化,為類的靜態變量賦予正確的初始值

  • 使用,new出對象程序中使用

  • 卸載,執行垃圾回收

  • 幾個小問題?
    1、JVM初始化步驟 ? 2、類初始化時機 ?3、哪幾種情況下,Java虛擬機將結束生命周期?
    答案參考這篇文章jvm系列(一):java類的加載機制


    類加載器
  • 啟動類加載器:Bootstrap ClassLoader,負責加載存放在JDK\jre\lib(JDK代表JDK的安裝目錄,下同)下,或被-Xbootclasspath參數指定的路徑中的,并且能被虛擬機識別的類庫

  • 擴展類加載器:Extension ClassLoader,該加載器由sun.misc.Launcher$ExtClassLoader實現,它負責加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統變量指定的路徑中的所有類庫(如javax.*開頭的類),開發者可以直接使用擴展類加載器。

  • 應用程序類加載器:Application ClassLoader,該類加載器由sun.misc.Launcher$AppClassLoader來實現,它負責加載用戶類路徑(ClassPath)所指定的類,開發者可以直接使用該類加載器

  • 類加載機制
  • 全盤負責,當一個類加載器負責加載某個Class時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來載入

  • 父類委托,先讓父類加載器試圖加載該類,只有在父類加載器無法加載該類時才嘗試從自己的類路徑中加載該類

  • 緩存機制,緩存機制將會保證所有加載過的Class都會被緩存,當程序中需要使用某個Class時,類加載器先從緩存區尋找該Class,只有緩存區不存在,系統才會讀取該類對應的二進制數據,并將其轉換成Class對象,存入緩存區。這就是為什么修改了Class后,必須重啟JVM,程序的修改才會生效

  • jvm內存結構
    主要關注點:
  • jvm內存結構都是什么

  • 對象分配規則

  • jvm內存結構

    方法區和對是所有線程共享的內存區域;而java棧、本地方法棧和程序員計數器是運行是線程私有的內存區域。


  • Java堆(Heap),是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。

  • 方法區(Method Area),方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。

  • 程序計數器(Program Counter Register),程序計數器(Program Counter Register)是一塊較小的內存空間,它的作用可以看做是當前線程所執行的字節碼的行號指示器。

  • JVM棧(JVM Stacks),與程序計數器一樣,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用于存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。

  • 本地方法棧(Native Method Stacks),本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務。

  • 對象分配規則
  • 對象優先分配在Eden區,如果Eden區沒有足夠的空間時,虛擬機執行一次Minor GC。

  • 大對象直接進入老年代(大對象是指需要大量連續內存空間的對象)。這樣做的目的是避免在Eden區和兩個Survivor區之間發生大量的內存拷貝(新生代采用復制算法收集內存)。

  • 長期存活的對象進入老年代。虛擬機為每個對象定義了一個年齡計數器,如果對象經過了1次Minor GC那么對象會進入Survivor區,之后每經過一次Minor GC那么對象的年齡加1,知道達到閥值對象進入老年區。

  • 動態判斷對象的年齡。如果Survivor區中相同年齡的所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入老年代。

  • 空間分配擔保。每次進行Minor GC時,JVM會計算Survivor區移至老年區的對象的平均大小,如果這個值大于老年區的剩余值大小則進行一次Full GC,如果小于檢查HandlePromotionFailure設置,如果true則只進行Monitor GC,如果false則進行Full GC。 

  • 如何通過參數來控制個各個內存區域
    參考此文章:jvm系列(二):JVM內存結構


    GC算法 垃圾回收
    主要關注點:
  • 對象存活判斷

  • GC算法

  • 垃圾回收器

  • 對象存活判斷
    判斷對象是否存活一般有兩種方式:
  • 引用計數:每個對象有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數為0時可以回收。此方法簡單,無法解決對象相互循環引用的問題。

  • 可達性分析(Reachability Analysis):從GC Roots開始向下搜索,搜索所走過的路徑稱為引用鏈。當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的,不可達對象。

  • GC算法
    GC最基礎的算法有三種:標記 -清除算法、復制算法、標記-壓縮算法,我們常用的垃圾回收器一般都采用分代收集算法。
  • 標記 -清除算法,“標記-清除”(Mark-Sweep)算法,如它的名字一樣,算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收掉所有被標記的對象。

  • 復制算法,“復制”(Copying)的收集算法,它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉。

  • 標記-壓縮算法,標記過程仍然與“標記-清除”算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存

  • 分代收集算法,“分代收集”(Generational Collection)算法,把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最適當的收集算法。

  • 垃圾回收器
  • Serial收集器,串行收集器是最古老,最穩定以及效率高的收集器,可能會產生較長的停頓,只使用一個線程去回收。

  • ParNew收集器,ParNew收集器其實就是Serial收集器的多線程版本。

  • Parallel收集器,Parallel Scavenge收集器類似ParNew收集器,Parallel收集器更關注系統的吞吐量。

  • Parallel Old 收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法

  • CMS收集器,CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。

  • G1收集器,G1 (Garbage-First)是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內存的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特征

  • GC算法和垃圾回收器算法圖解以及更詳細內容參考 jvm系列(三):GC算法 垃圾收集器


    GC分析 命令調優
    主要關注點:
  • GC日志分析

  • 調優命令

  • 調優工具

  • GC日志分析
    摘錄GC日志一部分(前部分為年輕代gc回收;后部分為full gc回收):
    2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K->10738K(274944K)] 371093K->147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs] 
    2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K->0K(274944K)] [ParOldGen: 136447K->140379K(302592K)] 147186K->140379K(577536K) [PSPermGen: 85411K->85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]

    通過上面日志分析得出,PSYoungGen、ParOldGen、PSPermGen屬于Parallel收集器。其中PSYoungGen表示gc回收前后年輕代的內存變化;ParOldGen表示gc回收前后老年代的內存變化;PSPermGen表示gc回收前后永久區的內存變化。young gc 主要是針對年輕代進行內存回收比較頻繁,耗時短;full gc 會對整個堆內存進行回城,耗時長,因此一般盡量減少full gc的次數
    young gc 日志:
    Full GC日志:
    調優命令
    Sun JDK監控和故障處理命令有jps jstat jmap jhat jstack jinfo
  • jps,JVM Process Status Tool,顯示指定系統內所有的HotSpot虛擬機進程。

  • jstat,JVM statistics Monitoring是用于監視虛擬機運行時狀態信息的命令,它可以顯示出虛擬機進程中的類裝載、內存、垃圾收集、JIT編譯等運行數據。

  • jmap,JVM Memory Map命令用于生成heap dump文件

  • jhat,JVM Heap Analysis Tool命令是與jmap搭配使用,用來分析jmap生成的dump,jhat內置了一個微型的HTTP/HTML服務器,生成dump的分析結果后,可以在瀏覽器中查看

  • jstack,用于生成java虛擬機當前時刻的線程快照。

  • jinfo,JVM Configuration info 這個命令作用是實時查看和調整虛擬機運行參數。

  • 詳細的命令使用參考這里jvm系列(四):jvm調優-命令篇


    調優工具
    常用調優工具分為兩類,jdk自帶監控工具:jconsole和jvisualvm,第三方有:MAT(Memory Analyzer Tool)、GChisto。
  • jconsole,Java Monitoring and Management Console是從java5開始,在JDK中自帶的java監控和管理控制臺,用于對JVM中內存,線程和類等的監控

  • jvisualvm,jdk自帶全能工具,可以分析內存快照、線程快照;監控內存變化、GC變化等。

  • MAT,Memory Analyzer Tool,一個基于Eclipse的內存分析工具,是一個快速、功能豐富的Java heap分析工具,它可以幫助我們查找內存泄漏和減少內存消耗

  • GChisto,一款專業分析gc日志的工具

  • 工具使用參考 jvm系列(七):jvm調優-工具篇




    作者:純潔的微笑
    出處:http://www.ityouknow.com/
    版權歸作者所有,轉載請注明出處
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:15
    • xFire客戶端代碼


    Source: http://www.cnblogs.com/ityouknow/archive/2012/11/26/2788772.html
    import java.net.URL;
    import org.apache.log4j.Logger;
    import org.codehaus.xfire.client.Client;
    public class IServiceClient {
    private static Logger logger = Logger.getLogger(IServiceClient.class);
    public static String IServiceClient(String info) {
    String result
    ="false";
    try {
    logger.debug(
    "begin Other");
    Client c1
    = new Client(
    new URL(
    "http://127.0.0.1:8080/service/SendInfo?wsdl"));
    logger.debug(
    "init");
    Object[] results1
    = c1.invoke("setInfo",new Object[] { info});
    logger.debug(
    "invoke");
    logger.debug(results1[
    0].toString());
    result
    =results1[0].toString();
    //Thread.sleep(500);
    } catch (Exception e) {
    e.printStackTrace();
    }
    return result;
    }
    public static void main(String[] args) {
    IServiceClient(
    "1006");
    }
    }

     
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:15
    • 如何查看jdk是32位(x86)還是64(x64)位


    Source: http://www.cnblogs.com/ityouknow/archive/2012/12/13/2816498.html
    public class test {
    public static void main(String[] args) {
    String arch = System.getProperty("sun.arch.data.model");
    System.out.println(arch+"-bit");
    }
    }

      
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:15
    • 網貸之家的爬蟲之旅

    Source: http://www.cnblogs.com/ityouknow/p/4423998.html
    [導讀]  因為本人公司正處于P2P的行業,分析行業數據,對平臺的運營決策有著很大的作用,因此需要爬網貸之家的相關數據。
    1、分析
           通過右鍵查看頁面源代碼發現頁面結構為表格布局,因此設想可以分為四個步驟來采集數據:
          1、使用爬蟲將頁面抓取下來;
          2、對頁面數據進行解析;
          3、入庫(mysql);
          4、寫個定時服務每天定時抓取。
          因為公司網站使用PHP,最近也學習了一點,curl非常適合用來爬去網頁,決定用PHP程序進行抓取。
    image
    2、抓取頁面
           網貸之家有一個數據的二級域名,展示所有接入的P2P公司的各種成交數據,輸入日期可以查詢對應日期的數據(http://shuju.wangdaizhijia.com/indexs-0-0-0-400-0-0.html?startTime=2015-04-04&endTime=2015-04-04),分析url發現只要改變后面的日期就可以分別的抓取各個日期下的數據,分析完畢,找一個url開始抓取;有一個小插曲,剛開始抓取的時候,返回的頁面信息都是404.html,最后分析發現網站對非瀏覽器的請求進行了屏蔽,直接跳轉404。后臺加綠色代碼的部分,成功抓取數據。
    function crawl($url){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)');
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $result=curl_exec($ch);
    curl_close($ch);
    return $result;
    }

    3、解析數據
         查看頁面源代碼發現,第一行為title去掉,最后兩列為平臺的連接和關注,均過濾掉。第一列的id需要根據下列的連接來截取,中間的所有數據會有漢子的單位和一些特殊字符,使用preg_replace進行替換,最后按照網貸之家平臺的數據格式進行拼接入庫的SQL,返回done。
    function analyze($dom,$satTime){
    $html = new simple_html_dom();
    $sql= "insert into XXX_data (XXPlatId,platName,averageMonth,dayTotal,averageRate,investNumber,averageInvestMoney,averageBorrowTime,borrowNumer,borrowBidNumber,averageBorrowMoney,firstTenInvestRate,firstTenBorrowRate,bidEndTime,registerTime,registerMoney,leverageFund,invest30total,repay60total,repayTotal,statisticsTime,excuteTime) values ";
    $html->load($dom);
    $istitle=0;
    foreach($html->find('tr') as $tr){
    $istitle=$istitle+1;
    if($istitle==1){
    continue;
    }
    $sql.="(";
    $count=0;
    foreach($tr->find('td') as $element){
    $count=$count+1;
    if($count==1){
    $href=$element->next_sibling()->find('a', 0)->href;
    $href=strstr($href, '.', TRUE);
    $href=strstr($href,'-');
    $sql.="'".substr($href,1)."',";
    }elseif($count==2){
    $val=$element->find('a', 0)->innertext;
    $sql.="'".$val."',";
    }elseif($count<21){
    $patterns = array();
    $patterns[0] = '/([-]*)/i';
    $patterns[1] = '/[%*]/';
    $val=preg_replace($patterns,'',$element->innertext);
    $sql.="'".$val."',";
    }
    }
    $sql.="'".$satTime."','".date('Y-m-d H:i:s')."'),";
    }
    $sql = substr($sql,0,strlen($sql)-1);
    $sql = strip_tags($sql);
    return $sql;
    }

    4、入庫
             通過網上的查找學習,發現PHP操作mysql比起java來說更簡單,幾句代碼搞定.
    function save($sql){
    $con = mysql_connect("192.168.0.1","root","root");
    if (!$con){
    die('Could not connect: ' . mysql_error());
    }
    mysql_select_db("xx_data", $con);
    mysql_query("set names utf8");
    mysql_query($sql);
    mysql_close($con);
    }

    5、批量爬取
         通過分析數據的查詢條件,每次的查詢都是根據url后綴的日期來查詢當日交易數據,  http://XXX/indexs.html?startTime=2015-04-01&endTime=2015-04-01,因為只需要遍歷歷史日期來拼接URl就用來爬取歷史的所有交易。
    function execute(){
    $starttime="2014-04-15";
    $endtime="2015-04-15";
    for($start = strtotime($starttime); $start <= strtotime($endtime);$start += 86400){
    $date=date('Y-m-d',$start);
    $url="http://shuju.XX.com/indexs.html?startTime=".$date."&endTime=".$date;
    //第一步 抓取
    $dom=crawl($url);
    //第二步 解析
    $sql=analyze($dom,$date);
    //第三步 入庫
    save($sql);
    }
    echo "execute end";
    }
    execute();


    6、設置定時服務
           設置定時任務來每天固定時間來抓取最新的數據,以免每次手工來執行,php也有自己的定時任務,但是網上看了下實現起來太復雜,因此利用linux的crontab來實現,linux下面輸入crontab –e 進入編輯狀態,添加一條定時利用curl來調用,至此爬蟲功能完畢。
    30 09 * * * curl http://192.168.0.1/crawl.php

     
    此程序僅供學習交流,如果有需要完整源碼的朋友可以單獨聯系我。
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(15)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:15
    • 大數據實踐-數據同步篇tungsten-relicator(mysql-mongo)

    Source: http://www.cnblogs.com/ityouknow/p/4918164.html
    [導讀] 
               隨著公司業務的快速發展數據量也迅速的增大,基于用戶各個維度深度分析,關系型數據壓力越來越大;因此急于尋找一些解決方案;調研了很久最后采用了 golang+mongod集群的這個方案,使用mongo做數據分析的存儲端,數據同步就成為一個問題,目前網上主流的工具和解決方案都比較少,唯一一個稍微多點的文章就是tungsten-relicator,最后技術選型也才用了它,目前也使用了快一年了,遇到過很多問題,但基本還算比較穩定。
     
    tungsten-relicator介紹
    Tungsten Replicator 是一個高性能、開源的數據復制引擎,用于 MySQL、Postgres 和 Oracle 數據庫。這是 Continuent 最先進的集群解決方案的核心組件之一。
    第三方數據復制引擎--Tungsten-Replicator 主要特點:
    1 支持高版本MySQL向低版本復制,5.1-->5.0
    2 支持跨數據庫系統的復制,MySQL-->PgSQL
    3 支持多主庫向單臺Slave的復制,Multi-Master-->Slave
    4 G-Replicator提取數據的更新記錄寫到MySQL 隊列表Queue;基于這個隊列,可以為其他應用服務提供便利
     
    方案設計:
               公司以前使用著mysql的主從,為了不影響正常業務,又添加了一個從庫;從第二個從庫同步到mongo集群中;本文不在描述mysql集群和monggo集群搭建,重點討論tungsten-relicator同步和部署
           1、停止從庫的主從同步,導出從庫中的所有數據,清空從庫;
           2、配置從庫和第二從庫的同步
           3、搭建tungsten-relicator同步(mysql-mongo)
           4、將從庫導出的數據從新導入從庫
          5、重啟啟動主從同步。
    部署完成后的圖解
                                     同步圖
     
     
    搭建tungsten-relicator同步
    tungsten-relicator需要部署到兩條服務器,主服務負責讀mysql binlog日志解析后傳送給從服務器,從服務器接收數據并同步到mongo
    首先配置主服務器(192.168.0.1)
    1、安裝基礎環境 JAVA  RUBY
    yum -y install java-1.7.0-openjdk*
    yum
    -y install ruby

    2、修改系統的最大鏈接數

    1)查看 ulimit -n


    2)更改



    vim /etc/security/limits.conf


    * soft nofile 65535


    * hard nofile 65535



    3)重啟linux


          reboot


    3、修改mysql配置
    vi /etc/my.cnf
    最下面添加
    binlog_format
    =row
    max_allowed_packet
    = 52M
    log_slave_updates
    = 1

    同時停止同步

    slave stop;

    4、tungsten主程序配置
    解壓 

    tar -zxvf tungsten-replicator-2.2.1-403.tar.gz
    cd tungsten
    -replicator-2.2.1-403
    啟動
    .
    /tools/tpm install mysql2mongodb \
    --master=192.168.0.1 \
    --install-directory=/opt/continuent \
    --replication-user=root\
    --replication-password=root\
    --enable-heterogenous-master=true \
    --repl-svc-extractor-filters=replicate \
    --property=replicator.filter.replicate.do=zhongxin \
    --property=replicator.filter.pkey.addColumnsToDeletes=true \
    --property=replicator.filter.pkey.addPkeyToInserts=true \
    --start

    master  --  主服務器Ip地址
    replication-user  --  myslq用戶名
    replication-password  --  mysql密碼
    property=replicator.filter.replicate.do  --  同步的數據庫庫名
     
    5、查看tungsten 同步狀態
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl status

    state    : ONLINE 表示服務啟動正常

     
     
    配置從服務器(192.168.0.2)
    1、安裝基礎環境 JAVA  RUBY
    yum -y install java-1.7.0-openjdk*
    yum
    -y install ruby

    2、修改系統的最大鏈接數

    1)查看 ulimit -n


    2)更改



    vim /etc/security/limits.conf


    * soft nofile 65535


    * hard nofile 65535



    3)重啟linux


          reboot


    3、配置免密碼登錄(從tungsten從服務器免密碼登錄主服務器)
     ssh-keygen -t rsa 一路回車
    cd .ssh
    /
    cp id_rsa.pub authorized_keys
    chmod
    600 authorized_keys
    scp authorized_keys root@
    192.168.0.2:/root/.ssh
    chmod
    700 -R .ssh

     

     驗證無密碼登錄:ssh 192.168.0.1 

    4、tungsten從服務程序配置
    解壓 

    tar -zxvf tungsten-replicator-2.2.1-403.tar.gz
    cd tungsten
    -replicator-2.2.1-403
    啟動
    ./tools/tungsten-installer --master-slave -a  \
         --datasource-type=mongodb \
         --datasource-port=27001 \
         --master-host=192.168.0.1     \
         --service-name=mysql2mongodb  \
         --home-directory=/opt/continuent \
         --java-file-encoding=UTF8 \
         --svc-parallelization-type=none \
         --start-and-report

    mongodb安裝在本地
    master-host  --  主服務地址
    5、查看tungsten 同步狀態
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl status

    state    : ONLINE 表示服務啟動正常

    6、啟動mysql同步數據了
    start slave;

     
     
     
    運營篇
    1、查看同步工具的日志
    tail -300f /opt/continuent/tungsten/tungsten-replicator/log/trepsvc.log
    tail
    -30f /opt/continuent/service_logs/trepsvc.log

    2、查看同步的狀態
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl status
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl services

    3、當同步出錯后,解決問題后,執行命令重新同步
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl -service mysql2mongodb online
    /opt/continuent/tungsten/tungsten-replicator/bin/trepctl status

    4、當一些表里面存在特殊符號可能會導致同步出錯,可以在從服務器啟動的時候加上一下參數跳過同步的表
    --property=replicator.filter.replicate.ignore=zhongxin.zx_notice_req_log \

     
     
    如果在運行一段時間后,因為某些原因需要將數據抹掉重新同步的話,可以安裝一下的步驟
           1、停止從庫的主從同步,導出從庫中的所有數據,清空從庫;
           2、刪除mysql從庫的tungsten_mysql2mongodb庫
           3、刪除mongo的 tungsten_mysql2mongodb庫
           4、重啟啟動tungsten的主從同步(安裝啟動命令)
           5、將從庫導出的數據從新導入從庫
            6、啟動mysql主從同步。
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(6)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:15
    • Elasticsearch、Logstash、Kibana搭建統一日志分析平臺

    Source: http://www.cnblogs.com/ityouknow/p/4933103.html
    ELKstack是Elasticsearch、Logstash、Kibana三個開源軟件的組合。目前都在Elastic.co公司名下。
    ELK是一套常用的開源日志監控和分析系統,包括一個分布式索引與搜索服務Elasticsearch,
    一個管理日志和事件的工具logstash,和一個數據可視化服務Kibana
    logstash_1.5.3                  負責日志的收集,處理和儲存
    elasticsearch-1.7.2            負責日志檢索和分析
    kibana-4.1.2-linux-x64.tar.gz  負責日志的可視化
    redis-2.4.14                      DB以及日志傳輸的通道來處理
    用一張圖來表示他們之間的關系
    image
     
    此文以兩個服務器為例來部署
    服務器A:192.168.0.1  java elasticsearch redis kibana logstash(agent indexer)
    服務器B:192.168.0.2  java logstash(agent)
     
    首先安裝服務器A相關軟件
    一、安裝基礎軟件
    yum -y install curl wget lrzsz axel

     
    二、安裝配置redis服務
    1、安裝tcl8.6.1
    a) tar -xf tcl8.6.1-src.tar.gz --strip-components=1 
    b) cd tcl8.
    6.1/unix
    c) .
    /configure --prefix=/usr/local
    d) make
    e) make test
    f) make install
    g) make install
    -private-headers
    h) ln
    -v -sf tclsh8.6 /usr/bin/tclsh
    i) chmod
    -v 755 /usr/lib/libtcl8.6.so(可選,并且如報找不到文件,沒關系)

    2、安裝redis-3.0.2
    wget http://download.redis.io/releases/redis-3.0.2.tar.gz 

    tar xzf redis-3.0.2.tar.gz /usr/local/redis

    cd redis-3.0.2

    make MALLOC=libc

    make test

    make install 

    2、配置redis

    a) mkdir /etc/redis 


    b) mkdir /var/redis 


    c) cp utils/redis_init_script /etc/init.d/redis


    d) vim /etc/init.d/redis
    頭部添加:


    #chkconfig: 345 60 60


    #!/bin/bash


    e) mkdir /var/redis/6379 


    f) cp redis.conf /etc/redis/6379.conf


    g) vim /etc/redis/6379.conf
            #設置daemonize為yes
            #設置pidfile為/var/run/redis_6379.pid
            #設置loglevel
            #設置logfile為/var/log/redis_6379.log
            #設置dir為/var/redis/6379


    h) sysctl vm.overcommit_memory=1


    i) chkconfig --add redis


    j) chkconfig redis on


    3、重啟服務
    service redis start/stop

    4、查看進程和端口
    1)查看進程
    ps -ef |grep redis
    root
    31927 25099 0 18:26 pts/0 00:00:00 vi /etc/init.d/redis

    2)查看端口
    netstat -tupnl |grep redis
    tcp
    0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 31966/redis-server
    tcp
    0 0 :::6379 :::* LISTEN 31966/redis-server

     
    三、安裝java環境
    1、安裝包
    yum -y list java* 

    yum -y install openjdk-7-jdk

    2、查看版本
    java -version
    java version
    "1.7.0_91"
    OpenJDK Runtime Environment (rhel
    -2.6.2.2.el6_7-x86_64 u91-b00)
    OpenJDK
    64-Bit Server VM (build 24.91-b01, mixed mode)

     
    四、安裝elasticsearch
    1、下載elasticsearch
    wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.2.noarch.rpm

    2、安裝elasticsearch
    rpm -ivh elasticsearch-1.7.2.noarch.rpm

    3、配置
    1)備份配置
    cp /etc/elasticsearch/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml.bak

    2)修改配置
    echo "network.bind_host: 192.168.0.1" >> /etc/elasticsearch/elasticsearch.yml

    4、啟動elasticsearch服務
    /etc/init.d/elasticsearch start
    /etc/init.d/elasticsearch stop

    5、查看進程和端口
    1)查看進程
    ps -ef |grep java

    2)查看端口
    netstat -tupnl |grep java

    6、測試
    curl -X GET http://192.168.54.147:9200
    {
    "status" : 200,
    "name" : "Miguel O'Hara",
    "cluster_name" : "elasticsearch",
    "version" : {
    "number" : "1.7.2",
    "build_hash" : "e43676b1385b8125d647f593f7202acbd816e8ec",
    "build_timestamp" : "2015-09-14T09:49:53Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.4"
    },
    "tagline" : "You Know, for Search"
    }

    7、添加到開機啟動
    update-rc.d elasticsearch defaults
    update
    -rc.d: using dependency based boot sequencing

     
    五、安裝logstash
    1、下載logstash
    wget https://download.elastic.co/logstash/logstash/packages/centos/logstash-1.5.4-1.noarch.rpm

    2、安裝logstash
    rpm -ivh logstash-1.5.4-1.noarch.rpm

    3、配置(默認沒有這個配置文件)
    vim /etc/logstash/conf.d/logstash_indexer.conf
    input {
    redis {
    host
    => "192.168.0.1"
    data_type
    => "list"
    key
    => "logstash:redis"
    type
    => "redis-input"
    port
    => "6379"
    }
    }
    output {
    elasticsearch {
    host
    => "192.168.0.1"
    }
    }

    4、啟動服務
    /etc/init.d/logstash start

    5、使用jps -mlv或ps -ef來查看下進程
    ps -ef|grep logst

    6、設置開機啟動
    update-rc.d logstash defaults
    update
    -rc.d: using dependency based boot sequencing

     
    六、安裝kibana(前端web)
    1、下載
    wget https://download.elastic.co/kibana/kibana/kibana-4.1.2-linux-x64.tar.gz

    2、解壓到指定目錄
    tar zxvf kibana-4.1.2-linux-x64.tar.gz -C /opt

    3、創建日志目錄
    mkdir -p /opt/kibanalog

    4、配置
    1)備份配置
    cp /opt/kibana-4.1.2-linux-x64/config/kibana.yml /opt/kibana-4.1.2-linux-x64/config/kibana.yml.bak

    2)修改配置
    sed -i 's!^elasticsearch_url: .*!elasticsearch_url: "http://192.168.0.1:9200"!g' /opt/kibana-4.1.2-linux-x64/config/kibana.yml
    sed
    -i 's!^host: .*!host: "192.168.0.1"!g' /opt/kibana-4.1.2-linux-x64/config/kibana.yml

    5、啟動服務
    cd /opt/kibanalog && nohup /opt/kibana-4.1.2-linux-x64/bin/kibana &

    6、查看進程和端口
    1)查看進程
    ps aux |grep kibana

    2)查看端口
    netstat -tupnl|grep 5601

    7、在windows上訪問
    http://192.168.0.1:5601
    8、設置開機啟動
    echo "cd /opt/kibanalog && nohup /opt/kibana-4.1.2-linux-x64/bin/kibana &" >> /etc/rc.local

     
    到此服務器A的相關軟件全部安裝完成;
     
    現在安裝日志采集端的程序(服務器B),可以有多個
    clientB安裝配置logstash(agent)
    1、安裝java環境
    yum -y list java* 

    yum -y install openjdk-7-jdk

    1、下載logstash
    wget https://download.elastic.co/logstash/logstash/packages/centos/logstash-1.5.4-1.noarch.rpm

    2、安裝logstash
    rpm -ivh logstash-1.5.4-1.noarch.rpm

    3、配置(默認沒有這個配置文件)
    1)配置logstash_agent
    vim /etc/logstash/conf.d/logstash_agent.conf
    input {
    file {
    path
    => "/tmp/*.log"
    start_position
    => beginning
    }
    }
    output {
    redis {
    host
    => "192.168.0.1"
    data_type
    => "list"
    key
    => "logstash:redis"
    }
    }

    5、啟動服務

    /etc/init.d/logstash start
    logstash started.

    6、使用jps -mlv或ps -ef來查看下進程
    ps -ef|grep logst

    7、設置開機啟動
    update-rc.d logstash defaults
    update
    -rc.d: using dependency based boot sequencing

     
    至此服務器B也安裝配置完成,根據日志采集端的需要可以配置N個服務B
     
    如何查看日志:
    1、查看redis日志
    cat /var/log/redis/redis-server.log

    2、查看elasticsearch日志
    cat /var/log/elasticsearch/elasticsearch.log
    tail
    -300f /var/log/elasticsearch/elasticsearch.log

    3、查看logstash日志
    cat /var/log/logstash/logstash.errtail -30f /var/log/logstash/logstash.err

    4、查看kibana日志
    cat /opt/kibanalog/nohup.out
    tail
    -30f /opt/kibanalog/nohup.out

     
     
    錯誤處理
    1)unable to fetch mapping, do you have indices matching the pattem?
    kibana 報這個錯誤就是因為沒有從logstash 過來任何數據一般檢查一下數據傳輸
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(15)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:14
    • spring 多數據源一致性事務方案


    Source: http://www.cnblogs.com/ityouknow/p/4977136.html
    spring 多數據源配置
    spring 多數據源配置一般有兩種方案:
    1、在spring項目啟動的時候直接配置兩個不同的數據源,不同的sessionFactory。在dao 層根據不同業務自行選擇使用哪個數據源的session來操作。
    2、配置多個不同的數據源,使用一個sessionFactory,在業務邏輯使用的時候自動切換到不同的數據源,有一個種是在攔截器里面根據不同的業務現切換到不同的datasource;有的會在業務層根據業務來自動切換。但這種方案在多線程并發的時候會出現一些問題,需要使用threadlocal等技術來實現多線程競爭切換數據源的問題。
     
    【本文暫時只討論第一種方案】
    spring多事務配置主要體現在db配置這塊,配置不同的數據源和不同的session
    1、一下貼出 spring-db.xml配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context
    ="http://www.springframework.org/schema/context"
    xmlns:aop
    ="http://www.springframework.org/schema/aop"
    xmlns:tx
    ="http://www.springframework.org/schema/tx"
    xsi:schemaLocation
    ="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
    >
    <bean id="test1DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
    <property name="driverClassName" value="${database.test1.driverClassName}" />
    <property name="url" value="${database.test1.url}" />
    <property name="username" value="${database.test1.username}" />
    <property name="password" value="${database.test1.password}" />
    </bean>
    <bean id="test2DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
    <property name="driverClassName" value="${database.test2.driverClassName}" />
    <property name="url" value="${database.test2.url}" />
    <property name="username" value="${database.test2.username}" />
    <property name="password" value="${database.test2.password}" />
    </bean>
    <bean id="test1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="test1DataSource" />
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
    <property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
    </bean>
    <bean id="test2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="test2DataSource" />
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
    <property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
    </bean>
    <bean id="test1TxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="test1DataSource"></property>
    </bean>
    <bean id="test2TxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="test2DataSource"></property>
    </bean>
    <tx:annotation-driven transaction-manager="test2TxManager" />
    <tx:annotation-driven transaction-manager="test1TxManager" />
    </beans>

     
    2、dao層做了一個小的封裝,將不同的SqlSessionFactory 注入到 SessionFactory,通過BaseDao來做簡單的封裝,封裝不同庫的基本增刪改。dao實現層都集成于Basedao 這樣的話,實現可以根據自己需要來選擇不同的庫來操作不同的內容。
    session工廠
    package com.neo.dao;
    import com.neo.entity.Entity;
    public class BaseDao extends SessionFactory{
    public void test1Update(Entity entity) {
    this.getTest1Session().update(entity.getClass().getSimpleName()+".update", entity);
    }
    public void test2Update(Entity entity) {
    this.getTest2Session().update(entity.getClass().getSimpleName()+".update", entity);
    }
    }

    BaseDao
    package com.neo.dao;
    import com.neo.entity.Entity;
    public class BaseDao extends SessionFactory{
    public void test1Update(Entity entity) {
    this.getTest1Session().update(entity.getClass().getSimpleName()+".update", entity);
    }
    public void test2Update(Entity entity) {
    this.getTest2Session().update(entity.getClass().getSimpleName()+".update", entity);
    }
    }

     
    代碼地址:https://github.com/ityouknow/spring-mybatis-mulidatasource/tree/master/spring-mybatis
     
    以上的配置在多數據源連接,正常的增刪改都是沒有問題的,但是遇到分布式的事務是就出問題:
    測試代碼:
    package com.neo.service.impl;
    import javax.annotation.Resource;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import com.neo.dao.UserDao;
    import com.neo.dao.UserInformationsDao;
    import com.neo.entity.UserEntity;
    import com.neo.entity.UserInformationsEntity;
    import com.neo.service.UserService;
    @Service
    public class UserServiceImpl implements UserService {
    @Resource UserDao userDao;
    @Resource UserInformationsDao userInformationsDao;
    @Override
    @Transactional
    public void updateUserinfo() {
    UserEntity user=new UserEntity();
    user.setId(1);
    user.setUserName("李四4");
    UserInformationsEntity userInfo=new UserInformationsEntity();
    userInfo.setUserId(1);
    userInfo.setAddress("陜西4");
    userDao.updateUser(user);
    userInformationsDao.updateUserInformations(userInfo);
    if(true){
    throw new RuntimeException("test tx ");
    }
    }
    }

     
    在service添加事務后,更新完畢拋出異常,test2更新進行了回滾,test1 數據更新沒有回滾。
     
    解決方案添加分布式的事務,Atomikos和spring結合來處理。
    Atomikos多數據源的配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context
    ="http://www.springframework.org/schema/context"
    xmlns:aop
    ="http://www.springframework.org/schema/aop"
    xmlns:tx
    ="http://www.springframework.org/schema/tx"
    xsi:schemaLocation
    ="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
    >
    <bean id="test1DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="test1"/>
    <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
    <property name="xaProperties">
    <props>
    <prop key="url">${database.test1.url}</prop>
    <prop key="user">${database.test1.username}</prop>
    <prop key="password">${database.test1.password}</prop>
    </props>
    </property>
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="100" />
    <property name="borrowConnectionTimeout" value="30" />
    <property name="testQuery" value="select 1" />
    <property name="maintenanceInterval" value="60" />
    </bean>
    <bean id="test2DataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="test2"/>
    <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
    <property name="xaProperties">
    <props>
    <prop key="url">${database.test2.url}</prop>
    <prop key="user">${database.test2.username}</prop>
    <prop key="password">${database.test2.password}</prop>
    </props>
    </property>
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="100" />
    <property name="borrowConnectionTimeout" value="30" />
    <property name="testQuery" value="select 1" />
    <property name="maintenanceInterval" value="60" />
    </bean>
    <bean id="test1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="test1DataSource" />
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
    <property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
    </bean>
    <bean id="test2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="test2DataSource" />
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
    <property name="mapperLocations" value="classpath*:mybatis/mapper/*.xml" />
    </bean>
    <!-- 分布式事務 -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
    <property name="forceShutdown" value="true"/>
    </bean>
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    <property name="transactionTimeout" value="300"/>
    </bean>
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="atomikosTransactionManager"/>
    <property name="userTransaction" ref="atomikosUserTransaction"/>
    </bean>
    <tx:annotation-driven/>
    </beans>

     
    添加完分布式的項目地址:
    https://github.com/ityouknow/spring-mybatis-mulidatasource/tree/master/spring-mybatis-atomikos
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(3)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:14
    • spring帝國-開篇

    Source: http://www.cnblogs.com/ityouknow/p/5292559.html

     spring簡介:


        spring是一個開源框架,spring是于2003 年興起的一個輕量級的Java 開發框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。它是為了解決企業應用開發的復雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件,同時為 J2EE 應用程序開發提供集成的框架。從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從spring中受益。spring的核心是控制反轉(IoC)和面向切面(AOP)。簡單來說,spring是一個分層的JavaSE/EEfull-stack(一站式) 輕量級開源框架。


     


       在開發人員的眼中spring是帝國一樣的存在,幾乎個個領域的技術都有spring的解決方案并且在基礎框架選型為spring后,后續相關的解決方案幾乎都是優先選擇spring相關組件,因此抽出時間來對常用的spring組件和原理進行學習、總結。


     


    wps626E.tmp


     


    spring ioc:IOC是Inversion of Control的縮寫,多數書籍翻譯成“控制反轉”,還有些書籍翻譯成為“控制反向”或者“控制倒置”。本來是由應用程序管理的對象之間的依賴關系,現在交給了容器管理,這就叫控制反轉,即交給了IOC容器,spring的IOC容器主要使用DI方式實現的。不需要主動查找,對象的查找、定位和創建全部由容器管理。spring ioc 是spring的核心,在spring中主要用戶管理容器中的bean。


     


    spring aop:AOP是OOP的延續,是Aspect Oriented Programming的縮寫,意思是面向方面編程。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,AOP可以說也是這種目標的一種實現。spring aop 也是spring的核心,利用aop的技術可以用來做日志、權限、緩存等功能實現


     


    spring orm:spring支持大多數ORM框架,比如Hibernate,JPA,JDO,TopLink和iBatis(spring2支持iBatis2,現MyBatis3的spring支持由MyBatis社區開發,并非spring)。


     


    spring mvc:spring MVC框架是有一個MVC框架,通過實現Model-View-Controller模式來很好地將數據、業務與展現進行分離。從這樣一個角度來說,spring MVC和Struts、Struts2非常類似。


     


    spring webservice:spring 支持集成Apache cxf、axis2、xfire等不同集中webservice實現方案。


     


    spring transaction:spring完美的支持了對事物的管理,目前主要有兩種實現發難,一種是配置文件、一種是基于注解來實現。


     


    spring jms:spring支持對activemq、RabbitMQ消息中間件的集成。


     


    spring data:spring Data 作為springSource的其中一個父項目, 旨在統一和簡化對各類型持久化存儲, 而不拘泥于是關系型數據庫還是NoSQL 數據存儲。


     


    spring cache:spring 的緩存技術還具備相當的靈活性,不僅能夠使用 SpEL(spring Expression Language)來定義緩存的 key 和各種 condition,還提供開箱即用的緩存臨時存儲方案,也支持和主流的專業緩存例如 EHCache 集成。


     


    spring boot:spring-boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Boot致力于在蓬勃發展的快速應用開發領域(rapid application development)成為領導者。


     


    spring security:spring Security是一個能夠為基于spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在spring應用上下文中配置的Bean,充分利用了spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。


     


    spring schedule:spring在schedule這塊支持JDK Timer、concurrent、quartz三種,這三種任務調度方案在實現機制和調用方法上都不同,但spring通過對其包裝,使得基于spring能用統一的配置和編碼風格來使用這三種schedule方案。


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(4)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:14
    • spring ioc


    Source: http://www.cnblogs.com/ityouknow/p/5311360.html


    spring ioc是spring的核心之一,也是spring體系的基礎,那么spring ioc所依賴的底層技術是什么的?反射,以前我們開發程序的時候對象之間的相互調用需要用new來實現,現在所有的bean都是通過spring容器來管理。這樣做有什么好處呢?解耦!以前程序直接的調用用new直接給寫死了,現在我們可以通過注入不同的接口實現類來完成對象直接的調用。


     


    首先來聊聊Java的反射機制


    1、反射機制的作用:


      反編譯:.class-->.java


      通過反射機制訪問java對象的屬性,方法,構造方法等;


    2、Java反射機制用途:


      在運行時判斷任意一個對象所屬的類


      在運行時構造任意一個類的對象


      在運行時判斷任意一個類所具有的成員變量和方法


      在運行時調用任意一個對象的方法


    3、sun為我們提供了那些反射機制中的類:



     java.lang.Class; 
    java.lang.reflect.Constructor;
    java.lang.reflect.Field;
    java.lang.reflect.Method;
    java.lang.reflect.Modifier;


    4、反射實現的方式



    Class c=Class.forName("className");
    注明:className必須為全名,也就是得包含包名,比如,cn.xx.UserInfo;
    Object obj
    =c.newInstance();
    //創建對象的實例

    Constructor getConstructor(Class[] params)
    //根據指定參數獲得public構造器

    Constructor[] getConstructors()
    //獲得public的所有構造器

    Constructor getDeclaredConstructor(Class[] params)
    //根據指定參數獲得public和非public的構造器

    Constructor[] getDeclaredConstructors()
    //獲得public的所有構造器

    ewInstance();
    //創建對象的實例

    獲得類方法的方法
    Method getMethod(String name, Class[] params),
    根據方法名,參數類型獲得方法
    Method[] getMethods()
    //獲得所有的public方法

    Method getDeclaredMethod(String name, Class[] params)
    //根據方法名和參數類型,獲得public和非public的方法

    Method[] getDeclaredMethods()
    //獲得所以的public和非public方法

    獲得類中屬性的方法
    Field getField(String name)
    //根據變量名得到相應的public變量

    Field[] getFields()
    //獲得類中所以public的方法

    Field getDeclaredField(String name)
    //根據方法名獲得public和非public變量

    Field[] getDeclaredFields()
    //獲得類中所有的public和非public方法


     


    總結一句,以前寫的代碼,類的熟悉、方法什么東西的都固定了,如果使用反射我們就可以在運行的時候動態的去修改、增刪對象的熟悉、方法等等。


     


    spring IOC是如果使用反射來完成對象的注入呢?


    1、讀取配置文件,或者掃描注解屬性


    2、根據配置文件,通過反射實例化對象


    3、給對象注入依賴的屬性


    4、放到類似hashMap結構中,供系統調用


     



    /**
    * 學習版容器
    *
    */

    public class LeamClassPathXMLApplicationContext {
    private List<Definition> beanDefines = new ArrayList<Definition>();
    private Map<String, Object> sigletons = new HashMap<String, Object>();
    public LeamClassPathXMLApplicationContext(String filename){
    this.readXML(filename);
    this.instanceBeans();
    this.injectObject();
    }
    /**
    * 為bean對象的屬性注入值
    */
    private void injectObject() {
    for(Definition beanDefinition : beanDefines){
    Object bean
    = sigletons.get(beanDefinition.getId());
    if(bean!=null){
    try {
    PropertyDescriptor[] ps
    = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
    for(ProsDefinition propertyDefinition : beanDefinition.getPropertys()){
    for(PropertyDescriptor properdesc : ps){
    if(propertyDefinition.getName().equals(properdesc.getName())){
    Method setter
    = properdesc.getWriteMethod();//獲取屬性的setter方法
    if(setter!=null){
    Object value
    = sigletons.get(propertyDefinition.getRef());
    setter.setAccessible(
    true);
    setter.invoke(bean, value);
    //把引用對象注入到屬性 }
    break;
    }
    }
    }
    }
    catch (Exception e) {
    }
    }
    }
    }
    /**
    * 完成bean的實例化
    */
    private void instanceBeans() {
    for(Definition beanDefinition : beanDefines){
    try {
    if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
    sigletons.put(beanDefinition.getId(),
    Class.forName(beanDefinition.getClassName()).newInstance());
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    /**
    * 讀取xml配置文件
    *
    @param filename
    */
    private void readXML(String filename) {
    SAXReader saxReader
    = new SAXReader();
    Document document
    =null;
    try{
    URL xmlpath
    = this.getClass().getClassLoader().getResource(filename);
    document
    = saxReader.read(xmlpath);
    Map
    <String,String> nsMap = new HashMap<String,String>();
    nsMap.put(
    "ns","http://www.springframework.org/schema/beans");//加入命名空間
    XPath xsub = document.createXPath("//ns:beans/ns:bean");//創建beans/bean查詢路徑
    xsub.setNamespaceURIs(nsMap);
    //設置命名空間
    List<Element> beans = xsub.selectNodes(document);//獲取文檔下所有bean節點
    for(Element element: beans){
    String id
    = element.attributeValue("id");//獲取id屬性值
    String clazz = element.attributeValue("class"); //獲取class屬性值
    Definition beanDefine = new Definition(id, clazz);
    XPath propertysub
    = element.createXPath("ns:property");
    propertysub.setNamespaceURIs(nsMap);
    //設置命名空間
    List<Element> propertys = propertysub.selectNodes(element);
    for(Element property : propertys){
    String propertyName
    = property.attributeValue("name");//元素內部引用的屬性也獲取
    String propertyref = property.attributeValue("ref");
    ProsDefinition propertyDefinition
    = new ProsDefinition(propertyName, propertyref);
    beanDefine.getPropertys().add(propertyDefinition);
    }
    beanDefines.add(beanDefine);
    }
    }
    catch(Exception e){
    e.printStackTrace();
    }

     }
    /**
    * 獲取bean實例
    *
    @param beanName
    *
    @return
    */
    public Object getBean(String beanName){
    return this.sigletons.get(beanName);
    }
    }


     


    spring ioc核心思想


    ioc的思想最核心的地方在于,資源不由使用資源的雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處。第一,資源集中管理,實現資源的可配置和易管理。第二,降低了使用資源雙方的依賴程度,也就是我們說的耦合度。


     


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(7)

    • 個人分類:生活學習
    ▲top
    • 3月 07 週二 201721:14
    • spring aop


    Source: http://www.cnblogs.com/ityouknow/p/5329550.html


    什么是AOP


    AOP(Aspect-OrientedProgramming,面向方面編程),它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。


     


    AOP使用場景


    AOP用來封裝橫切關注點,具體可以在下面的場景中使用:


    Authentication 權限


    Caching 緩存


    Context passing 內容傳遞


    Error handling 錯誤處理


    Lazy loading 懶加載


    Debugging  調試


    logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準


    Performance optimization 性能優化


    Persistence  持久化


    Resource pooling 資源池


    Synchronization 同步


    Transactions 事務


     


    Spring AOP底層技術


     


    Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。默認的策略是如果目標類是接口,則使用JDK動態代理技術,否則使用Cglib來生成代理。


     


    動態代理利用反射的原理,給對象動態的生產代理對象,在執行的方法前后來執行相關內容:



    /**
    * 動態代理類
    *
    * @author yanbin
    *
    */
    public class DynamicProxy implements InvocationHandler {
    /** 需要代理的目標類 */
    private Object target;

    /**
    * 寫法固定,aop專用:綁定委托對象并返回一個代理類
    *
    * @param delegate
    * @return
    */
    public Object bind(Object target) {
    this.target
    = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    /**
    * @param Object
    * target:指被代理的對象。
    * @param Method
    * method:要調用的方法
    * @param Object
    * [] args:方法調用時所需要的參數
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result
    = null;
    // 切面之前執行
    System.out.println(
    "切面之前執行");
    // 執行業務
    result
    = method.invoke(target, args);
    // 切面之后執行
    System.out.println(
    "切面之后執行");
    return result;
    }
    }


    CGLIB是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強。采用的是繼承的方式



    /**
    * 使用cglib動態代理
    *
    *
    @author yanbin
    *
    */
    public class CglibProxy implements MethodInterceptor {
    private Object target;
    /**
    * 創建代理對象
    *
    *
    @param target
    *
    @return
    */
    public Object getInstance(Object target) {
    this.target = target;
    Enhancer enhancer
    = new Enhancer();
    enhancer.setSuperclass(
    this.target.getClass());
    // 回調方法
    enhancer.setCallback(this);
    // 創建代理對象
    return enhancer.create();
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object result
    = null;
    System.out.println(
    "事物開始");
    result
    = methodProxy.invokeSuper(proxy, args);
    System.out.println(
    "事物結束");
    return result;
    }
    }


     


     


    AOP相關概念


    方面(Aspect):一個關注點的模塊化,這個關注點實現可能另外橫切多個對象。事務管理是J2EE應用中一個很好的橫切關注點例子。方面用Spring的 Advisor或攔截器實現。


     


    連接點(Joinpoint): 程序執行過程中明確的點,如方法的調用或特定的異常被拋出。


     


    通知(Advice): 在特定的連接點,AOP框架執行的動作。各種類型的通知包括“around”、“before”和“throws”通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護一個“圍繞”連接點的攔截器鏈。Spring中定義了四個advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice


     


    切入點(Pointcut): 指定一個通知將被引發的一系列連接點的集合。AOP框架必須允許開發者指定切入點:例如,使用正則表達式。 Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,可以通過名字很清楚的理解, MethodMatcher是用來檢查目標類的方法是否可以被應用此通知,而ClassFilter是用來檢查Pointcut是否應該應用到目標類上


     


    引入(Introduction): 添加方法或字段到被通知的類。 Spring允許引入新的接口到任何被通知的對象。例如,你可以使用一個引入使任何對象實現 IsModified接口,來簡化緩存。Spring中要使用Introduction, 可有通過DelegatingIntroductionInterceptor來實現通知,通過DefaultIntroductionAdvisor來配置Advice和代理類要實現的接口


     


    目標對象(Target Object): 包含連接點的對象。也被稱作被通知或被代理對象。POJO


     


    AOP代理(AOP Proxy): AOP框架創建的對象,包含通知。 在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。


     


    織入(Weaving): 組裝方面來創建一個被通知對象。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在運行時完成。Spring和其他純Java AOP框架一樣,在運行時完成織入。


     


    幾種實現方式


    1、基于代理的AOP


    2、純簡單java對象切面


    3、@Aspect注解形式的


    4、注入形式的Aspcet切面


     


    面先寫一下幾個基本的類。


    接口類:



    /**
    * 定義一個接口
    *
    @author 陳麗娜
    *
    @version 2015年5月31日上午9:16:50
    */
    public interface Sleepable {
    /**
    * 睡覺方法
    *
    @author 陳麗娜
    *
    @version 2015年5月31日上午9:17:14
    */
    void sleep();
    }


    實現類:



    /**
    * 陳麗娜 本人實現睡覺接口
    *
    @author 陳麗娜
    *
    @version 2015年5月31日下午4:51:43
    */
    public class ChenLliNa implements Sleepable {
    @Override
    public void sleep() {
    // TODO Auto-generated method stub
    System.out.println("乖,該睡覺了!");
    }
    }


     


    增強類:



    /**
    * 定義一個睡眠的增強 同時實現前置 和后置
    *
    @author 陳麗娜
    *
    @version 2015年5月31日上午9:24:43
    */
    public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable {
    System.out.println(
    "睡覺前要敷面膜");
    }
    @Override
    public void before(Method method, Object[] args, Object target)throws Throwable {
    System.out.println(
    "睡覺后要做美夢");
    }
    }


     


    1、基于代理的AOP



    <!-- 創建一個增強 advice -->
    <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper"/>
    <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>
    <!-- 定義切點 匹配所有的sleep方法-->
    <bean id ="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="pattern" value=".*sleep"></property>
    </bean>
    <!-- 切面 增強+切點結合 -->
    <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="advice" ref="sleepHelper"/>
    <property name="pointcut" ref="sleepPointcut"/>
    </bean>
    <!-- 定義代理對象 -->
    <bean id="linaProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="lina"/>
    <property name="interceptorNames" value="sleepHelperAdvisor"/>
    </bean>


     


    如配置文件中:


    pattern屬性指定了正則表達式,他匹配所有的sleep方法


    使用org.springframework.aop.support.DefaultPointcutAdvisor的目的是為了使切點和增強結合起來形成一個完整的切面


    最后配置完后通過org.springframework.aop.framework.ProxyFactoryBean產生一個最終的代理對象。


     


    2、純簡單java對象切面


    純簡單java對象切面這話怎么說呢,在我看來就是相對于第一種配置,不需要使用代理,,而是通過spring的內部機制去自動掃描,這時候我們的配置文件就該如下修改:



    <!-- 創建一個增強 advice -->
    <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper"/>
    <!-- 目標類 -->
    <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>
    <!-- 配置切點和通知-->
    <bean id ="sleepAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref="sleepHelper"></property>
    <property name="pattern" value=".*sleep"/>
    </bean>
    <!-- 自動代理配置 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>


    是不是相對于第一種簡單了許多,不用再去配置代理了。


     


    3、@Aspect注解形式


    根據我們的經驗也知道,注解的形式相對于配置文件是簡單一些的,這時候需要在已有的方法或類上家注解:



    /**
    * 通過注解的方式 添加增強
    *
    @author 陳麗娜
    *
    @version 2015年5月31日上午10:26:13
    */
    @Aspect
    @Component
    public class SleepHelper03 {

    /*@Pointcut("execution(* com.tgb.springaop.service.impl..*(..))")*/
    @Pointcut(
    "execution(* *.sleep(..))")
    public void sleeppoint(){}
    @Before(
    "sleeppoint()")
    public void beforeSleep(){
    System.out.println(
    "睡覺前要敷面膜");
    }
    @AfterReturning(
    "sleeppoint()")
    public void afterSleep(){
    System.out.println(
    "睡覺后要做美夢");
    }


     


    配置文件中只需寫:



    <!--掃描包 -->
    <context:component-scan base-package="com.tgb" annotation-config="true"/>
    <!-- ASPECTJ注解 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <!-- 目標類 -->
    <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>


     


    4、注入形式的Aspcet切面


    個人感覺這個是最簡單的也是最常用的,也是最靈活的。配置文件如下:



    <!-- 目標類 -->
    <bean id="lina" class="com.tgb.springaop.service.impl.ChenLliNa"/>
    <bean id ="sleepHelper" class="com.tgb.springaop.aspect.SleepHelper02"/>
    <aop:config>
    <aop:aspect ref="sleepHelper">
    <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))"/>
    <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))"/>
    </aop:aspect>
    </aop:config>


    配置文件中提到的SleepHelper02類如下:



    /**
    * 通過注解的方式 添加增強
    * @author 陳麗娜
    * @version 2015年5月31日上午10:26:13
    */
    public class SleepHelper02 {
    public void beforeSleep(){
    System.out.println("睡覺前要敷面膜");
    }
    public void afterSleep(){
    System.out.println("睡覺后要做美夢");
    }
    }


     


    參考:http://itindex.net/detail/53556-spring-aop


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(3)

    • 個人分類:生活學習
    ▲top
    «1...228229230»

    pop-under

    參觀人氣

    • 本日人氣:
    • 累積人氣:

    線上人數

    Marquee

    最新文章

    • 文章列表
    • jvm系列(四):jvm調優-命令大全(jps jstat jmap jhat jstack jinfo)
    • spring boot(一):入門篇
    • jvm系列(一):java類的加載機制
    • jvm系列(三):java GC算法 垃圾收集器
    • spring boot 實戰:我們的第一款開源軟件
    • jvm系列(六):jvm調優-從eclipse開始
    • 混合應用技術選型
    • jvm系列(二):JVM內存結構
    • spring boot(五):spring data jpa的使用

    熱門文章

    • (1,762)jQuery之前端國際化jQuery.i18n.properties
    • (630)技術筆記:Indy控件發送郵件
    • (513)linux下安裝sqlite3
    • (501)學習筆記: Delphi之線程類TThread
    • (242)VC單選按鈕控件(Radio Button)用法(轉)
    • (149)Android AppBar
    • (103)單條件和多條件查詢
    • (50)淺談config文件的使用
    • (26)Tomcat shutdown執行后無法退出進程問題排查及解決
    • (22)基于 Asp.Net的 Comet 技術解析

    文章分類

    • 生活學習 (2,296)
    • 未分類文章 (1)

    最新留言

    • [20/04/24] 我是女生想約炮 有男生願意給我溫暖的嗎?我賴是woyou58 於文章「(1)從底層設計,探討插件式GIS框架的...」留言:
      我叫黎兒女生最近內心掙扎著要不要約炮我的line:woy...

    文章搜尋

    文章精選

    誰來我家

    Live Traffic Feed