欧美色欧美亚洲高清在线观看,国产特黄特色a级在线视频,国产一区视频一区欧美,亚洲成a 人在线观看中文

  1. <ul id="fwlom"></ul>

    <object id="fwlom"></object>

    <span id="fwlom"></span><dfn id="fwlom"></dfn>

      <object id="fwlom"></object>

      Linux操作系統(tǒng)的權(quán)限代碼分析

      時間:2019-05-12 04:07:04下載本文作者:會員上傳
      簡介:寫寫幫文庫小編為你整理了多篇相關(guān)的《Linux操作系統(tǒng)的權(quán)限代碼分析》,但愿對你工作學(xué)習(xí)有幫助,當然你在寫寫幫文庫還可以找到更多《Linux操作系統(tǒng)的權(quán)限代碼分析》。

      第一篇:Linux操作系統(tǒng)的權(quán)限代碼分析

      現(xiàn)在關(guān)于內(nèi)核的書很少涉及到Linux內(nèi)核的安全,內(nèi)核安全大概包括了密碼學(xué)實現(xiàn)(crypto)和訪問控制(security)兩個部分。安全系 統(tǒng)作為Linux內(nèi)核的一個重要的子系統(tǒng),已經(jīng)為我們提供了很多的相關(guān)接口,這里我們就對安全訪問控制做一個簡要的分析和介紹。訪問控制的原理注定要和虛擬文件系統(tǒng)和進程管理有著非常緊密的聯(lián)系,因為作為用戶主體的表現(xiàn)形式就是進程,而作為資源客體對象的表現(xiàn)形式就是文件,而訪問 控制就是如何實現(xiàn)正確的用戶可以訪問正確的資源。Linux能夠提供給我們許多可信的方式來處理這樣的問題。

      初始化工作

      這個初始化工作在init/main.c中的start_kernel()中security_init()定義了,其具體的實現(xiàn)是在security/security.c中:

      int __init security_init(void){ printk(KERN_INFO “Security Framework v” SECURITY_FRAMEWORK_VERSION “ initialized/n”);if(verify(&dummy_security_ops)){ printk(KERN_ERR “%s could not verify ” “dummy_security_ops structure./n”, __FUNCTION__);return-EIO;} security_ops = &dummy_security_ops;do_security_initcalls();return 0;} 這個函數(shù)首先用verify來驗證所指定的訪問控制策略(dummy_security_ops)是否為空,如果為空就按“保持默認”的方式進行分 配,這里的“保持沉默”就是對于任何的訪問控制采取不管不問的方式處理了。然后就是把dummy_security_ops指定給系統(tǒng)全局安全策略 security_ops。

      訪問控制策略的相關(guān)接口

      關(guān)于這些接口就是定義在了include/linux/security.h中的security_operations,包括如下一些操作:當父 進程trace子進程時進行的權(quán)限檢查,對權(quán)能的獲取、設(shè)置檢查、設(shè)置、有效性檢查,對進程做審計的檢查,當某個操作使用一般系統(tǒng)接口表時需要的權(quán)限檢 查,當使用內(nèi)核消息環(huán)或改變登錄終端時需要的權(quán)限檢查,當改變系統(tǒng)時間需要的檢查,當分配一個新的虛擬內(nèi)存頁需要的權(quán)限檢查,當執(zhí)行二進制程序時需要的各 種權(quán)限分配和檢查,對文件系統(tǒng)操作時需要的各種訪問控制操作,對inode索引節(jié)點操作時需要的各種訪問控制操作,對文件操作時的各種訪問控制操作,對進 程操作的需要的各種訪問控制操作,對進程間通信信號燈的權(quán)限控制,對消息隊列的控制,對進程間通信的共享內(nèi)存區(qū)域的控制,對網(wǎng)絡(luò)消息處理需要的各種控制,注冊與撤銷訪問控制策略,對網(wǎng)絡(luò)連接的控制,對套接字的各種控制,對IPSEC中xfrm用戶自定義策略的分配,密鑰管理的控制等等,幾乎囊括了系統(tǒng)各種 行為的控制。

      權(quán)限管理

      虛擬文件系統(tǒng)為各種類型的文件系統(tǒng)提供統(tǒng)一的操作接口,同時這樣的做法也可以簡化文件權(quán)限的管理。那么Linux時如何巧妙地實現(xiàn)這種想法呢?Linux 采用的是基于列的ACL自主訪問控制,即在每個文件里存儲對本文件的訪問權(quán)限信息,這里我們采用索引節(jié)點inode(定義在 include/linux/fs.h)作為切入點進行分析。在inode結(jié)構(gòu)體中有i_uid和i_gid元素,還有一個i_mode元素。這個 i_mode是16位的無符號整數(shù)表示,由9位權(quán)限方式位、3位“粘滯”標志位和4位文件類型標志位,它們的具體的定義在 include/linux/stat.h中:

      #define S_IFMT 00170000 /* 用于抽取i_mode域中類型部分的屏蔽位 */ #define S_IFSOCK 0140000 /* 套接字類型碼 */ #define S_IFLNK 0120000 /* 符號連接類型碼 */ #define S_IFREG 0100000 /* 普通文件類型碼 */ #define S_IFBLK 0060000 /* 塊特別文件類型碼 */ #define S_IFDIR 0040000 /* 目錄文件類型碼 */ #define S_IFCHR 0020000 /* 字符特別文件類型碼 */ #define S_IFIFO 0010000 /* 管道或FIFO類型碼 */ #define S_ISUID 0004000 /* 用戶粘滯位 */ #define S_ISGID 0002000 /* 用戶組粘滯位 */ #define S_ISVTX 0001000 /* 粘滯位 */ #define S_IRWXU 00700 /* 用戶讀寫執(zhí)行 */ #define S_IRUSR 00400 /* 用戶讀 */ #define S_IWUSR 00200 /* 用戶寫 */ #define S_IXUSR 00100 /* 用戶執(zhí)行 */ #define S_IRWXG 00070 /* 用戶組讀寫執(zhí)行 */ #define S_IRGRP 00040 /* 用戶組讀 */ #define S_IWGRP 00020 /* 用戶組寫 */ #define S_IXGRP 00010 /* 用戶組執(zhí)行 */ #define S_IRWXO 00007 /* 其他用戶讀寫執(zhí)行 */ #define S_IROTH 00004 /* 其他用戶讀 */ #define S_IWOTH 00002 /* 其他用戶寫 */ #define S_IXOTH 00001 /* 其他用戶執(zhí)行 */ #define S_IRWXUGO(S_IRWXU|S_IRWXG|S_IRWXO)/* 全部用戶讀寫執(zhí)行 */ #define S_IALLUGO(S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)/* 全部用戶全部權(quán)限 */ #define S_IRUGO(S_IRUSR|S_IRGRP|S_IROTH)/* 全部用戶讀 */ #define S_IWUGO(S_IWUSR|S_IWGRP|S_IWOTH)/* 全部用戶寫 */ #define S_IXUGO(S_IXUSR|S_IXGRP|S_IXOTH)/* 全部用戶執(zhí)行 */ 同時,每個進程的task_struct中也有對應(yīng)的uid,euid,suid,fsuid,gid,egid,sgid,fsgid等元素,當用戶登錄系統(tǒng)就創(chuàng)建了一個shell進程,它從/etc/passwd中取得對應(yīng)用戶的uid和gid 來唯一標志這個用戶,以后所有的進程就代代相傳。當內(nèi)核在執(zhí)行用戶進程訪問文件的請求時就要對比進程的uid、gid與文件的訪問模式位,由此決定該進程 是否有對文件的操作權(quán)限。uid為零的用戶為超級用戶,可以對任何資源進行管理,當然這也導(dǎo)致了系統(tǒng)安全的不完備性。

      判定一個進程是否有對某個文件有某種訪問的主要工作是由fs/namei.c中的permission函數(shù)決定的,具體的實現(xiàn)方式如下,其中的mask參數(shù)是所要求的訪問方式位的標志位:

      int permission(struct inode *inode, int mask, struct nameidata *nd){ umode_t mode = inode->i_mode;int retval, submask;if(mask & MAY_WRITE){ //假如加載的文件系統(tǒng)是只讀的就不允許寫,比如是磁盤設(shè)備

      if(IS_RDONLY(inode)&&(S_ISREG(mode)|| S_ISDIR(mode)|| S_ISLNK(mode)))

      return-EROFS;//假如加載的文件系統(tǒng)是不可變的就不允許寫

      if(IS_IMMUTABLE(inode))return-EACCES;} //是否滿足可執(zhí)行

      if((mask & MAY_EXEC)&& S_ISREG(mode)&&(!(mode & S_IXUGO)||(nd && nd->mnt &&(nd->mnt->mnt_flags & MNT_NOEXEC))))return-EACCES;submask = mask & ~MAY_APPEND;//返回適應(yīng)的權(quán)限位

      if(inode->i_op && inode->i_op->permission)//交給了具體文件系統(tǒng)實現(xiàn),比如說ext3文件系統(tǒng)

      retval = inode->i_op->permission(inode, submask, nd);else //如果當前進程的fsuid與文件uid相同要比對文件屬主的權(quán)限,否則比對用戶組

      retval = generic_permission(inode, submask, NULL);if(retval)return retval;//返回適應(yīng)的訪問控制策略的權(quán)限位,比如說selinux return security_inode_permission(inode, mask, nd);}

      第二篇:機票操作系統(tǒng)代碼

      操作系統(tǒng)代碼

      1,查詢航班:AVH/緊跟輸入城市段、日期(數(shù)字)、月份(英文)后回車查看。如果查詢指定航空公司月份后加“/”再加航空公司代號。

      2,訂座:SD后緊跟序號計劃預(yù)定倉位跟人數(shù)后回車。(如果顯示JET代表待定航班)

      3.人名:NM1后緊跟客人姓名,如果多個個客人,人名雨人名之間用數(shù)字1隔開(國際航班必須輸入英文,中國人姓在前后加/,外國人名在前)

      4,聯(lián)系方式:CT后輸入聯(lián)系電話

      5,預(yù)留時間:TKTL/后跟幾點/日期月份BJS…(代碼)

      6,封口:@IK(封口號碼為5位數(shù)字)

      7,提記錄:RT后緊跟封口號碼

      8,取消訂票:XEPNR

      9,價格查詢:FD:城市段(只使用于國內(nèi)查詢)PAT:A 查國內(nèi)稅和價格

      10:查詢那些航空公司飛:SKPEK緊跟目的地

      11,查詢指定日期直達航班:AV:城市段/日期月份

      12,查詢經(jīng)停點:IT:航班號/日期月份

      13,查詢航班經(jīng)停的城市起降時間和機型:FF:航班號/日期月份(沒有經(jīng)停的不顯示)14,查稅(價格):QTE:/承運人(航空公司)(必須輸入完行程封口或達到上面第二步),如果出來很多倉位,在輸入XSFSQ后跟代表倉位代碼的序號。(共享的航班不能查稅)15, 查詢學(xué)生機票的稅和價格QTE:SD/航空公司

      16,查詢移民機票價:QTE:EM/航空公司

      17,查詢青年機票價格:QTE:ZZ/航空公司

      18,OPE票的預(yù)定指令:SN:承運人---艙位---出發(fā)地與目的地

      19,查詢SPA價格的指令:NFAD:城市段/CA(只能用于國航聯(lián)運協(xié)議的航空公司。國際段的查詢)

      20,查匯率:XS(空格跟FSC后跟幣種代碼/人民幣(可以互換)

      21,查代碼代表城市:CD:跟城市代碼

      22,用姓名查找記錄:RT/旅客姓的拼音/航班號/日月年

      23,SK:城市段/日期 查詢在特定周期內(nèi)所有航班的信息,所顯示的航班信息時間為指定時間的前后三天一周的時間

      24,查看是否出票:提記錄后,輸入PG1回車,有票號證明已經(jīng)出票完畢。

      25,查詢國際段航班價格指令:XSFSD(空格)行程/日期/航空公司,如果后加X,最便宜的會顯示在最前面。

      26,如果沒有艙位需要候補艙位:SD后跟序號在跟艙位/LL后跟人數(shù)

      CP全清屏I清上次屏PN下翻PB上翻PF最前頁PG重新顯示當前頁PL最后頁。Q值的計算方法:Q值乘以兌換率。(如果使用系統(tǒng)里票面價格的時候不用單獨計算Q值,因為系統(tǒng)里的報價已經(jīng)包含全部費用,如果使用促銷價即不使用系統(tǒng)里顯示的價格的時候要計算Q值再加稅)

      學(xué)生票:LH的Q艙位UA的V艙位 大部分情況下代表學(xué)生票

      外航(例如:AC,UA,NW等)大部分是Q票面,(國際段的價格票面應(yīng)該以做境外段的票務(wù)公司報出的價格為準)國航的價格看系統(tǒng)或大本政策。去往北美洲國航聯(lián)運的比較AC,UA等轉(zhuǎn)機的價格略高。去往歐洲的國航相對法航的要便宜,HU飛日本韓國便宜 去往東南亞國家南航便宜,北京去往韓國MU,北京到香港CZ便宜

      第三篇:操作系統(tǒng)課程設(shè)計題目及代碼

      題目一

      模擬操作系統(tǒng)設(shè)計

      設(shè)計一個模擬操作系統(tǒng)管理程序,實現(xiàn)下列管理功能: 1.內(nèi)存管理功能 2.文件管理功能 3.磁盤管理功能

      題目二

      虛擬存儲器各頁面置換算法的實現(xiàn)與比較 內(nèi) 容:設(shè)計一個虛擬存儲區(qū)和內(nèi)存工作區(qū),通過產(chǎn)生一個隨機數(shù)的方法得到一個頁面序列,假設(shè)內(nèi)存給定的頁面數(shù)由鍵盤輸入,分別計算使用下述各方法時的內(nèi)存命中率:

      先進先出算法(FIFO)、最近最少使用算法(LRU)、最佳淘汰算法(OPT)、最少訪問頁面算法(LFU)等。

      參考資料

      題目二

      資料

      虛擬存儲器各頁面置換算法的實現(xiàn)與比較

      1.實驗?zāi)康?/p>

      存儲管理的主要功能之一是合理的分配空間。請求頁式管理是一種常用的虛擬存儲管理技術(shù)。

      本實驗的目的是通過請求頁式存儲管理中頁面置換算法模擬設(shè)計,了解虛擬存儲技術(shù)的特點,掌握請求頁式存儲管理的頁面置換算法。2.實驗內(nèi)容

      (1)通過隨機數(shù)產(chǎn)生一個指令序列,共320條指令。指令的地址按下述原則生成: 1)50%的指令是順序執(zhí)行的;

      2)25%的指令是均勻分布在前地址部分; 3)25%的指令是均勻分布在后地址部分; 具體的實施方法是:

      1)在[0,319]的指令地址之間隨機選取一起點m; 2)順序執(zhí)行一條指令,即執(zhí)行地址為m+1的指令;

      3)在前地址[0,m+1]中隨機選取一條指令并執(zhí)行,該指令的地址為m'; 4)順序執(zhí)行一條指令,其地址為m'+1;

      5)在后地址[m'+2,319]中隨機選取一條指令并執(zhí)行; 6)重復(fù)上述步驟1)-5),直到執(zhí)行320次指令。(2)將指令序列變換成為頁地址流 設(shè):1)頁面大小為1k;

      2)用戶內(nèi)存容量為4頁到32頁; 3)用戶虛存容量為32k; 在用戶虛存中,按每k存放10條指令排列虛存地址,即320條指令在虛存中的存放方式為: 第0條-第9條指令為第0頁(對應(yīng)虛存地址為[0,9]); 第10條-第19條指令為第1頁(對應(yīng)虛存地址為[10,19]);

      ...第310條-第319條指令為第31頁(對應(yīng)虛存地址為[310,319]);

      按以上方式,用戶指令可組成為32頁。

      (3)計算并輸出下列各種算法在不同內(nèi)存容量下的命中率。1)先進先出的算法(FIFO); 2)最近最少使用算法(LRR);3)最佳淘汰算法(OPT):先淘汰最不常用的頁地址; 4)最少訪問頁面算法(LF.U); 5)最近最不經(jīng)常使用算法(NUR)。其中3)和4)為選擇內(nèi)容。命中率=1-頁面失效次數(shù)/頁地址流長度

      在本實驗中,頁地址流長度為320,頁面失效次數(shù)為每次訪問相應(yīng)指令時,該指令所對應(yīng)的頁不在內(nèi)存的次數(shù)。3.隨機數(shù)產(chǎn)生辦法

      關(guān)于隨機數(shù)產(chǎn)生辦法,Linux或Unix系統(tǒng)提供函數(shù)srand()和rand(),分別進行初始化和產(chǎn)生隨機數(shù)。例如: srand();

      語句可初始化一個隨機數(shù); a[0]=10*rand()/32767*319+1;a[1]=10*rand()/32767*a[0];

      ..語句可用來產(chǎn)生a[0]與a[1]中的隨機數(shù)。

      提示:

      首先用Srand()和rand()函數(shù)定義和產(chǎn)生指令序列,然后將指令序列變換成相應(yīng)的頁地址流,并針對不同的算法計算出相應(yīng)的命中率。

      命中率=1-頁面失效次數(shù)/頁地址流長度

      1、數(shù)據(jù)結(jié)構(gòu)

      (1)頁面類型 typedef struct{

      int pn,pfn,counter,time;}pl-type;

      其中pn為頁號,pfn為頁面號,count為一個周期內(nèi)訪問該頁面的次數(shù),time為訪問時間。

      (2)頁面控制結(jié)構(gòu) pfc_struct{

      int pn,pfn;

      struct pfc_struct *next;

      };typedef struct

      pfc_struct pfc_type;pfc_type

      pfc[total_vp],*freepf_head,*busypf_head;pfc_type *busypf_tail;其中,pfc[total_vp]定義用戶進程虛頁控制結(jié)構(gòu),*freepf_head為空頁面頭的指針,*busypf_head為忙頁面頭的指針,*busyf_tail為忙頁面尾的指針。

      2、函數(shù)定義

      (1)Void initialize():初始化函數(shù),給每個相關(guān)的頁面賦值。(2)Void FIFO():計算使用FIFO算法時的命中率。(2)Void LRU():計算使用FIFO算法時的命中率。(4)VoidOPT():計算使用OPT算法時的命中率。(5)Void LFU():計算使用LFU算法時的命中率。(6)Void

      NUR():計算使用NUR算法時的命中率。

      3、變量定義

      (1)int a[tatal_instruction] :指令流數(shù)據(jù)組。

      (2)int page[total_instruction]:每條指令所屬頁號。

      (3)int offset[total_instruction]:每頁裝入不敷出0條指令后取模運算頁號偏移量。(4)int total_pf:用戶進程的內(nèi)存頁面數(shù)。(5)int diseffect:頁面失效次數(shù)。

      程序清單

      程序: 程序: #include “stdio.h” #include “process.h” #include “stdlib.h” #define TRUE 1 #define FALSE 0 #define INVALID-1 #define null 0 #define total_instruction 320 /*指令流長*/ #define total_vp 32 /*虛頁長*/ #define clear_period 50 /*清0周期*/ typedef struct { int pn,pfn,counter,time;}pl_type;pl_type pl[total_vp];/*頁面數(shù)據(jù)結(jié)構(gòu)*/ struct pfc_struct{ /*頁面控制結(jié)構(gòu)*/ int pn,pfn;struct pfc_struct *next;};typedef struct pfc_struct pfc_type;pfc_type pfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;int diseffect,a[total_instruction];int page[total_instruction],offset[total_instruction];void initialize();void FIFO();void LRU();void OPT();void LFU();void NUR();main(){ int S,i,j;srand(getpid()*10);/*由于每次運行時進程號不同,故可用來作為初始化隨機數(shù)隊

      列的種子*/ S=(float)319*rand()/32767+1;for(i=0;inext;pl[busypf_head->pn].pfn=INVALID;freepf_head=busypf_head;/*釋放忙頁面隊列中的第一個頁面*/ freepf_head->next=null;busypf_head=p;} p=freepf_head->next;/*按FIFO方式調(diào)新頁面入內(nèi)存頁面*/ freepf_head->next=null;freepf_head->pn=page[i];pl[page[i]].pfn=freepf_head->pfn;if(busypf_tail==null)

      busypf_head=busypf_tail=freepf_head;else {busypf_tail->next=freepf_head;busypf_tail=freepf_head;} freepf_head=p;} } printf(“FIFO:%6.4”,1-(float)diseffect/320);} void LRU(total_pf)/*LRU*/ int total_pf;{ int min,minj,i,j,present_time;initialize(total_pf);present_time=0;for(i=0;ipl[j].time&&pl[j].pfn!=INVALID){min=pl[j].time;minj=j;} freepf_head=&pfc[pl[minj].pfn];pl[minj].pfn=INVALID;pl[minj].time=-1;freepf_head->next=null;} pl[page[i]].pfn=freepf_head->pfn;pl[page[i]].time=present_time;freepf_head=freepf_head->next;} else pl[page[i]].time=present_time;present_time++;} printf(“LRU:%6.4f”,1-(float)diseffect/320);} void NUR(total_pf)/*NUR*/ int total_pf;{ int i,j,dp,cont_flag,old_dp;pfc_type *t;initialize(total_pf);dp=0;for(i=0;inext=null;} pl[page[i]].pfn=freepf_head->pfn;freepf_head=freepf_head->next;} else pl[page[i]].counter=1;if(i%clear_period==0)for(j=0;jnext=null;pl[maxpage].pfn=INVALID;} pl[page[i]].pfn=freepf_head->pfn;freepf_head=freepf_head->next;} } printf(“OPT:%6.4f”,1-(float)diseffect/320);} void LFU(total_pf)/*LFU*/ int total_pf;{ int i,j,min,minpage;pfc_type * t;initialize(total_pf);for(i=0;ipl[j].counter&&pl[j].pfn!=INVALID){ min=pl[j].counter;minpage=j;} pl[j].counter=0;} freepf_head=&pfc[pl[minpage].pfn];pl[minpage].pfn=INVALID;freepf_head->next=null;} pl[page[i]].pfn=freepf_head->pfn;freepf_head=freepf_head->next;} else pl[page[i]].counter++;} printf(“LFU:%6.4f”,1-(float)diseffect/320);} void initialize(total_pf)/*初始化相關(guān)數(shù)據(jù)*/ int total_pf;/*用戶進程的內(nèi)存頁面數(shù)*/ {int i;diseffect=0;for(i=0;i

      1、操作系統(tǒng)實驗教程 張麗芬編著

      清華大學(xué)出版社

      2、操作系統(tǒng)原理實驗教程(基于Linux)胡峰松編

      清華大學(xué)出版社

      第四篇:struts2代碼分析

      1.Struts2架構(gòu)圖和請求處理流程

      請求首先通過Filter chain,F(xiàn)ilter主要包括ActionContextCleanUp,它主要清理當前線程的ActionContext和Dispatcher;FilterDispatcher主要通過AcionMapper來決定需要調(diào)用哪個Action。

      ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里創(chuàng)建ActionProxy,ActionProxy創(chuàng)建ActionInvocation,然后ActionInvocation調(diào)用Interceptors,執(zhí)行Action本身,創(chuàng)建Result并返回,當然,如果要在返回之前做些什么,可以實現(xiàn)PreResultListener。

      2.Struts2部分類介紹

      這部分從Struts2參考文檔中翻譯就可以了。

      ActionMapper

      ActionMapper其實是HttpServletRequest和Action調(diào)用請求的一個映射,它屏蔽了Action對于Request等java Servlet類的依賴。Struts2中它的默認實現(xiàn)類是DefaultActionMapper,ActionMapper很大的用處可以根據(jù)自己的需要來設(shè)計url格式,它自己也有Restful的實現(xiàn),具體可以參考文檔的docs¥actionmapper.html。

      ActionProxy&ActionInvocation

      Action的一個代理,由ActionProxyFactory創(chuàng)建,它本身不包括Action實例,默認實現(xiàn)DefaultActionProxy是由ActionInvocation持有Action實例。ActionProxy作用是如何取得Action,無論是本地還是遠程。而ActionInvocation的作用是如何執(zhí)行Action,攔截器的功能就是在ActionInvocation中實現(xiàn)的。

      ConfigurationProvider&Configuration

      ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其實現(xiàn)類XmlConfigurationProvider及其子類StrutsXmlConfigurationProvider來解析。

      3.Struts2請求流程

      1、客戶端發(fā)送請求

      2、請求先通過ActionContextCleanUp-->FilterDispatcher

      3、FilterDispatcher通過ActionMapper來決定這個Request需要調(diào)用哪個Action

      4、如果ActionMapper決定調(diào)用某個Action,F(xiàn)ilterDispatcher把請求的處理交給ActionProxy,這兒已經(jīng)轉(zhuǎn)到它的Delegate--Dispatcher來執(zhí)行

      5、ActionProxy根據(jù)ActionMapping和ConfigurationManager找到需要調(diào)用的Action類

      6、ActionProxy創(chuàng)建一個ActionInvocation的實例

      7、ActionInvocation調(diào)用真正的Action,當然這涉及到相關(guān)攔截器的調(diào)用

      8、Action執(zhí)行完畢,ActionInvocation創(chuàng)建Result并返回,當然,如果要在返回之前做些什么,可以實現(xiàn)PreResultListener。添加PreResultListener可以在Interceptor中實現(xiàn)。

      首先強調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個線程都有自己獨立的實例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      我們再看在FilterDispatcher創(chuàng)建Dispatcher的:

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      創(chuàng)建Dispatcher之后,來看init()方法

      init()方法是用來Load用戶配置文件,資源文件以及默認的配置文件.主要分七步走,看下面注釋

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager

      =

      new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      }

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager

      =

      new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      throw

      }

      new ConfigurationException(“Could not find or error in org/apache/struts2/default.properties”, e);

      loadSettings(props, defaultSettings);

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      settings.getImpl(name),// Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      再來看第二步:init_TraditionalXmlConfigurations()

      private void init_TraditionalXmlConfigurations(){

      settings.getImpl(name), //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      對于其它配置文件只用接口。

      類XmlConfigurationProvider負責配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

      public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成Document對象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

      addAction()方法負責讀取標簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負責將標簽轉(zhuǎn)化為ResultTypeConfig對象; loadInterceptors()方法負責將標簽轉(zhuǎn)化為InterceptorConfi對象;

      loadInterceptorStack()方法負責將標簽轉(zhuǎn)化為InterceptorStackConfig對象;

      StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實現(xiàn)ConfigurationProviderloadInterceptorStacks()方法負責將標簽轉(zhuǎn)化成InterceptorStackConfig對象。

      而上面的方法最終會被addPackage()方法調(diào)用,addPackage又會被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對象中。

      protected PackageConfig

      addPackage(Element

      packageElement)

      throws ConfigurationException {

      PackageConfig.Builder newPackage = buildPackageContext(packageElement);

      if(newPackage.isNeedsRefresh()){

      return newPackage.build();

      }

      // add result types(and default result)to this package

      addResultTypes(newPackage, packageElement);

      // load the interceptors and interceptor stacks for this package

      loadInterceptors(newPackage, packageElement);

      // load the default interceptor reference for this package

      loadDefaultInterceptorRef(newPackage, packageElement);

      // load the default class ref for this package

      loadDefaultClassRef(newPackage, packageElement);

      // load the global result list for this package

      loadGlobalResults(newPackage, packageElement);

      // load the global exception handler list for this package

      loadGobalExceptionMappings(newPackage, packageElement);

      // get actions

      NodeList actionList = packageElement.getElementsByTagName(“action”);

      for(int i = 0;i < actionList.getLength();i++){

      Element actionElement =(Element)actionList.item(i);

      addAction(actionElement, newPackage);

      }

      // load the default action reference for this package

      loadDefaultActionRef(newPackage, packageElement);

      PackageConfig cfg = newPackage.build();

      configuration.addPackageConfig(cfg.getName(), cfg);

      return cfg;

      }

      loadConfigurationFiles解析讀取xml中的內(nèi)容

      private List

      loadConfigurationFiles(String

      fileName,Element includeElement){

      ...//通過DomHelper調(diào)用SAX進行解析xml

      doc = DomHelper.parse(in, dtdMappings);

      ...Element rootElement = doc.getDocumentElement();

      NodeList children = rootElement.getChildNodes();

      int childSize = children.getLength();

      for(int i = 0;i < childSize;i++){

      Node childNode = children.item(i);

      if(childNode instanceof Element){

      Element child =(Element)childNode;

      final String nodeName = child.getNodeName();

      if(“include”.equals(nodeName)){

      String includeFileName = child.getAttribute(“file”);

      //解析每個action配置是,對于include文件可以使用通配符*來進行配置

      //如Struts.xml中可配置成

      if(includeFileName.indexOf('*')!=-1){

      ClassPathFinder wildcardFinder = new ClassPathFinder();

      wildcardFinder.setPattern(includeFileName);

      Vector wildcardMatches = wildcardFinder.findMatches();

      for(String match : wildcardMatches){

      //遞歸Load子file中的

      docs.addAll(loadConfigurationFiles(match, child));

      }

      } else {

      docs.addAll(loadConfigurationFiles(includeFileName, child));

      }

      }

      }

      }

      docs.add(doc);

      loadedFileUrls.add(url.toString());

      ...return docs;

      }

      首先強調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個線程都有自己獨立的實例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      我們再看在FilterDispatcher創(chuàng)建Dispatcher的:

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      創(chuàng)建Dispatcher之后,來看init()方法

      init()方法是用來Load用戶配置文件,資源文件以及默認的配置文件.主要分七步走,看下面注釋

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      new

      }

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      new

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      settings.getImpl(name),if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      再來看第二步:init_TraditionalXmlConfigurations()

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      settings.getImpl(name),用默認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      對于其它配置文件只用接口。

      類XmlConfigurationProvider負責配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

      public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實現(xiàn)ConfigurationProviderDocument對象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

      addAction()方法負責讀取標簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負責將標簽轉(zhuǎn)化為ResultTypeConfig對象; loadInterceptors()方法負責將標簽轉(zhuǎn)化為InterceptorConfi對象;

      loadInterceptorStack()方法負責將標簽轉(zhuǎn)化為InterceptorStackConfig對象;

      loadInterceptorStacks()方法負責將標簽轉(zhuǎn)化成InterceptorStackConfig對象。

      而上面的方法最終會被addPackage()方法調(diào)用,addPackage又會被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對象中。

      protected PackageConfig

      addPackage(Element

      packageElement)

      throws ConfigurationException {

      PackageConfig.Builder newPackage = buildPackageContext(packageElement);

      if(newPackage.isNeedsRefresh()){

      return newPackage.build();

      }

      // add result types(and default result)to this package

      addResultTypes(newPackage, packageElement);

      // load the interceptors and interceptor stacks for this package

      loadInterceptors(newPackage, packageElement);

      // load the default interceptor reference for this package

      loadDefaultInterceptorRef(newPackage, packageElement);

      // load the default class ref for this package

      loadDefaultClassRef(newPackage, packageElement);

      // load the global result list for this package

      loadGlobalResults(newPackage, packageElement);

      // load the global exception handler list for this package

      loadGobalExceptionMappings(newPackage, packageElement);

      // get actions

      NodeList actionList = packageElement.getElementsByTagName(“action”);

      for(int i = 0;i < actionList.getLength();i++){

      Element actionElement =(Element)actionList.item(i);

      addAction(actionElement, newPackage);

      }

      // load the default action reference for this package

      loadDefaultActionRef(newPackage, packageElement);

      PackageConfig cfg = newPackage.build();

      configuration.addPackageConfig(cfg.getName(), cfg);

      return cfg;

      }

      loadConfigurationFiles解析讀取xml中的內(nèi)容

      private List

      loadConfigurationFiles(String

      fileName, includeElement){

      ...//通過DomHelper調(diào)用SAX進行解析xml

      doc = DomHelper.parse(in, dtdMappings);

      ...Element rootElement = doc.getDocumentElement();

      NodeList children = rootElement.getChildNodes();

      int childSize = children.getLength();

      for(int i = 0;i < childSize;i++){

      Node childNode = children.item(i);

      if(childNode instanceof Element){

      Element child =(Element)childNode;

      final String nodeName = child.getNodeName();

      if(“include”.equals(nodeName)){

      String includeFileName = child.getAttribute(“file”);

      //解析每個action配置是,對于include文件可以使用通配符*來進行配置

      //如Struts.xml中可配置成

      if(includeFileName.indexOf('*')!=-1){

      ClassPathFinder wildcardFinder = new ClassPathFinder();

      wildcardFinder.setPattern(includeFileName);

      Element

      Vector wildcardMatches = wildcardFinder.findMatches();

      for(String match : wildcardMatches){

      //遞歸Load子file中的

      docs.addAll(loadConfigurationFiles(match, child));

      }

      } else {

      docs.addAll(loadConfigurationFiles(includeFileName, child));

      }

      }

      }

      }

      docs.add(doc);

      loadedFileUrls.add(url.toString());

      ...return docs;

      }

      接下來第三步:init_LegacyStrutsProperties()調(diào)用的是調(diào)用的是LegacyPropertiesConfigurationProvider 通過比較前

      DefaultPropertiesProvider

      調(diào)

      用的是LegacyPropertiesConfigurationProvider.發(fā)現(xiàn)DefaultPropertiesProvider繼承自后者,但重寫了register()方法,主要是生成PropertiesSetting的不同,前者是根據(jù)org/apache/struts2/default.properties 后者是根據(jù)struts.properties 我們展開register()中的Settings.getInstance(),最后是調(diào)用getDefaultInstance()

      private static Settings getDefaultInstance(){

      if(defaultImpl == null){

      // Create bootstrap implementation

      //不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

      //不帶參數(shù)就是默認為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

      //在struts.proterties中查找struts.configuration的值,這個值必須是org.apache.struts2.config.Configuration接口的實現(xiàn)類

      //所以我有個困惑就是在下面的轉(zhuǎn)換當中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點先放下了,有時間再研究

      String className = get(StrutsConstants.STRUTS_CONFIGURATION);

      if(!className.equals(defaultImpl.getClass().getName())){

      try {

      // singleton instances shouldn't be built accessing request or session-specific context data

      defaultImpl oader().loadClass(className), null);

      } catch(Exception e){

      LOG.error(“Settings:

      }

      }

      } catch(IllegalArgumentException ex){

      // ignore

      }

      private static Settings getDefaultInstance(){

      if(defaultImpl == null){

      // Create bootstrap implementation

      //不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

      //不帶參數(shù)就是默認為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

      //在struts.proterties中查找struts.configuration的值,這個值必須是

      Could

      not

      instantiate

      the struts.configuration object, substituting the default implementation.”, e);

      =

      (Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLorg.apache.struts2.config.Configuration接口的實現(xiàn)類

      //所以我有個困惑就是在下面的轉(zhuǎn)換當中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點先放下了,有時間再研究

      String className = get(StrutsConstants.STRUTS_CONFIGURATION);

      if(!className.equals(defaultImpl.getClass().getName())){

      try {

      // singleton instances shouldn't be built accessing request or session-specific context data

      defaultImpl oader().loadClass(className), null);

      } catch(Exception e){

      LOG.error(“Settings:

      }

      }

      } catch(IllegalArgumentException ex){

      // ignore

      }

      在2.1.6中去掉了第四步:init_ZeroConfiguration();第五步是自定義的configProviders

      private void init_CustomConfigurationProviders(){

      //從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

      String configProvs = initParams.get(”configProviders“);

      if(configProvs!= null){

      String[] classes = configProvs.split(”¥¥s*[,]¥¥s*“);

      for(String cname : classes){

      try {

      Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

      ConfigurationProvider(ConfigurationProvider)cls.newInstance();

      configurationManager.addConfigurationProvider(prov);

      prov

      =

      Could

      not

      instantiate

      the struts.configuration object, substituting the default implementation.”, e);

      =

      (Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassL

      }

      ...}

      }

      }

      private void init_CustomConfigurationProviders(){

      //從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

      String configProvs = initParams.get(“configProviders”);

      if(configProvs!= null){

      String[] classes = configProvs.split(“¥¥s*[,]¥¥s*”);

      for(String cname : classes){

      try {

      Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

      ConfigurationProvider(ConfigurationProvider)cls.newInstance();

      configurationManager.addConfigurationProvider(prov);

      }

      ...}

      }

      }

      第六步:init_FilterInitParameters

      //從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

      private void init_FilterInitParameters(){

      configurationManager.addConfigurationProvider(new ConfigurationProvider(){

      public void destroy(){}

      public

      void

      init(Configuration

      configuration)

      throws ConfigurationException {}

      public void loadPackages()throws ConfigurationException {}

      public boolean needsReload(){ return false;}

      prov

      =

      public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

      props.putAll(initParams);//在這里實現(xiàn)滴~

      }

      });

      }

      //從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

      private void init_FilterInitParameters(){

      configurationManager.addConfigurationProvider(new ConfigurationProvider(){

      public void destroy(){}

      public

      void

      init(Configuration

      configuration)

      throws ConfigurationException {}

      public void loadPackages()throws ConfigurationException {}

      public boolean needsReload(){ return false;}

      public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

      props.putAll(initParams);//在這里實現(xiàn)滴~

      }

      });

      }

      第七步:init_AliasStandardObjects,使用BeanSelectionProvider 這是將配置文件中定義的與實際的類相映射,就是注入bean的依賴關(guān)系,這部分以后有時候再研究Container

      接下來是看怎樣調(diào)用這些ConfigurationProviders 展開init_PreloadConfiguration()

      private Container init_PreloadConfiguration(){

      Configuration config = configurationManager.getConfiguration();

      Container container = config.getContainer();

      boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

      LocalizedTextUtil.setReloadBundles(reloadi18n);

      return container;

      }

      //再看getConfiguration()

      public synchronized Configuration getConfiguration(){

      if(configuration == null){

      setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

      try {

      //重點就是這個reloadContainer

      configuration.reloadContainer(getContainerProviders());

      } catch(ConfigurationException e){

      setConfiguration(null);

      throw new ConfigurationException(“Unable to load configuration.”, e);

      }

      } else {

      conditionalReload();

      }

      return configuration;

      }

      private Container init_PreloadConfiguration(){

      Configuration config = configurationManager.getConfiguration();

      Container container = config.getContainer();

      boolean reloadi18n

      =

      Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

      LocalizedTextUtil.setReloadBundles(reloadi18n);

      return container;

      }

      //再看getConfiguration()

      public synchronized Configuration getConfiguration(){

      if(configuration == null){

      setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

      try {

      //重點就是這個reloadContainer

      configuration.reloadContainer(getContainerProviders());

      } catch(ConfigurationException e){

      setConfiguration(null);

      throw new ConfigurationException(“Unable to load configuration.”, e);

      }

      } else {

      conditionalReload();

      }

      return configuration;

      }

      展開DefaultConfiguration中的reloadContainer

      public synchronized List

      reloadContainer(List providers)throws ConfigurationException {

      packageContexts.clear();

      loadedFileNames.clear();

      List

      packageProviders = new ArrayList

      ();

      //Struts2(xwork2)用Container來完成依賴注入的功能

      //首先初始化一個ContainerBuilder,再由builder來保存接口與實現(xiàn)類或工廠類的對應(yīng)關(guān)系

      //然后通過builder.create(boolean)方法產(chǎn)生container

      //由container.getInstance(Class);就可以得到接口的實現(xiàn)實例了

      //這一部分比較復(fù)雜,后面研究完成了,會單獨拿出來講,這里先弄清楚Xwork依賴注入的實現(xiàn)步驟就可以了

      ContainerProperties props = new ContainerProperties();

      ContainerBuilder builder = new ContainerBuilder();

      for(final ContainerProvider containerProvider : providers)

      {

      //循環(huán)調(diào)用ConfigurationProvider的init和register方法,明白了吧,在這里統(tǒng)一循環(huán)調(diào)用

      containerProvider.init(this);

      containerProvider.register(builder, props);

      }

      props.setConstants(builder);

      //注入依賴關(guān)系,在這里并不產(chǎn)生實例

      builder.factory(Configuration.class, new Factory(){

      public Configuration create(Context context)throws Exception {

      return DefaultConfiguration.this;

      }

      });

      ActionContext oldContext = ActionContext.getContext();

      try {

      // Set the bootstrap container for the purposes of factory creation

      Container bootstrap = createBootstrapContainer();

      setContext(bootstrap);

      //create已經(jīng)注入依賴關(guān)系的Container

      container = builder.create(false);

      setContext(container);

      objectFactory = container.getInstance(ObjectFactory.class);

      // Process the configuration providers first

      for(final ContainerProvider containerProvider : providers)

      {

      if(containerProvider instanceof PackageProvider){

      container.inject(containerProvider);

      //調(diào)用PackageProvider的loadPackages()方法,這里主要是針對XmlConfigurationProvider和StrutsXmlConfigurationProvider

      ((PackageProvider)containerProvider).loadPackages();

      packageProviders.add((PackageProvider)containerProvider);

      }

      }

      // Then process any package providers from the plugins

      Set

      packageProviderNames

      = container.getInstanceNames(PackageProvider.class);

      if(packageProviderNames!= null){

      for(String name : packageProviderNames){

      PackageProvider

      provider.init(this);

      provider.loadPackages();

      packageProviders.add(provider);

      }

      }

      rebuildRuntimeConfiguration();

      } finally {

      if(oldContext == null){

      ActionContext.setContext(null);

      }

      }

      return packageProviders;

      }

      Dispatcher已經(jīng)在之前講過,這就好辦了。FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。

      public void init(FilterConfig filterConfig)throws ServletException {

      try {

      this.filterConfig = filterConfig;

      initLogging();

      //創(chuàng)建dispatcher,前面都已經(jīng)講過啰

      dispatcher = createDispatcher(filterConfig);

      dispatcher.init();

      //注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

      dispatcher.getContainer().inject(this);

      //StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

      //可以在struts-default.xml中的可以找到

      staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

      } finally {

      provider

      = container.getInstance(PackageProvider.class, name);

      ActionContext.setContext(null);

      }

      }

      public void init(FilterConfig filterConfig)throws ServletException {

      try {

      this.filterConfig = filterConfig;

      initLogging();

      //創(chuàng)建dispatcher,前面都已經(jīng)講過啰

      dispatcher = createDispatcher(filterConfig);

      dispatcher.init();

      //注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

      dispatcher.getContainer().inject(this);

      //StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

      //可以在struts-default.xml中的可以找到

      staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

      } finally {

      ActionContext.setContext(null);

      }

      }

      //下面來看DefaultStaticContentLoader的setHostConfig

      public void setHostConfig(HostConfig filterConfig){

      //讀取初始參數(shù)

      pakages,調(diào)用

      parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

      String param = filterConfig.getInitParameter(“packages”);

      //“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

      String packages = getAdditionalPackages();

      if(param!= null){

      packages = param + “ ” + packages;

      }

      this.pathPrefixes = parse(packages);

      initLogging(filterConfig);

      }

      template //下面來看DefaultStaticContentLoader的setHostConfig

      public void setHostConfig(HostConfig filterConfig){

      //讀取初始參數(shù)

      pakages,調(diào)用

      parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

      String param = filterConfig.getInitParameter(“packages”);

      //“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

      String packages = getAdditionalPackages();

      if(param!= null){

      packages = param + “ ” + packages;

      }

      this.pathPrefixes = parse(packages);

      initLogging(filterConfig);

      }

      現(xiàn)在回去doFilter的方法,每當有一個Request,都會調(diào)用這些Filters的doFilter方法

      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

      HttpServletRequest request =(HttpServletRequest)req;

      HttpServletResponse response =(HttpServletResponse)res;

      ServletContext servletContext = getServletContext();

      String timerKey = “FilterDispatcher_doFilter: ”;

      try {

      // FIXME: this should be refactored better to not duplicate work with the action invocation

      //先看看ValueStackFactory所注入的實現(xiàn)類OgnlValueStackFactory

      //new OgnlValueStack

      ValueStack

      stack

      = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

      ActionContext ctx = new ActionContext(stack.getContext());

      ActionContext.setContext(ctx);

      template

      UtilTimerStack.push(timerKey);

      //如果是multipart/form-data就用MultiPartRequestWrapper進行包裝

      //MultiPartRequestWrapper

      StrutsRequestWrapper的子類,兩者都是HttpServletRequest實現(xiàn)

      //此時在MultiPartRequestWrapper中就會把Files給解析出來,用于文件上傳

      //所有request都會StrutsRequestWrapper進行包裝,StrutsRequestWrapper是可以訪問ValueStack

      //下面是參見Dispatcher的wrapRequest

      // String content_type = request.getContentType();

      //if(content_type!= null&&content_type.indexOf(“multipart/form-data”)!=-1){

      //MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

      //request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

      //} else {

      //

      request = new StrutsRequestWrapper(request);

      // }

      request = prepareDispatcherAndWrapRequest(request, response);

      ActionMapping mapping;

      try {

      //根據(jù)url取得對應(yīng)的Action的配置信息

      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲在 ActionMapping對象中

      mapping

      =

      actionMapper.getMapping(request, dispatcher.getConfigurationManager());

      } catch(Exception ex){

      log.error(“error getting ActionMapping”, ex);

      dispatcher.sendError(request,return;

      }

      //如果找不到對應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

      //這兒有個例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對應(yīng)的靜態(tài)資源并輸出到頁面流中,當然.class文件除外。如果再沒有則跳轉(zhuǎn)到

      response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

      =new 404

      if(mapping == null){

      // there is no action in this request, should we look for a static resource?

      String resourcePath = RequestUtils.getServletPath(request);

      if(“".equals(resourcePath)&& null!= request.getPathInfo()){

      resourcePath = request.getPathInfo();

      }

      if(staticResourceLoader.canHandle(resourcePath)){

      // 在DefaultStaticContentLoader

      :return

      serveStatic

      &&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

      staticResourceLoader.findStaticResource(resourcePath, response);

      } else {

      // this is a normal request, let it pass through

      chain.doFilter(request, response);

      }

      // The framework did its job here

      return;

      }

      //正式開始Action的方法

      dispatcher.serviceAction(request, response, servletContext, mapping);

      } finally {

      try {

      ActionContextCleanUp.cleanUp(req);

      } finally {

      UtilTimerStack.pop(timerKey);

      }

      }

      }

      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

      HttpServletRequest request =(HttpServletRequest)req;

      request,HttpServletResponse response =(HttpServletResponse)res;

      ServletContext servletContext = getServletContext();

      String timerKey = ”FilterDispatcher_doFilter: “;

      try {

      // FIXME: this should be refactored better to not duplicate work with the action invocation

      //先看看ValueStackFactory所注入的實現(xiàn)類OgnlValueStackFactory

      //new OgnlValueStack

      ValueStack

      stack

      = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

      ActionContext ctx = new ActionContext(stack.getContext());

      ActionContext.setContext(ctx);

      UtilTimerStack.push(timerKey);

      //如果是multipart/form-data就用MultiPartRequestWrapper進行包裝

      //MultiPartRequestWrapperHttpServletRequest實現(xiàn)

      //此時在MultiPartRequestWrapper中就會把Files給解析出來,用于文件上傳

      //所有request都會StrutsRequestWrapper進行包裝,StrutsRequestWrapper是可以訪問ValueStack

      //下面是參見Dispatcher的wrapRequest

      // String content_type = request.getContentType();

      //if(content_type!= null&&content_type.indexOf(”multipart/form-data“)!=-1){

      //MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

      //request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

      //} else {

      //

      request = new StrutsRequestWrapper(request);

      // }

      request = prepareDispatcherAndWrapRequest(request, response);

      ActionMapping mapping;

      try {

      =new

      StrutsRequestWrapper的子類,兩者都是

      //根據(jù)url取得對應(yīng)的Action的配置信息

      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲在 ActionMapping對象中

      mapping

      } catch(Exception ex){

      log.error(”error getting ActionMapping“, ex);

      dispatcher.sendError(request,return;

      }

      //如果找不到對應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

      //這兒有個例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對應(yīng)的靜態(tài)資源并輸出到頁面流中,當然.class文件除外。如果再沒有則跳轉(zhuǎn)到404

      if(mapping == null){

      // there is no action in this request, should we look for a static resource?

      String resourcePath = RequestUtils.getServletPath(request);

      if(”“.equals(resourcePath)&& null!= request.getPathInfo()){

      resourcePath = request.getPathInfo();

      }

      if(staticResourceLoader.canHandle(resourcePath)){

      // 在DefaultStaticContentLoader

      :return

      serveStatic

      &&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

      staticResourceLoader.findStaticResource(resourcePath, response);

      } else {

      // this is a normal request, let it pass through

      chain.doFilter(request, response);

      }

      // The framework did its job here

      return;

      }

      request,response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

      =

      actionMapper.getMapping(request, dispatcher.getConfigurationManager());

      //正式開始Action的方法

      dispatcher.serviceAction(request, response, servletContext, mapping);

      } finally {

      try {

      ActionContextCleanUp.cleanUp(req);

      } finally {

      UtilTimerStack.pop(timerKey);

      }

      }

      }

      //下面是ActionMapper接口的實現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

      String uri = getUri(request);//得到請求路徑的URI,如:testAtcion.action或testAction.do

      int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時找不到而且的bug

      uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

      uri = dropExtension(uri, mapping);//刪除擴展名,默認擴展名為action

      if(uri == null){

      return null;

      }

      parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

      handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

      //如果Action的name沒有解析出來,直接返回

      if(mapping.getName()== null){

      returnnull;

      }

      //下面處理形如testAction!method格式的請求路徑

      if(allowDynamicMethodCalls){

      // handle ”name!method“ convention.String name = mapping.getName();

      int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

      if(exclamation!=-1){

      mapping.setName(name.substring(0, exclamation));//提取左邊為name

      mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

      }

      }

      return mapping;

      }

      //下面是ActionMapper接口的實現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

      String uri = getUri(request);//得到請求路徑的URI,如:testAtcion.action或testAction.do

      int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時找不到而且的bug

      uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

      uri = dropExtension(uri, mapping);//刪除擴展名,默認擴展名為action

      if(uri == null){

      return null;

      }

      parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

      handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

      //如果Action的name沒有解析出來,直接返回

      if(mapping.getName()== null){

      returnnull;

      }

      //下面處理形如testAction!method格式的請求路徑

      if(allowDynamicMethodCalls){

      // handle ”name!method“ convention.String name = mapping.getName();

      int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

      if(exclamation!=-1){

      mapping.setName(name.substring(0, exclamation));//提取左邊為name

      mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

      }

      }

      return mapping;

      }

      從代碼中看出,getMapping()方法返回ActionMapping類型的對象,該對象包含三個參數(shù):Action的name、namespace和要調(diào)用的方法method。

      如果getMapping()方法返回ActionMapping對象為null,則FilterDispatcher認為用戶請求不是Action,自然另當別論,F(xiàn)ilterDispatcher會做一件非常有意思的事:如果請求以/struts開頭,會自動查找在web.xml文件中配置的 packages初始化參數(shù),就像下面這樣:

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      packages

      com.lizanhong.action

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      packages

      com.lizanhong.action

      FilterDispatcher會將com.lizanhong.action包下的文件當作靜態(tài)資源處理,即直接在頁面上顯示文件內(nèi)容,不過會忽略擴展名為class的文件。比如在com.lizanhong.action包下有一個aaa.txt的文本文件,其內(nèi)容為“中華人民共和國”,訪問

      http://localhost:8081/Struts2Demo/struts/aaa.txt時會輸出txt中的內(nèi)容

      FilterDispatcher.findStaticResource()方法

      protectedvoid findStaticResource(String

      name,HttpServletRequest

      request, HttpServletResponse response)throws IOException {

      if(!name.endsWith(”.class“)){//忽略class文件

      //遍歷packages參數(shù)

      for(String pathPrefix : pathPrefixes){

      InputStream is = findInputStream(name, pathPrefix);//讀取請求文件流

      if(is!= null){

      ...// set the content-type header

      String contentType = getContentType(name);//讀取內(nèi)容類型

      if(contentType!= null){

      response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

      }

      ...try {

      //將讀取到的文件流以每次復(fù)制4096個字節(jié)的方式循環(huán)輸出

      copy(is, response.getOutputStream());

      } finally {

      is.close();

      }

      return;

      }

      }

      }

      }

      protectedvoid findStaticResource(String

      name,HttpServletRequest

      request, HttpServletResponse response)throws IOException {

      if(!name.endsWith(”.class“)){//忽略class文件

      //遍歷packages參數(shù)

      for(String pathPrefix : pathPrefixes){

      InputStream is = findInputStream(name, pathPrefix);//讀取請求文件流

      if(is!= null){

      ...// set the content-type header

      String contentType = getContentType(name);//讀取內(nèi)容類型

      if(contentType!= null){

      response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

      }

      ...try {

      //將讀取到的文件流以每次復(fù)制4096個字節(jié)的方式循環(huán)輸出

      copy(is, response.getOutputStream());

      } finally {

      is.close();

      }

      return;

      }

      }

      }

      }

      如果用戶請求的資源不是以/struts開頭——可能是.jsp文件,也可能是.html文件,則通過過濾器鏈繼續(xù)往下傳送,直到到達請求的資源為止。

      如果getMapping()方法返回有效的ActionMapping對象,則被認為正在請求某個Action,將調(diào)用 Dispatcher.serviceAction(request, response, servletContext, mapping)方法,該方法是處理Action的關(guān)鍵所在。

      下面就來看serviceAction,這又回到全局變量dispatcher中了

      //Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

      //createContextMap方法主要把Application、Session、Request的key value值拷貝到Map中

      Map extraContext = createContextMap(request, response, mapping, context);

      // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action

      ValueStack

      stack

      =

      (ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

      boolean nullStack = stack == null;

      if(nullStack){

      ActionContext ctx = ActionContext.getContext();

      if(ctx!= null){

      stack = ctx.getValueStack();

      }

      }

      if(stack!= null){

      extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));

      }

      String timerKey = ”Handling request from Dispatcher“;

      try {

      UtilTimerStack.push(timerKey);

      String namespace = mapping.getNamespace();

      String name = mapping.getName();

      String method = mapping.getMethod();

      Configuration config = configurationManager.getConfiguration();

      //創(chuàng)建一個Action的代理對象,ActionProxyFactory是創(chuàng)建ActionProxy的工廠

      //參考實現(xiàn)類:DefaultActionProxy和DefaultActionProxyFactory

      ActionProxy

      proxy

      = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);

      request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

      // if the ActionMapping says to go straight to a result, do it!

      //如果是Result,則直接轉(zhuǎn)向,關(guān)于Result,ActionProxy,ActionInvocation下一講中再分析

      if(mapping.getResult()!= null){

      Result result = mapping.getResult();

      result.execute(proxy.getInvocation());

      } else {

      //執(zhí)行Action

      proxy.execute();

      }

      // If there was a previous value stack then set it back onto the request

      if(!nullStack){

      request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

      }

      } catch(ConfigurationException e){

      // WW-2874 Only log error if in devMode

      if(devMode){

      LOG.error(”Could not find action or result“, e);

      }

      else {

      LOG.warn(”Could not find action or result“, e);

      }

      sendError(request, HttpServletResponse.SC_NOT_FOUND, e);

      } catch(Exception e){

      sendError(request,} finally {

      UtilTimerStack.pop(timerKey);

      }

      } 下面開始講一下主菜ActionProxy了.在這之前最好先去了解一下動態(tài)Proxy的基本知識.ActionProxy是Action的一個代理類,也就是說Action的調(diào)用是通過ActionProxy實現(xiàn)的,其實就是調(diào)用了ActionProxy.execute()方法,而該方法又調(diào)用了ActionInvocation.invoke()方法。歸根到底,最后調(diào)用的是DefaultActionInvocation.invokeAction()方法。DefaultActionInvocation()->init()->createAction()。

      最后

      調(diào)

      用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()這里的步驟是先由ActionProxyFactory創(chuàng)建ActionInvocation和ActionProxy.public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

      ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

      container.inject(inv);

      return }

      public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

      createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

      response,context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);

      response,context,ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

      container.inject(inv);

      return }

      下面先看DefaultActionInvocation的init方法

      public void init(ActionProxy proxy){

      this.proxy = proxy;

      Map contextMap = createContextMap();

      // Setting this so that other classes, like object factories, can use the ActionProxy and other

      // contextual information to operate

      ActionContext actionContext = ActionContext.getContext();

      if(actionContext!= null){

      actionContext.setActionInvocation(this);

      }

      //創(chuàng)建Action,struts2中每一個Request都會創(chuàng)建一個新的Action

      createAction(contextMap);

      if(pushAction){

      stack.push(action);

      contextMap.put(”action“, action);

      }

      invocationContext = new ActionContext(contextMap);

      invocationContext.setName(proxy.getActionName());

      // get a new List so we don't get problems with the iterator if someone changes the list

      List

      interceptorList

      =

      new ArrayList(proxy.getConfig().getInterceptors());

      interceptors = interceptorList.iterator();

      createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

      }

      protected void createAction(Map contextMap){

      // load action

      String timerKey = ”actionCreate: “ + proxy.getActionName();

      try {

      UtilTimerStack.push(timerKey);

      //默認為SpringObjectFactory:struts.objectFactory=spring.這里非常巧妙,在struts.properties中可以重寫這個屬性

      //在前面BeanSelectionProvider中通過配置文件為ObjectFactory設(shè)置實現(xiàn)類

      //這里以Spring為例,這里會調(diào)到SpringObjectFactory的buildBean方法,可以通過ApplicationContext的getBean()方法得到Spring的Bean

      action

      =

      objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);

      } catch(InstantiationException e){

      throw new

      XWorkException(”Unable

      to

      intantiate

      Action!“,e, proxy.getConfig());

      } catch(IllegalAccessException e){

      throw new XWorkException(”Illegal access to constructor, is it public?", e, proxy.getConfig());

      } catch(Exception e){

      ...} finally {

      UtilTimerStack.pop(timerKey);

      }

      if(actionEventListener!= null){

      action = actionEventListener.prepare(action, stack);

      }

      }

      //SpringObjectFactory

      public Object buildBean(String beanName, Map extraContext, boolean injectInternal)throws Exception {

      Object o = null;

      try {

      //SpringObjectFactory

      web.xml

      中的

      第五篇:典型相關(guān)分析SAS代碼

      data fit;input X1 X2 X3 X4 X5 Y1 Y2 Y3;cards;14651000 3446 98.8 2094.51 104.2 2555.14 2637.67 179.76 13985000 3339 113.8 2305.2233 133.8 2462.45 2670.99 161.74 15162900 3093 108.9 2494.6668 93.8 2831.87 3015.04 186 14275800 3084 99.6 2770.48 99.8 2957.2 2259.86 210.3 13966000 3040 101.6 3224.05 142.4 2767.25 2169.47 206.16 13947000 2978 112.4086 3690.34 123.8 2935 2307 218.36 14632000 2952 102.5 3980.44 79.1 3119.91 2332.38 232.33 14123200 2761 106.2 4543.41 97.9 3230.04 2344.04 241.53 14299300 2703 107.3469 5231.33 143.2 3195.12 2411.98 239.79 14849000 2644 111.3 6007.5498 90.8 3342.09 2466.6 252.5 15218000 2604 103.8 6790.899 97.2 3456.7 2471.53 261.34 15344000 2567 99 7565 95.7 3518 2360.31 266.29 run;ods rtf file='F:結(jié)果.doc';proccancorr data=fit all vprefix=YING vname='yingxiang' wprefix=CHAN wname='shengchan';var X1 X2 X3 X4 X5;with Y1 Y2 Y3;run;ods rtf close;

      下載Linux操作系統(tǒng)的權(quán)限代碼分析word格式文檔
      下載Linux操作系統(tǒng)的權(quán)限代碼分析.doc
      將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
      點此處下載文檔

      文檔為doc格式


      聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),未作人工編輯處理,也不承擔相關(guān)法律責任。如果您發(fā)現(xiàn)有涉嫌版權(quán)的內(nèi)容,歡迎發(fā)送郵件至:645879355@qq.com 進行舉報,并提供相關(guān)證據(jù),工作人員會在5個工作日內(nèi)聯(lián)系你,一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

      相關(guān)范文推薦

        《操作系統(tǒng)課程設(shè)計》指導(dǎo)書分析五篇范文

        《操作系統(tǒng)課程設(shè)計》實驗指導(dǎo) 課程設(shè)計一:進程調(diào)度 1、 設(shè)計目的 (1) 要求學(xué)生設(shè)計一個模擬進程調(diào)度的算法 (2) 理解進程控制塊的結(jié)構(gòu) (3) 理解進程運行的并發(fā)性 (4) 掌握進程調(diào)度的......

        SAP用戶權(quán)限風險分析(大全)

        一、SAP用戶企業(yè)權(quán)限風險內(nèi)控存在的風險 在日趨復(fù)雜的信息化環(huán)境中,分散的業(yè)務(wù)流程對信息安全提出了更高的要求,公司治理、風險管理、合規(guī)管理越來越困難,傳統(tǒng)的支離破碎的風險......

        手機操作系統(tǒng)上演新三國演義探討分析

        www.tel365.net 呼叫中心 手機操作系統(tǒng)上演新三國演義探討分析 移動操作系統(tǒng)的三大巨頭——蘋果、谷歌和微軟都已發(fā)布各自最新的操作系統(tǒng)iOS6、安卓4.1JellyBean(果凍豆)和Win......

        詞法分析設(shè)計實驗報告(附代碼)[精選合集]

        實驗一詞法分析設(shè)計 實驗學(xué)時:4 實驗類型:綜合 實驗要求:必修 一、實驗?zāi)康?通過本實驗的編程實踐,使學(xué)生了解詞法分析的任務(wù),掌握詞法分析程序設(shè)計的原理和構(gòu)造方法,使學(xué)生對編譯......

        RBS2000基站告警代碼分析與處理

        基站告警代碼分析與處理 RBS2000系列(RBS2202、RBS2301、RBS2302、RBS2206) 1 1 SO CF,external condition map class 1 故障代碼:SO CF EC1:4 故障名稱:L/R SWI(BTS in local mod......

        XX公司(代碼:)投資分析報告_某某(學(xué)號:XX)(最終定稿)

        ****公司投資分析報告 一、基本情況 分析對象:**公司(股票代碼:******) 所屬行業(yè)與區(qū)位: 分析時點:2013年*月*日 投資建議:(買入、增持、推薦、中性、觀望、減持、賣出) 分析人:**班級......

        藥物分析試驗教學(xué)大綱課程名稱藥物分析課程代碼130042課程

        《藥物分析》實驗教學(xué)大綱 課程名稱: 藥物分析 課程代碼:130042 課程類型:專業(yè)基礎(chǔ)課程 開課學(xué)期:第四學(xué)期 課程總學(xué)時:108學(xué)時 實驗學(xué)時:38學(xué)時 前期課程:藥物化學(xué)、藥理學(xué)、分析......

        ssh框架的構(gòu)成分析和代碼構(gòu)架小結(jié)

        ssh框架的構(gòu)成分析和代碼構(gòu)架小結(jié) 最近在弄j2ee,發(fā)現(xiàn)還是學(xué)到了很多東西,心情happy??!昨天看到了一個文章是關(guān)于ssh的,就弄下來了,后面加點自己的東西,很感謝網(wǎng)上的各位前輩的總......