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

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

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

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

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

      struts2源代碼分析(個(gè)人覺得非常經(jīng)典)

      時(shí)間:2019-05-12 02:43:00下載本文作者:會(huì)員上傳
      簡介:寫寫幫文庫小編為你整理了多篇相關(guān)的《struts2源代碼分析(個(gè)人覺得非常經(jīng)典)》,但愿對(duì)你工作學(xué)習(xí)有幫助,當(dāng)然你在寫寫幫文庫還可以找到更多《struts2源代碼分析(個(gè)人覺得非常經(jīng)典)》。

      第一篇:struts2源代碼分析(個(gè)人覺得非常經(jīng)典)

      本章講述Struts2的工作原理。

      讀者如果曾經(jīng)學(xué)習(xí)過Struts1.x或者有過Struts1.x的開發(fā)經(jīng)驗(yàn),那么千萬不要想當(dāng)然地以為這一章可以跳過。實(shí)際上Struts1.x與Struts2并無我們想象的血緣關(guān)系。雖然Struts2的開發(fā)小組極力保留Struts1.x的習(xí)慣,但因?yàn)镾truts2的核心設(shè)計(jì)完全改變,從思想到設(shè)計(jì)到工作流程,都有了很大的不同。

      Struts2是Struts社區(qū)和WebWork社區(qū)的共同成果,我們甚至可以說,Struts2是WebWork的升級(jí)版,他采用的正是WebWork的核心,所以,Struts2并不是一個(gè)不成熟的產(chǎn)品,相反,構(gòu)建在WebWork基礎(chǔ)之上的Struts2是一個(gè)運(yùn)行穩(wěn)定、性能優(yōu)異、設(shè)計(jì)成熟的WEB框架。

      本章主要對(duì)Struts的源代碼進(jìn)行分析,因?yàn)镾truts2與WebWork的關(guān)系如此密不可分,因此,讀者需要下載xwork的源代碼,訪問http://文件,則通過過濾器鏈繼續(xù)往下傳送,直到到達(dá)請(qǐng)求的資源為止。

      如果getMapping()方法返回有效的ActionMapping對(duì)象,則被認(rèn)為正在請(qǐng)求某個(gè)Action,將調(diào)用Dispatcher.serviceAction(request, response, servletContext, mapping)方法,該方法是處理Action的關(guān)鍵所在。上述過程的源代碼如清單15所示。

      代碼清單15:FilterDispatcher.doFilter()方法

      publicvoid 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 {

      UtilTimerStack.push(timerKey);

      request = prepareDispatcherAndWrapRequest(request, response);//重新包裝request

      ActionMapping mapping;

      try {

      mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());//得到存儲(chǔ)Action信息的ActionMapping對(duì)象

      } catch(Exception ex){

      ……(省略部分代碼)

      return;

      }

      if(mapping == null){//如果mapping為null,則認(rèn)為不是請(qǐng)求Action資源

      String resourcePath = RequestUtils.getServletPath(request);

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

      resourcePath = request.getPathInfo();

      }

      {

      ngth());

      //如果請(qǐng)求的資源以/struts開頭,則當(dāng)作靜態(tài)資源處理

      if(serveStatic && resourcePath.startsWith(”/struts“))

      String name = resourcePath.substring(”/struts“.le

      findStaticResource(name, request, response);} else {

      //否則,過濾器鏈繼續(xù)往下傳遞

      chain.doFilter(request, response);}

      // The framework did its job here

      return;

      }

      //如果請(qǐng)求的資源是Action,則調(diào)用serviceAction方法。

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

      } finally {

      try {

      ActionContextCleanUp.cleanUp(req);

      }

      } finally {

      UtilTimerStack.pop(timerKey);

      } }

      這段代碼的活動(dòng)圖如圖18所示:

      (圖18)

      在Dispatcher.serviceAction()方法中,先加載Struts2的配置文件,如果沒有人為配置,則默認(rèn)加載struts-default.xml、struts-plugin.xml和struts.xml,并且將配置信息保存在形如com.opensymphony.xwork2.config.entities.XxxxConfig的類中。

      類com.opensymphony.xwork2.config.providers.XmlConfigurationProvider負(fù)責(zé)配置文件的讀取和解析,addAction()方法負(fù)責(zé)讀取標(biāo)簽,并將數(shù)據(jù)保存在ActionConfig中;addResultTypes()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為ResultTypeConfig對(duì)象;loadInterceptors()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorConfig對(duì)象;loadInterceptorStack()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorStackConfig對(duì)象;loadInterceptorStacks()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化成InterceptorStackConfig對(duì)象。而上面的方法最終會(huì)被addPackage()方法調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對(duì)象中,細(xì)節(jié)請(qǐng)參考代碼清單16。

      代碼清單16:XmlConfigurationProvider.addPackage()方法

      protected PackageConfig addPackage(Element packageElement)throws ConfigurationException {

      PackageConfig newPackage = buildPackageContext(packageElement);

      age

      if(newPackage.isNeedsRefresh()){

      return newPackage;} if(LOG.isDebugEnabled()){

      LOG.debug(”Loaded “ + newPackage);} // add result types(and default result)to this package addResultTypes(newPackage, packageElement);// load the interceptors and interceptor stacks for this packloadInterceptors(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

      loadGlobalExceptionMappings(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);

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

      return newPackage;

      }

      活動(dòng)圖如圖19所示:

      (圖19)

      配置信息加載完成后,創(chuàng)建一個(gè)Action的代理對(duì)象——ActionProxy引用,實(shí)際上對(duì)Action的調(diào)用正是通過ActionProxy實(shí)現(xiàn)的,而ActionProxy又由ActionProxyFactory創(chuàng)建,ActionProxyFactory是創(chuàng)建ActionProxy的工廠。

      注:ActionProxy和ActionProxyFactory都是接口,他們的默認(rèn)實(shí)現(xiàn)類分別是DefaultActionProxy和DefaultActionProxyFactory,位于com.opensymphony.xwork2包下。

      在這里,我們絕對(duì)有必要介紹一下com.opensymphony.xwork2.DefaultActionInvocation類,該類是對(duì)ActionInvocation接口的默認(rèn)實(shí)現(xiàn),負(fù)責(zé)Action和截?cái)r器的執(zhí)行。

      在DefaultActionInvocation類中,定義了invoke()方法,該方法實(shí)現(xiàn)了截?cái)r器的遞歸調(diào)用和執(zhí)行Action的execute()方法。其中,遞歸調(diào)用截?cái)r器的代碼如清單17所示:

      代碼清單17:調(diào)用截?cái)r器,DefaultActionInvocation.invoke()方法的部分代碼

      if(interceptors.hasNext()){

      //從截?cái)r器集合中取出當(dāng)前的截?cái)r器

      final InterceptorMapping interceptor =(InterceptorMapping)interceptors.next();

      UtilTimerStack.profile(”interceptor: “+interceptor.getName(),new UtilTimerStack.ProfilingBlock(){

      public String doProfiling()throws Exception {

      //執(zhí)行截?cái)r器(Interceptor)接口中定義的intercept方法

      resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);

      returnnull;

      }

      });

      }

      從代碼中似乎看不到截?cái)r器的遞歸調(diào)用,其實(shí)是否遞歸完全取決于程序員對(duì)程序的控制,先來看一下Interceptor接口的定義:

      代碼清單18:Interceptor.java publicinterface Interceptor extends Serializable {

      void destroy();

      void init();

      String intercept(ActionInvocation invocation)throws Exception;}

      所有的截?cái)r器必須實(shí)現(xiàn)intercept方法,而該方法的參數(shù)恰恰又是ActionInvocation,所以,如果在intercept方法中調(diào)用invocation.invoke(),代碼清單17會(huì)再次執(zhí)行,從Action的Intercepor列表中找到下一個(gè)截?cái)r器,依此遞歸。下面是一個(gè)自定義截?cái)r器示例:

      代碼清單19:CustomIntercepter.java publicclass CustomIntercepter extends AbstractInterceptor {

      @Override

      public String intercept(ActionInvocation actionInvocation)throws Exception

      } { actionInvocation.invoke();return”李贊紅“;}

      截?cái)r器的調(diào)用活動(dòng)圖如圖20所示:

      (圖20)

      如果截?cái)r器全部執(zhí)行完畢,則調(diào)用invokeActionOnly()方法執(zhí)行Action,invokeActionOnly()方法基本沒做什么工作,只調(diào)用了invokeAction()方法。

      為了執(zhí)行Action,必須先創(chuàng)建該對(duì)象,該工作在DefaultActionInvocation的構(gòu)造方法中調(diào)用init()方法早早完成。調(diào)用過程是:DefaultActionInvocation()->init()->createAction()。創(chuàng)建Action的代碼如下:

      代碼清單20:DefaultActionInvocation.createAction()方法

      protectedvoid createAction(Map contextMap){

      try {

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

      } catch(InstantiationException e){

      ……異常代碼省略

      }

      }

      Action創(chuàng)建好后,輪到invokeAction()大顯身手了,該方法比較長,但關(guān)鍵語句實(shí)在很少,用心點(diǎn)看不會(huì)很難。

      代碼清單20:DefaultActionInvocation.invokeAction()方法

      protected String invokeAction(Object action, ActionConfig actionConfig)throws Exception {

      //獲取Action中定義的execute()方法名稱,實(shí)際上該方法是可以隨便定義的

      String methodName = proxy.getMethod();

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

      try {

      UtilTimerStack.push(timerKey);

      Method method;

      try {

      //將方法名轉(zhuǎn)化成Method對(duì)象

      method = getAction().getClass().getMethod(methodName, new Class[0]);

      } catch(NoSuchMethodException e){

      // hmm--OK, try doXxx instead

      try {

      //如果Method出錯(cuò),則嘗試在方法名前加do,再轉(zhuǎn)成Method對(duì)象

      String altMethodName = ”do“ + methodName.substring(0, 1).toUpperCase()+ methodName.substring(1);

      method = getAction().getClass().getMethod(altMethodName, new Class[0]);

      } catch(NoSuchMethodException e1){

      // throw the original one

      throw e;

      }

      }

      //執(zhí)行方法

      [0]);

      }

      Object methodResult = method.invoke(action, new Object

      //處理跳轉(zhuǎn)

      if(methodResult instanceof Result){

      this.result =(Result)methodResult;

      returnnull;

      } else {

      return(String)methodResult;

      } } catch(NoSuchMethodException e){

      ……省略異常代碼 } finally {

      UtilTimerStack.pop(timerKey);}

      剛才使用了一段插述,我們繼續(xù)回到ActionProxy類。

      我們說Action的調(diào)用是通過ActionProxy實(shí)現(xiàn)的,其實(shí)就是調(diào)用了ActionProxy.execute()方法,而該方法又調(diào)用了ActionInvocation.invoke()方法。歸根到底,最后調(diào)用的是DefaultActionInvocation.invokeAction()方法。

      以下是調(diào)用關(guān)系圖:

      其中:

      ?

      ActionProxy:管理Action的生命周期,它是設(shè)置和執(zhí)行Action的起始點(diǎn)。

      ?

      ActionInvocation:在ActionProxy層之下,它表示了Action的執(zhí)行狀態(tài)。它持有Action實(shí)例和所有的Interceptor

      以下是serviceAction()方法的定義:

      代碼清單21:Dispatcher.serviceAction()方法

      publicvoid serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

      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);

      if(stack!= null){

      extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().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();

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

      proxy.setMethod(method);

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

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

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

      Result result = mapping.getResult();

      result.execute(proxy.getInvocation());

      } else {

      proxy.execute();

      }

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

      if(stack!= null){

      request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

      }

      } catch(ConfigurationException e){

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

      sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);

      } catch(Exception e){

      thrownew ServletException(e);

      } finally {

      UtilTimerStack.pop(timerKey);

      }

      }

      最后,通過Result完成頁面的跳轉(zhuǎn)。

      3.4 本小節(jié)總結(jié)

      總體來講,Struts2的工作機(jī)制比Struts1.x要復(fù)雜很多,但我們不得不佩服Struts和WebWork開發(fā)小組的功底,代碼如此優(yōu)雅,甚至能夠感受看到兩個(gè)開發(fā)小組心神相通的默契。兩個(gè)字:佩服。

      以下是Struts2運(yùn)行時(shí)調(diào)用方法的順序圖:

      (圖21)

      四、總結(jié)

      閱讀源代碼是一件非常辛苦的事,對(duì)讀者本身的要求也很高,一方面要有扎實(shí)的功底,另一方面要有超強(qiáng)的耐力和恒心。本章目的就是希望能幫助讀者理清一條思路,在必要的地方作出簡單的解釋,達(dá)到事半功倍的效果。

      當(dāng)然,筆者不可能為讀者解釋所有類,這也不是我的初衷。Struts2+xwork一共有700余類,除了為讀者做到現(xiàn)在的這些,已無法再做更多的事情。讀者可以到Struts官方網(wǎng)站下載幫助文檔,慢慢閱讀和理解,相信會(huì)受益頗豐。

      本章并不適合java語言初學(xué)者或者對(duì)java博大精深的思想理解不深的讀者閱讀,這其中涉及到太多的術(shù)語和類的使用,特別不要去鉆牛角尖,容易使自信心受損?;靖闱宄truts2的使用之后,再回過頭來閱讀本章,對(duì)一些知識(shí)點(diǎn)和思想也許會(huì)有更深的體會(huì)。

      如果讀者的java功底比較渾厚,而且對(duì)Struts2充滿興趣,但又沒太多時(shí)間研究,不妨仔細(xì)閱讀本章,再對(duì)照Struts的源代碼,希望對(duì)您有所幫助。

      第二篇:struts2代碼分析

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

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

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

      2.Struts2部分類介紹

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

      ActionMapper

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

      ActionProxy&ActionInvocation

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

      ConfigurationProvider&Configuration

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

      3.Struts2請(qǐng)求流程

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

      2、請(qǐng)求先通過ActionContextCleanUp-->FilterDispatcher

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

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

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

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

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

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

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

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

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

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

      this.initParams = initParams;

      }

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

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

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

      this.initParams = initParams;

      }

      我們?cè)倏丛贔ilterDispatcher創(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接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

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

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

      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信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

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

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進(jìn)來的initParams

      init_FilterInitParameters();// [6]

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

      init_AliasStandardObjects();// [7]

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

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

      //其中的重點(diǎn)就是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信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

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

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進(jìn)來的initParams

      init_FilterInitParameters();// [6]

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

      init_AliasStandardObjects();// [7]

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

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

      //其中的重點(diǎn)就是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接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(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實(shí)際上只是實(shí)現(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的配置信息,如果項(xiàng)目中需要覆蓋,可以在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

      //這個(gè)props是register的一個(gè)入?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的配置信息,如果項(xiàng)目中需要覆蓋,可以在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

      //這個(gè)props是register的一個(gè)入?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ù)值

      //如果

      使

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

      //如果不想使用默認(rèn)的名稱,直接在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負(fù)責(zé)解析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ù)值

      //如果

      使

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

      //如果不想使用默認(rèn)的名稱,直接在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負(fù)責(zé)解析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”);

      }

      }

      }

      對(duì)于其它配置文件只用接口。

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

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

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

      loadInterceptorStack()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorStackConfig對(duì)象;

      StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實(shí)現(xiàn)ConfigurationProviderloadInterceptorStacks()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化成InterceptorStackConfig對(duì)象。

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

      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進(jìn)行解析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”);

      //解析每個(gè)action配置是,對(duì)于include文件可以使用通配符*來進(jìn)行配置

      //如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;

      }

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

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

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

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

      this.initParams = initParams;

      }

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

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

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

      this.initParams = initParams;

      }

      我們?cè)倏丛贔ilterDispatcher創(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接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

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

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

      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信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

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

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進(jìn)來的initParams

      init_FilterInitParameters();// [6]

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

      init_AliasStandardObjects();// [7]

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

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

      //其中的重點(diǎn)就是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信息,默認(rèn)的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

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

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進(jìn)來的initParams

      init_FilterInitParameters();// [6]

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

      init_AliasStandardObjects();// [7]

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

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

      //其中的重點(diǎn)就是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接口進(jìn)行的,這個(gè)接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實(shí)例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實(shí)現(xiàn)對(duì)配置文件的屬性進(jìn)行注冊(cè)和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實(shí)際上只是實(shí)現(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實(shí)際上只是實(shí)現(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的配置信息,如果項(xiàng)目中需要覆蓋,可以在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

      //這個(gè)props是register的一個(gè)入?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的配置信息,如果項(xiàng)目中需要覆蓋,可以在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

      //這個(gè)props是register的一個(gè)入?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),用默認(rèn)的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認(rèn)的配置文件必須取名為這三個(gè)名稱了

      //如果不想使用默認(rèn)的名稱,直接在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負(fù)責(zé)解析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ù)值

      //如果

      使

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

      //如果不想使用默認(rèn)的名稱,直接在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負(fù)責(zé)解析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”);

      }

      }

      }

      對(duì)于其它配置文件只用接口。

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

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

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

      loadInterceptorStack()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化為InterceptorStackConfig對(duì)象;

      loadInterceptorStacks()方法負(fù)責(zé)將標(biāo)簽轉(zhuǎn)化成InterceptorStackConfig對(duì)象。

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

      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進(jìn)行解析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”);

      //解析每個(gè)action配置是,對(duì)于include文件可以使用通配符*來進(jìn)行配置

      //如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ù)就是默認(rèn)為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

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

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

      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ù)就是默認(rèn)為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

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

      Could

      not

      instantiate

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

      =

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

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

      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);//在這里實(shí)現(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);//在這里實(shí)現(xiàn)滴~

      }

      });

      }

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

      //重點(diǎn)就是這個(gè)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 {

      //重點(diǎn)就是這個(gè)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來完成依賴注入的功能

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

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

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

      //這一部分比較復(fù)雜,后面研究完成了,會(huì)單獨(dú)拿出來講,這里先弄清楚Xwork依賴注入的實(shí)現(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)生實(shí)例

      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()方法,這里主要是針對(duì)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的方法,每當(dāng)有一個(gè)Request,都會(huì)調(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所注入的實(shí)現(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進(jìn)行包裝

      //MultiPartRequestWrapper

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

      //此時(shí)在MultiPartRequestWrapper中就會(huì)把Files給解析出來,用于文件上傳

      //所有request都會(huì)StrutsRequestWrapper進(jìn)行包裝,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取得對(duì)應(yīng)的Action的配置信息

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

      mapping

      =

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

      } catch(Exception ex){

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

      dispatcher.sendError(request,return;

      }

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

      //這兒有個(gè)例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對(duì)應(yīng)的靜態(tài)資源并輸出到頁面流中,當(dāng)然.class文件除外。如果再?zèng)]有則跳轉(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所注入的實(shí)現(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進(jìn)行包裝

      //MultiPartRequestWrapperHttpServletRequest實(shí)現(xiàn)

      //此時(shí)在MultiPartRequestWrapper中就會(huì)把Files給解析出來,用于文件上傳

      //所有request都會(huì)StrutsRequestWrapper進(jìn)行包裝,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取得對(duì)應(yīng)的Action的配置信息

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

      mapping

      } catch(Exception ex){

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

      dispatcher.sendError(request,return;

      }

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

      //這兒有個(gè)例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對(duì)應(yīng)的靜態(tài)資源并輸出到頁面流中,當(dāng)然.class文件除外。如果再?zèng)]有則跳轉(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接口的實(shí)現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

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

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

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

      uri = dropExtension(uri, mapping);//刪除擴(kuò)展名,默認(rèn)擴(kuò)展名為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格式的請(qǐng)求路徑

      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接口的實(shí)現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

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

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

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

      uri = dropExtension(uri, mapping);//刪除擴(kuò)展名,默認(rèn)擴(kuò)展名為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格式的請(qǐng)求路徑

      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類型的對(duì)象,該對(duì)象包含三個(gè)參數(shù):Action的name、namespace和要調(diào)用的方法method。

      如果getMapping()方法返回ActionMapping對(duì)象為null,則FilterDispatcher認(rèn)為用戶請(qǐng)求不是Action,自然另當(dāng)別論,F(xiàn)ilterDispatcher會(huì)做一件非常有意思的事:如果請(qǐng)求以/struts開頭,會(huì)自動(dòng)查找在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會(huì)將com.lizanhong.action包下的文件當(dāng)作靜態(tài)資源處理,即直接在頁面上顯示文件內(nèi)容,不過會(huì)忽略擴(kuò)展名為class的文件。比如在com.lizanhong.action包下有一個(gè)aaa.txt的文本文件,其內(nèi)容為“中華人民共和國”,訪問

      http://localhost:8081/Struts2Demo/struts/aaa.txt時(shí)會(huì)輸出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);//讀取請(qǐng)求文件流

      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個(gè)字節(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);//讀取請(qǐng)求文件流

      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個(gè)字節(jié)的方式循環(huán)輸出

      copy(is, response.getOutputStream());

      } finally {

      is.close();

      }

      return;

      }

      }

      }

      }

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

      如果getMapping()方法返回有效的ActionMapping對(duì)象,則被認(rèn)為正在請(qǐng)求某個(gè)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)建一個(gè)Action的代理對(duì)象,ActionProxyFactory是創(chuàng)建ActionProxy的工廠

      //參考實(shí)現(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了.在這之前最好先去了解一下動(dòng)態(tài)Proxy的基本知識(shí).ActionProxy是Action的一個(gè)代理類,也就是說Action的調(diào)用是通過ActionProxy實(shí)現(xiàn)的,其實(shí)就是調(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中每一個(gè)Request都會(huì)創(chuàng)建一個(gè)新的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);

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

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

      //這里以Spring為例,這里會(huì)調(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

      會(huì)

      web.xml

      中的

      第三篇:Android系統(tǒng)啟動(dòng)源代碼調(diào)查分析

      Android系統(tǒng)啟動(dòng)調(diào)查。

      目的:Android程序入口在哪里?Mainifest配置文件如何加載實(shí)例化?從系統(tǒng)層到應(yīng)用層如何使用?

      目標(biāo)從系統(tǒng)角度來了解Android啟動(dòng)過程,通過下載源代碼并且根據(jù)源代碼從底層開始跟蹤,跟著方法走一遍Android啟動(dòng)過程。了解Zygote進(jìn)程是什么?

      開機(jī)一開始:Linux啟動(dòng)這一層,主要包括了兩塊:BootLoader(嵌入式系統(tǒng)的引導(dǎo)程序)和Kernel(Linux內(nèi)核層,驅(qū)動(dòng)層)第二塊:Android系統(tǒng)啟動(dòng)。

      我們都知道,Linux系統(tǒng)啟動(dòng),定義了一個(gè)Init.rc這個(gè)系統(tǒng)啟動(dòng)的配置文件(放在System/bin文件下面)。

      Init.rc啟動(dòng)的時(shí)候,最開始啟動(dòng)了SystemManager守護(hù)進(jìn)程,它的源代碼是一個(gè)Java文件,守護(hù)進(jìn)程是一個(gè)與界面無關(guān),會(huì)持續(xù)運(yùn)行在后臺(tái),用來接收響應(yīng),并且維持系統(tǒng)運(yùn)營的。

      在啟動(dòng)servicemanager的同時(shí),再來啟動(dòng)Zygote,Zygote實(shí)際上啟動(dòng)的是:app_main.cpp的系統(tǒng)文件.這個(gè)文件的main()方法,會(huì)調(diào)用Android_Runtime.cpp的文件中的start()方法,這個(gè)方法通過JNI機(jī)制,來調(diào)用ZygoteInit.java孵化器初始文件,這個(gè)文件的Main()函數(shù),將會(huì)去調(diào)用所有進(jìn)程。

      這個(gè)ZygoteInit文件的main()函數(shù),這個(gè)函數(shù)通過JNI機(jī)制調(diào)用了FrameWrok中的SystemServer文件,這個(gè)文件有三個(gè)函數(shù):main(),init1()和init2()方法。

      Init1()方法會(huì)通過JNI機(jī)制再去調(diào)用com_Android__server_SystemService.java的原生態(tài)文件,去實(shí)現(xiàn)系統(tǒng)初始化的操作,(調(diào)用System_init.cpp)。

      當(dāng)系統(tǒng)初始化工作做完之后,系統(tǒng)反過來會(huì)調(diào)用SystemServer文件下面的init2()方法,會(huì)通過runtime方法調(diào)用ServerThread進(jìn)程去調(diào)用激活其他的所有進(jìn)程。

      第三塊:應(yīng)用程序啟動(dòng)(下次再講)。

      使用工具:【代碼分析工具】source Insight 【源代碼】 Android 源代碼包

      操作步驟:

      在下載好Android SDK 安裝包之后(如果沒有下載好請(qǐng)移步這里)

      【配置代碼分析工具】

      打開source Insight 軟件,來配置Android源代碼。

      “項(xiàng)目”→“新建項(xiàng)目”

      在“新項(xiàng)目名”填寫:“Android 14”(Android 第14個(gè)版本,代表Android V4.0.3)在“項(xiàng)目文件儲(chǔ)存位置”填寫:SDK源代碼包的位置

      繼續(xù)進(jìn)行配置,點(diǎn)擊確定。

      選中右邊的所有文件夾,點(diǎn)擊“添加所有”按鈕,將這個(gè)版本的源代碼全部導(dǎo)入。

      應(yīng)用級(jí)別:選中將所有的子集目錄,下級(jí)子目錄中的所有文件都導(dǎo)入查找項(xiàng)目。

      進(jìn)行檢索。。。

      一共找到了“213720”個(gè)文件,是否導(dǎo)入?選中“Yes”

      導(dǎo)入文件,索引建立

      這時(shí)候,查看正下方,項(xiàng)目文件(213720)已經(jīng)全部導(dǎo)入,項(xiàng)目準(zhǔn)備完畢??梢赃M(jìn)行調(diào)查了。

      這時(shí)候你看到的右邊工具欄,就是我們可以用來方便查找的搜索欄,輸入對(duì)應(yīng)的關(guān)鍵字即可。

      切入正題,查找Android系統(tǒng)啟動(dòng)文件

      【查找Init文件】啟動(dòng)方法會(huì)初始化MainiFest.xml配置文件,配置文件再去調(diào)用里面的配置,但是啟動(dòng)方法何時(shí)啟動(dòng)的調(diào)查,還未找到源頭,只知道一切事物的源頭,從這里開始。

      原代碼如下:

      service console /system/bin/sh(啟動(dòng)Linux內(nèi)核)

      console

      disabled

      user shell

      group log

      on property:ro.secure=0

      start console

      # adbd is controlled by the persist.service.adb.enable system property service adbd /sbin/adbd

      disabled

      # adbd on at boot in emulator on property:ro.kernel.qemu=1

      start adbd

      on property:persist.service.adb.enable=1

      start adbd

      on property:persist.service.adb.enable=0

      stop adbd

      service servicemanager /system/bin/servicemanager(啟動(dòng)服務(wù)管理進(jìn)程)

      user system

      critical

      onrestart restart zygote

      onrestart restart media

      service vold /system/bin/vold

      socket vold stream 0660 root mount

      ioprio be 2

      service netd /system/bin/netd

      socket netd stream 0660 root system

      socket dnsproxyd stream 0660 root inet

      service debuggerd /system/bin/debuggerd

      service ril-daemon /system/bin/rild

      socket rild stream 660 root radio

      socket rild-debug stream 660 radio system

      user root

      group radio cache inet misc audio sdcard_rw

      service zygote /system/bin/app_process-Xzygote /system/bin--zygote--start-system-server

      socket zygote stream 666

      onrestart write /sys/android_power/request_state wake

      onrestart write /sys/power/state on

      onrestart restart media

      onrestart restart netd

      OK,現(xiàn)在先調(diào)查(ServerManager)這個(gè)啟動(dòng)進(jìn)程。

      在system/core/libsysutils/src 目錄下(系統(tǒng)級(jí)啟動(dòng)進(jìn)程)

      (啟動(dòng)孵化器進(jìn)程)

      在左側(cè)點(diǎn)擊start方法

      這就是守護(hù)進(jìn)程中的源代碼之一,start()方法 ServiceManager::ServiceManager(){ } int ServiceManager::start(const char *name){ //如果進(jìn)程已經(jīng)啟動(dòng),那么打印日志:“XX進(jìn)程已經(jīng)啟動(dòng)”

      if(isRunning(name)){

      SLOGW(“Service '%s' is already running”, name);

      return 0;

      }

      SLOGD(“Starting service '%s'”, name);

      property_set(“ctl.start”, name);

      int count = 200;

      while(count--){

      sched_yield();

      if(isRunning(name))

      break;

      }

      if(!count){

      SLOGW(“Timed out waiting for service '%s' to start”, name);

      errno = ETIMEDOUT;

      return-1;

      }

      SLOGD(“Sucessfully started '%s'”, name);

      return 0;}

      再來看同時(shí)啟動(dòng)的app_main的源代碼,我們?nèi)ゲ榭匆幌滤膍ain函數(shù)

      int main(int argc, const char* const argv[]){

      // These are global variables in ProcessState.cpp

      mArgC = argc;

      mArgV = argv;

      mArgLen = 0;

      for(int i=0;i

      mArgLen += strlen(argv[i])+ 1;

      }

      mArgLen--;

      AppRuntime runtime;

      const char *arg;

      const char *argv0;

      argv0 = argv[0];

      // Process command line arguments

      // ignore argv[0]

      argc--;

      argv++;

      // Everything up to '--' or first non '-' arg goes to the vm

      int i = runtime.addVmArguments(argc, argv);

      // Next arg is parent directory

      if(i < argc){

      runtime.mParentDir = argv[i++];

      }

      // Next arg is startup classname or “--zygote”

      if(i < argc){

      arg = argv[i++];

      if(0 == strcmp(“--zygote”, arg)){

      bool startSystemServer =(i < argc)?

      strcmp(argv[i], “--start-system-server”)== 0 : false;

      setArgv0(argv0, “zygote”);

      //設(shè)置了一個(gè)進(jìn)程名叫zygote的進(jìn)程,通過runtime來啟動(dòng)ZygoteInit文件中的startSystemServer方法

      set_process_name(“zygote”);

      runtime.start(“com.android.internal.os.ZygoteInit”,startSystemServer);

      } else {

      set_process_name(argv0);

      runtime.mClassName = arg;

      // Remainder of args get passed to startup class main()

      runtime.mArgC = argc-i;

      runtime.mArgV = argv+i;

      LOGV(“App process is starting with pid=%d, class=%s.n”,getpid(), runtime.getClassName());

      runtime.start();

      }

      } else {

      LOG_ALWAYS_FATAL(“app_process: no class name or--zygote supplied.”);

      fprintf(stderr, “Error: no class name or--zygote supplied.n”);

      app_usage();

      return 10;

      } } 調(diào)查一下runtime的類。AppRuntime,這就是android系統(tǒng)的運(yùn)行時(shí)類,它啟動(dòng)了zygote孵化器進(jìn)程,用來孵化Davlik虛擬機(jī)的。

      runtime.start(“com.android.internal.os.ZygoteInit”,startSystemServer);所涉及到的ZygoteInit文件。

      找到ZygoteInit文件(FrameWork里面的一個(gè)java類)。先去看看Main函數(shù)。

      public static void main(String argv[]){

      try {

      VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024);

      // Start profiling the zygote initialization.SamplingProfilerIntegration.start();

      registerZygoteSocket();

      EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());

      preloadClasses();

      //cacheRegisterMaps();

      preloadResources();

      EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());

      // Finish profiling the zygote initialization.SamplingProfilerIntegration.writeZygoteSnapshot();

      // Do an initial gc to clean up after startup

      gc();

      // If requested, start system server directly from Zygote

      if(argv.length!= 2){

      throw new RuntimeException(argv[0] + USAGE_STRING);

      }

      if(argv[1].equals(“true”)){ //如果輸入?yún)?shù)為真,我們就啟動(dòng)系統(tǒng)服務(wù)

      startSystemServer();

      } else if(!argv[1].equals(“false”)){

      throw new RuntimeException(argv[0] + USAGE_STRING);

      }

      Log.i(TAG, “Accepting command socket connections”);

      if(ZYGOTE_FORK_MODE){ //如果孵化器一直是交叉模式,就啟動(dòng)運(yùn)行交叉模式函數(shù);否則就選擇另一個(gè)循環(huán)模式

      runForkMode();

      } else {

      runSelectLoopMode();

      }

      closeServerSocket();

      } catch(MethodAndArgsCaller caller){

      caller.run();

      } catch(RuntimeException ex){

      Log.e(TAG, “Zygote died with exception”, ex);

      closeServerSocket();

      throw ex;

      }

      }

      我們繼續(xù)查看,如果參數(shù)為真的情況下,ZygoteInit文件中的,startSystemServer()函數(shù)的源代碼。

      /**

      * Prepare the arguments and fork for the system server process.*/

      private static boolean startSystemServer()

      throws MethodAndArgsCaller, RuntimeException {

      /* Hardcoded command line to start the system server */

      String args[] = {

      “--setuid=1000”,“--setgid=1000”,“--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003”,“--capabilities=130104352,130104352”,“--runtime-init”,“--nice-name=system_server”,“com.android.server.SystemServer”,//這個(gè)虛擬機(jī)的名字叫system Server

      };

      ZygoteConnection.Arguments parsedArgs = null;

      int pid;

      try {

      parsedArgs = new ZygoteConnection.Arguments(args);

      /*

      * Enable debugging of the system process if *either* the command line flags

      * indicate it should be debuggable or the ro.debuggable system property

      * is set to “1”

      */

      int debugFlags = parsedArgs.debugFlags;

      if(“1”.equals(SystemProperties.get(“ro.debuggable”)))

      debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;

      /* Request to fork the system server process */

      pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);

      } catch(IllegalArgumentException ex){

      throw new RuntimeException(ex);

      }

      /* For child process */

      if(pid == 0){

      handleSystemServerProcess(parsedArgs);

      }

      return true;

      }

      我們繼續(xù)去查看 system Server的源代碼

      main函數(shù):

      /**

      * This method is called from Zygote to initialize the system.This will cause the native

      * services(SurfaceFlinger, AudioFlinger, etc..)to be started.After that it will call back

      * up into init2()to start the Android services.*/

      native public static void init1(String[] args);//Init1()函數(shù)卻是個(gè)空函數(shù)

      public static void main(String[] args){

      if(System.currentTimeMillis()< EARLIEST_SUPPORTED_TIME){

      // If a device's clock is before 1970(before 0), a lot of

      // APIs crash dealing with negative numbers, notably

      // java.io.File#setLastModified, so instead we fake it and

      // hope that time from cell towers or NTP fixes it

      // shortly.Slog.w(TAG, “System clock is before 1970;setting to 1970.”);

      SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);

      }

      if(SamplingProfilerIntegration.isEnabled()){

      SamplingProfilerIntegration.start();

      timer = new Timer();

      timer.schedule(new TimerTask(){

      @Override

      public void run(){

      SamplingProfilerIntegration.writeSnapshot(“system_server”);

      }

      }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);

      }

      // The system server has to run all of the time, so it needs to be

      // as efficient as possible with its memory usage.VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

      System.loadLibrary(“android_servers”);

      init1(args);// main()函數(shù)中,會(huì)調(diào)用到 init1()的方法。

      }

      public static final void init2(){

      Slog.i(TAG, “Entered the Android system server!”);

      Thread thr = new ServerThread();

      thr.setName(“android.server.ServerThread”);

      thr.start();

      }

      因?yàn)橥ㄟ^調(diào)查發(fā)現(xiàn),SystemServer文件的main()函數(shù)調(diào)用的init1()函數(shù),是一個(gè)空方法,native public static void init1(String[] args);

      但是根據(jù)JNI調(diào)用機(jī)制,我們可以在同名文件夾(framework/base/services/)下找到JNL目錄,然后找到和系統(tǒng)相關(guān)的com_android_server_SystemServer.java文件

      使用“C”的動(dòng)態(tài)鏈接嗲用system_init 的方法。它去回調(diào)Init2的方法

      我們繼續(xù)看看SystemServer方法的Init2()方法是看什么用的。

      去調(diào)查一下ServerThread()方法是干什么用的?這個(gè)內(nèi)部類ServerThread就是啟動(dòng),并且實(shí)例化每一個(gè)系統(tǒng)進(jìn)程的線程類

      class ServerThread extends Thread {

      private static final String TAG = “SystemServer”;

      private final static boolean INCLUDE_DEMO = false;

      private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010;

      private ContentResolver mContentResolver;

      private class AdbSettingsObserver extends ContentObserver {

      public AdbSettingsObserver(){

      super(null);

      }

      @Override

      public void onChange(boolean selfChange){

      boolean enableAdb =(Settings.Secure.getInt(mContentResolver,Settings.Secure.ADB_ENABLED, 0)> 0);

      // setting this secure property will start or stop adbd

      SystemProperties.set(“persist.service.adb.enable”, enableAdb ? “1” : “0”);

      }

      }

      @Override

      public void run(){

      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,SystemClock.uptimeMillis());

      Looper.prepare();

      android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);

      BinderInternal.disableBackgroundScheduling(true);

      android.os.Process.setCanSelfBackground(false);

      // Check whether we failed to shut down last time we tried.{

      final String shutdownAction = SystemProperties.get(ShutdownThread.SHUTDOWN_ACTION_PROPERTY, “");

      if(shutdownAction!= null && shutdownAction.length()> 0){

      boolean reboot =(shutdownAction.charAt(0)== '1');

      final String reason;

      if(shutdownAction.length()> 1){

      reason = shutdownAction.substring(1, shutdownAction.length());

      } else {

      reason = null;

      }

      ShutdownThread.rebootOrShutdown(reboot, reason);

      }

      }

      String factoryTestStr = SystemProperties.get(”ro.factorytest“);

      int factoryTest = ”“.equals(factoryTestStr)? SystemServer.FACTORY_TEST_OFF

      : Integer.parseInt(factoryTestStr);

      LightsService lights = null;

      PowerManagerService power = null;

      BatteryService battery = null;

      ConnectivityService connectivity = null;

      IPackageManager pm = null;

      Context context = null;

      WindowManagerService wm = null;

      BluetoothService bluetooth = null;

      BluetoothA2dpService bluetoothA2dp = null;

      HeadsetObserver headset = null;

      DockObserver dock = null;

      UsbService usb = null;

      UiModeManagerService uiMode = null;

      RecognitionManagerService recognition = null;

      ThrottleService throttle = null;

      // Critical services...try {

      Slog.i(TAG, ”Entropy Service“);

      ServiceManager.addService(”entropy“, new EntropyService());

      Slog.i(TAG, ”Power Manager“);

      power = new PowerManagerService();

      ServiceManager.addService(Context.POWER_SERVICE, power);

      Slog.i(TAG, ”Activity Manager“);

      context = ActivityManagerService.main(factoryTest);

      Slog.i(TAG, ”Telephony Registry“);

      ServiceManager.addService(”telephony.registry“, new TelephonyRegistry(context));

      AttributeCache.init(context);

      Slog.i(TAG, ”Package Manager“);

      pm = PackageManagerService.main(context,factoryTest!= SystemServer.FACTORY_TEST_OFF);

      ActivityManagerService.setSystemProcess();

      mContentResolver = context.getContentResolver();

      // The AccountManager must come before the ContentService

      try {

      Slog.i(TAG, ”Account Manager“);

      ServiceManager.addService(Context.ACCOUNT_SERVICE,new AccountManagerService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Account Manager“, e);

      }

      Slog.i(TAG, ”Content Manager“);

      ContentService.main(context,factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);

      Slog.i(TAG, ”System Content Providers“);

      ActivityManagerService.installSystemProviders();

      Slog.i(TAG, ”Battery Service“);

      battery = new BatteryService(context);

      ServiceManager.addService(”battery“, battery);

      Slog.i(TAG, ”Lights Service“);

      lights = new LightsService(context);

      Slog.i(TAG, ”Vibrator Service“);

      ServiceManager.addService(”vibrator“, new VibratorService(context));

      // only initialize the power service after we have started the

      // lights service, content providers and the battery service.power.init(context, lights, ActivityManagerService.getDefault(), battery);

      Slog.i(TAG, ”Alarm Manager“);

      AlarmManagerService alarm = new AlarmManagerService(context);

      ServiceManager.addService(Context.ALARM_SERVICE, alarm);

      Slog.i(TAG, ”Init Watchdog“);

      Watchdog.getInstance().init(context, battery, power, alarm,ActivityManagerService.self());

      Slog.i(TAG, ”Window Manager“);

      wm = WindowManagerService.main(context, power,factoryTest!= SystemServer.FACTORY_TEST_LOW_LEVEL);

      ServiceManager.addService(Context.WINDOW_SERVICE, wm);

      ((ActivityManagerService)ServiceManager.getService(”activity“)).setWindowManager(wm);

      // Skip Bluetooth if we have an emulator kernel

      // TODO: Use a more reliable check to see if this product should

      // support Bluetooth-see bug 988521

      if(SystemProperties.get(”ro.kernel.qemu“).equals(”1“)){

      Slog.i(TAG, ”Registering null Bluetooth Service(emulator)“);

      ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);

      } else if(factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL){

      Slog.i(TAG, ”Registering null Bluetooth Service(factory test)“);

      ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);

      } else {

      Slog.i(TAG, ”Bluetooth Service“);

      bluetooth = new BluetoothService(context);

      ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);

      bluetooth.initAfterRegistration();

      bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);

      ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,bluetoothA2dp);

      int bluetoothOn = Settings.Secure.getInt(mContentResolver,Settings.Secure.BLUETOOTH_ON, 0);

      if(bluetoothOn > 0){

      bluetooth.enable();

      }

      }

      } catch(RuntimeException e){

      Slog.e(”System“, ”Failure starting core service“, e);

      }

      DevicePolicyManagerService devicePolicy = null;

      StatusBarManagerService statusBar = null;

      InputMethodManagerService imm = null;

      AppWidgetService appWidget = null;

      NotificationManagerService notification = null;

      WallpaperManagerService wallpaper = null;

      LocationManagerService location = null;

      if(factoryTest!= SystemServer.FACTORY_TEST_LOW_LEVEL){

      try {

      Slog.i(TAG, ”Device Policy“);

      devicePolicy = new DevicePolicyManagerService(context);

      ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting DevicePolicyService“, e);

      }

      try {

      Slog.i(TAG, ”Status Bar“);

      statusBar = new StatusBarManagerService(context);

      ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting StatusBarManagerService“, e);

      }

      try {

      Slog.i(TAG, ”Clipboard Service“);

      ServiceManager.addService(Context.CLIPBOARD_SERVICE,new ClipboardService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Clipboard Service“, e);

      }

      try {

      Slog.i(TAG, ”Input Method Service“);

      imm = new InputMethodManagerService(context, statusBar);

      ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Input Manager Service“, e);

      }

      try {

      Slog.i(TAG, ”NetStat Service“);

      ServiceManager.addService(”netstat“, new NetStatService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting NetStat Service“, e);

      }

      try {

      Slog.i(TAG, ”NetworkManagement Service“);

      ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE,NetworkManagementService.create(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting NetworkManagement Service“, e);

      }

      try {

      Slog.i(TAG, ”Connectivity Service“);

      connectivity = ConnectivityService.getInstance(context);

      ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Connectivity Service“, e);

      }

      try {

      Slog.i(TAG, ”Throttle Service“);

      throttle = new ThrottleService(context);

      ServiceManager.addService(Context.THROTTLE_SERVICE, throttle);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting ThrottleService“, e);

      }

      try {

      Slog.i(TAG, ”Accessibility Manager“);

      ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,new AccessibilityManagerService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Accessibility Manager“, e);

      }

      try {

      /*

      * NotificationManagerService is dependant on MountService,*(for media / usb notifications)so we must start MountService first.*/

      Slog.i(TAG, ”Mount Service“);

      ServiceManager.addService(”mount“, new MountService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Mount Service“, e);

      }

      try {

      Slog.i(TAG, ”Notification Manager“);

      notification = new NotificationManagerService(context, statusBar, lights);

      ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Notification Manager“, e);

      }

      try {

      Slog.i(TAG, ”Device Storage Monitor“);

      ServiceManager.addService(DeviceStorageMonitorService.SERVICE,new DeviceStorageMonitorService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting DeviceStorageMonitor service“, e);

      }

      try {

      Slog.i(TAG, ”Location Manager“);

      location = new LocationManagerService(context);

      ServiceManager.addService(Context.LOCATION_SERVICE, location);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Location Manager“, e);

      }

      try {

      Slog.i(TAG, ”Search Service“);

      ServiceManager.addService(Context.SEARCH_SERVICE,new SearchManagerService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Search Service“, e);

      }

      if(INCLUDE_DEMO){

      Slog.i(TAG, ”Installing demo data...“);

      (new DemoThread(context)).start();

      }

      try {

      Slog.i(TAG, ”DropBox Service“);

      ServiceManager.addService(Context.DROPBOX_SERVICE,new DropBoxManagerService(context, new File(”/data/system/dropbox“)));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting DropBoxManagerService“, e);

      }

      try {

      Slog.i(TAG, ”Wallpaper Service“);

      wallpaper = new WallpaperManagerService(context);

      ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Wallpaper Service“, e);

      }

      try {

      Slog.i(TAG, ”Audio Service“);

      ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting Audio Service“, e);

      }

      try {

      Slog.i(TAG, ”Headset Observer“);

      // Listen for wired headset changes

      headset = new HeadsetObserver(context);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting HeadsetObserver“, e);

      }

      try {

      Slog.i(TAG, ”Dock Observer“);

      // Listen for dock station changes

      dock = new DockObserver(context, power);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting DockObserver“, e);

      }

      try {

      Slog.i(TAG, ”USB Service“);

      // Listen for USB changes

      usb = new UsbService(context);

      ServiceManager.addService(Context.USB_SERVICE, usb);

      } catch(Throwable e){

      Slog.e(TAG, ”Failure starting UsbService“, e);

      }

      try {

      Slog.i(TAG, ”UI Mode Manager Service");

      第四篇:非常完美電視節(jié)目分析

      三、非常完美電視節(jié)目分析

      節(jié)目類型:綜藝類相親節(jié)目 節(jié)目時(shí)常:1h30min 目標(biāo)人群:適齡男女及其父母

      一:片頭 15s AE 二:內(nèi)容

      1、主持人出場(chǎng)、喊口號(hào)(接廣告)50s 現(xiàn)場(chǎng)畫面

      2、主持人引入、嘉賓出場(chǎng) 1min50s 現(xiàn)場(chǎng)畫面

      3、戀愛公開課 2min30s VCR短片

      4、女嘉賓1 17min25s VCR自我介紹 現(xiàn)場(chǎng)畫面 人物出場(chǎng) 現(xiàn)場(chǎng)畫面 男嘉賓表態(tài) 現(xiàn)場(chǎng)畫面 摘面具 現(xiàn)場(chǎng)畫面 選擇心動(dòng)男生 現(xiàn)場(chǎng)畫面 與男嘉賓互動(dòng) 現(xiàn)場(chǎng)畫面+彈幕 男嘉賓進(jìn)行選擇 現(xiàn)場(chǎng)畫面 女生告白環(huán)節(jié) 現(xiàn)場(chǎng)畫面+VCR 情感專家點(diǎn)評(píng) 現(xiàn)場(chǎng)畫面

      5、女嘉賓 2 略

      VCR自我介紹 現(xiàn)場(chǎng)畫面 人物出場(chǎng) 現(xiàn)場(chǎng)畫面 男嘉賓表態(tài) 現(xiàn)場(chǎng)畫面 摘面具 現(xiàn)場(chǎng)畫面 女生告白環(huán)節(jié) 現(xiàn)場(chǎng)畫面+視頻 男嘉賓反問 現(xiàn)場(chǎng)畫面 四位嘉賓環(huán)節(jié)類似

      6、結(jié)尾

      節(jié)目總結(jié):

      節(jié)目亮點(diǎn):往期節(jié)目的亮點(diǎn)在于男嘉賓

      個(gè)人感受:此檔節(jié)目屬于綜藝類相親節(jié)目,節(jié)目制作的主要難點(diǎn)在于主持人對(duì)于現(xiàn)場(chǎng)的把控、以及情感專家對(duì)問題的點(diǎn)評(píng);在拍攝過程中,沒有太多復(fù)雜的鏡頭需要去拍,主要以固定鏡頭搖鏡頭為主。本期節(jié)目,編導(dǎo)對(duì)節(jié)目重心選擇有誤,主要的節(jié)目都在嘉賓方面,內(nèi)容拖沓,主持人缺乏引入,專家露面太少,告別部分過于狗血,強(qiáng)行煽淚。男嘉賓一直是那幾位,看過了很多期次節(jié)目之后,感覺已經(jīng)沒有可以吸引女性觀眾眼球的地方。

      第五篇:我個(gè)人覺得一節(jié)語文課

      我個(gè)人覺得一節(jié)語文課,如果開頭導(dǎo)入得好,這節(jié)課也就成功了一半。這位老師做到了!以講故事的形式開始一節(jié)課,吸引學(xué)生的興趣,講到興頭上時(shí),老師突然打住,說:“想知道下面發(fā)生了什么嗎?好,打開課本,看課文?!敝圃炝藨夷?,讓學(xué)生想學(xué)課文,激發(fā)求知的欲望。并且這位老師在讓學(xué)生讀課文的時(shí)候也指出了朗讀要求,如:注意生字讀音,大聲讀課文,標(biāo)出自然段。

      很喜歡這位老師語文課閱讀的方式,多樣有趣。有開火車式的,一人讀一段,分自然段讀;整體讀,或者互相讀,在學(xué)生讀的過程中,老師走下講臺(tái)進(jìn)行個(gè)別輔導(dǎo)。

      在基礎(chǔ)知識(shí)解決完了之后,直接進(jìn)入課文的學(xué)習(xí)階段。由老師讀課文,幫助學(xué)生正字正音。然后提問學(xué)生,讀完之后知道什么,不明白什么。學(xué)生也很配合,大膽提出了很多稀奇古怪的問題,不過這也正表明孩子們天真的想象力,他們敢于說出自己內(nèi)心的想法,哪怕很簡單甚至很愚蠢,作為教師都應(yīng)該去鼓勵(lì),而不是批評(píng)。這位老師對(duì)于學(xué)生提出的問題都很肯定,并讓學(xué)生回到課文里去找尋答案,這種做法,可以讓學(xué)生通過讀課文,自己獨(dú)立解決先前提出的問題。之后老師運(yùn)用多媒體展示船行的過程以及劍掉入江里的動(dòng)態(tài)圖畫,幫助學(xué)生理解,以便于學(xué)生回答自己提出的諸多問題。

      這位老師還注意課堂學(xué)生的交流合作,就能否撈劍這一話題讓學(xué)生進(jìn)行討論并闡述理由。老師走下去個(gè)別交流,了解學(xué)生的想法。在撈得著與撈不著之間展開討論分析,各圓其說,發(fā)散思維,只要說的有道理,老師都用一種肯定的眼神關(guān)注著這個(gè)學(xué)生。老師運(yùn)用紙片展示船行的過程,解釋為什么撈不到劍,也就順理成章。

      最后,由課文聯(lián)系到自己的生活,學(xué)到了什么,揭示課文的主旨。這篇課文的學(xué)習(xí)也就暫告一段落了??傮w上感覺符合小學(xué)生的認(rèn)知結(jié)構(gòu),從趣味入手,讓學(xué)生快樂學(xué)習(xí)。

      有一點(diǎn)我不太明白,為什么要讓學(xué)生把書反過來放在桌上,語文課,不是讓學(xué)生直接面對(duì)課文嗎?這樣做難道是為了讓學(xué)生對(duì)剛才的閱讀進(jìn)行回顧?這是一節(jié)新課,不是復(fù)習(xí)課??!

      下載struts2源代碼分析(個(gè)人覺得非常經(jīng)典)word格式文檔
      下載struts2源代碼分析(個(gè)人覺得非常經(jīng)典).doc
      將本文檔下載到自己電腦,方便修改和收藏,請(qǐng)勿使用迅雷等下載。
      點(diǎn)此處下載文檔

      文檔為doc格式


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

      相關(guān)范文推薦

        個(gè)人通訊錄管理系統(tǒng),java源代碼

        package cn.pab.manager; import java.util.List; import java.util.Scanner; import cn.pab.dao.PersonDao; import cn.pab.dao.TypeDao; import cn.pab.dao.UserDao; im......

        個(gè)人述職報(bào)告模板(非常實(shí)用)

        個(gè)人述職報(bào)告模板(非常實(shí)用)述職是管理干部依據(jù)自己的職務(wù)要求,就一定時(shí)期內(nèi)的任期目標(biāo),向主管部門及本企業(yè)的全體工友,匯報(bào)自己履行崗位責(zé)任情況,是干部管理考核的一種形式。個(gè)......

        個(gè)人優(yōu)缺點(diǎn)評(píng)價(jià)(非常實(shí)用)

        個(gè)人優(yōu)缺點(diǎn)評(píng)價(jià)(非常實(shí)用) 1. 優(yōu)點(diǎn):樂于助人,善于團(tuán)結(jié),吃苦耐勞,平易近人。 缺點(diǎn):工作作風(fēng)過于拘謹(jǐn)不夠大膽 2.優(yōu)點(diǎn):尊敬師長,團(tuán)結(jié)同學(xué),樂于助人,是老師的好幫手,同學(xué)的好朋友, 學(xué)習(xí)勤奮,積......

        個(gè)人覺得比較好的英文句子

        英語名句 1. ...And so on and forth and so fifth! 真是沒完沒了!2.Age before beauty! 長者優(yōu)先。3.Old habits die hard! 積習(xí)難改。4.Never say die. 永不言敗。5.Hang i......

        C語言面試題大匯總,個(gè)人覺得還是比較全

        4. static有什么用途?(請(qǐng)至少說明兩種) 1.限制變量的作用域 2.設(shè)置變量的存儲(chǔ)域 7. 引用與指針有什么區(qū)別? 1) 引用必須被初始化,指針不必。 2) 引用初始化以后不能被改變,指針可......

        就業(yè)指導(dǎo)ppt整理(個(gè)人覺得相對(duì)比較重要的)(推薦)

        就業(yè)指導(dǎo)ppt整理 派遣的有關(guān)規(guī)定: (1)畢業(yè)生的報(bào)到期限一般為一個(gè)月。 (2)畢業(yè)生上半月報(bào)到的,發(fā)給全月工資;下半月報(bào)到的,發(fā)給半月工資。 (3)三年以上固定期限和無固定期限勞動(dòng)合同的......

        銀行個(gè)人述職報(bào)告(非常不錯(cuò))

        尊敬的各位領(lǐng)導(dǎo)、同事們,大家好! 2010年是我從事客戶工作的第一年。這一年櫛風(fēng)沐雨、耕耘收獲;這一年忙碌充實(shí)、緊張有序;這一年學(xué)習(xí)思考、感觸良多。 感觸之一:德行品質(zhì)得到了鍛......

        非常實(shí)用的個(gè)人述職報(bào)告供借鑒

        5篇非常實(shí)用的個(gè)人述職報(bào)告供借鑒尊敬的領(lǐng)導(dǎo):今年,在各級(jí)領(lǐng)導(dǎo)的正確指引下,我始終恪盡職守、團(tuán)結(jié)同事,堅(jiān)決服從各項(xiàng)管理方針、政策,想方設(shè)法推進(jìn)工作進(jìn)步。以下是本人的述職報(bào)告:......