现在的位置: 首页 > 综合 > 正文

struts2核心流程源码分析

2013年06月28日 ⁄ 综合 ⁄ 共 17733字 ⁄ 字号 评论关闭

Struts2的初始化

StrutsPrepareAndExecuteFilter

属性摘要

protected  List<Pattern>

excludedPatterns

protected  ExecuteOperations

execute

protected  PrepareOperations

prepare


1、初始化过程

1.  public void  init(FilterConfig filterConfig){  

2.     InitOperations init = new  InitOperations();  

3.      //封装filterConfig。方法getInitParameterNames将参数名以String存入List

4.     FilterHostConfig config = new  FilterHostConfig(filterConfig);  

5.      // 初始化struts内部日志   

6.     init.initLogging(config);  

7.      //创建dispatcher 。并初始化,这部分下面我们重点分析,初始化时加载那些资源

8.     Dispatcher dispatcher = init.initDispatcher(config);  

9.     init.initStaticContentLoader(config, dispatcher);  

10.     //初始化类属性:prepare execute    

11.    prepare = new  PrepareOperations(filterConfig.getServletContext(), dispatcher);  

12.    execute = new  ExecuteOperations(filterConfig.getServletContext(), dispatcher);  

13.    this .excludedPatterns = init.buildExcludedPatternsList(dispatcher);  

14.

1.1、封装filterConfig

1.  public class FilterHostConfig implements HostConfig {  

2.      private FilterConfig config;  

3.      public FilterHostConfig(FilterConfig config) {  

4.          this.config = config;  

5.      }  

6.      //根据init-param配置的param-name获取param-value的值   

7.      public String getInitParameter(String key) {  

8.          return config.getInitParameter(key);  

9.      }  

10.    //返回初始化参数名的List 

11.     public Iterator<String> getInitParameterNames() {  

12.         return MakeIterator.convert(config.getInitParameterNames());  

13.     }  

14.     public ServletContext getServletContext() {  

15.         return config.getServletContext();  

16.     }  

17. }

只有短短的几行代码,将Filter初始化参数名称有枚举类型转为Iterator,此类的主要作为是对filterConfig 封装。

创建并初始化Dispatcher 

1.  public Dispatcher initDispatcher( HostConfig filterConfig ) {  

2.         Dispatcher dispatcher = createDispatcher(filterConfig);  

3.         dispatcher.init();  

4.         return dispatcher;  

5.     } 

创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher:

1.  private Dispatcher createDispatcher( HostConfig filterConfig ) {  

2.      Map<String, String> params = new HashMap<String, String>();  

3.      for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); )

4.           String name = (String) e.next();  

5.          String value = filterConfig.getInitParameter(name);  

6.          params.put(name, value);  

7.      }  

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

9.  }  

Dispatcher初始化过程主要内容如图,

1. public void init() {  

2.    if (configurationManager == null) {  

3.      configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);  

4.    }  

5.      //封装org/apache/struts2/default.properties  

6.      init_DefaultProperties(); // [1]  

7.      //封装struts-default.xml,struts-plugin.xml,struts.xml  

8.      init_TraditionalXmlConfigurations(); // [2]  

9.      init_LegacyStrutsProperties(); // [3]  

10.     //封装用户自己实现的ConfigurationProviders              

11.     init_CustomConfigurationProviders(); // [5]  

12.     //Filter的初始化参数  

13.     init_FilterInitParameters() ; // [6]  

14.     init_AliasStandardObjects() ; // [7]  

15.      //此处最为关键,加载[1-7]对象代表的配置中的数据。

16.     Container container = init_PreloadConfiguration();  

17.      container.inject(this);   

18.      init_CheckWebLogicWorkaround(container);  

19.     
//
添加dispatcherlistener

20.      if (!dispatcherListeners.isEmpty()) {  

21.          for (DispatcherListener l : dispatcherListeners) {  

22.               l.dispatcherInitialized(this);  

23.           }  

24.      }  

25.    }  

所要加载struts2的相关配置文件包括default.properties,struts-default.xml,struts-plugin.xml,struts.xml……

[1-7]的过程是将所有的配置信息封装为ConfigurationProviders对象,并在创建container的时候加载所有的配置数据,init_PreloadConfiguration函数执行加载过程。

封装为ConfigurationProvier对象

 以default.properties为例,具体的封装操作如下:

1.  private void init_DefaultProperties() {  

2.      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());  

3.  }  

配置文件加载过程

Dispatcher.java文件

1.private Containerinit_PreloadConfiguration() {

2.   //创建配置管理和Container对象

3.    Configuration config =
configurationManager
.getConfiguration();

4.    Container container =config.getContainer();

5.   
//
设置多语言变量

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

7.    LocalizedTextUtil.setReloadBundles(reloadi18n);

8.    ContainerHolder.store(container);

9.    return container;

10.  }

ConfigurationManager.java

1.   publicsynchronizedConfiguration getConfiguration() {

2.      //创建配置管理对象

3.      setConfiguration(createConfiguration(defaultFrameworkBeanName));

4.     //添加所有配置文件的文件管理器到配置管理器中

5.     configuration.reloadContainer(getContainerProviders());

6.     returnconfiguration;

7.   }

8.  protected Configuration createConfiguration(String beanName) {

9.      returnnewDefaultConfiguration(beanName);

10.  }

DefaultConfiguration.java

开始加载Provider中的数据

1.    publicsynchronizedList<PackageProvider> reloadContainer(List<ContainerProvider>providers)  {

2.     

3.       packageContexts.clear();

4.       loadedFileNames.clear();

5.       List<PackageProvider>packageProviders =new ArrayList<PackageProvider>();

6.       ContainerProperties props =new ContainerProperties();

7.       ContainerBuilder builder =new ContainerBuilder();

8.       //ContainerBuilder使用反射机制和注入建立基本的containerfactory

9.       Container bootstrap =createBootstrapContainer(providers);

10.     for (final ContainerProvider containerProvider :providers)

11.     {

12.     bootstrap.inject(containerProvider);

13.     //配置文件的ConfigurationProviders读取各自的配置文件,将数据以文档对象的加入container

14.     containerProvider.init(this);

15.     //调用register方法开始加载document对象中的部分非以包组合的信息,以StrutsXmlConfigurationProvider为例加载beanconstant,其他provider各有不同

16.     containerProvider.register(builder,props);

17.     }

18.     props.setConstants(builder);

19.     builder.factory(Configuration.class,newFactory<Configuration>() {

20.        public Configuration create(Context context)throws Exception {

21.        return DefaultConfiguration.this;

22.     }

23.     });

24.     ActionContext oldContext =ActionContext.getContext();

25.     // Set the bootstrap container forthe purposes of factory creation

26.     setContext(bootstrap);

27.     container = builder.create(false);

28.     setContext(container);

29.     objectFactory =container.getInstance(ObjectFactory.class);

30.     //先处理配置文件的ContainerProvider,加载其中的包节点下的数据,并将container放入  packageProviders

31.     for (final ContainerProvider containerProvider :providers)

32.     {

33.        if (containerProviderinstanceof PackageProvider){

34.        container.inject(containerProvider);

35.        //此处是重点,里面加载了包节点下的所有数据

36.         ((PackageProvider)containerProvider).loadPackages();

37.        packageProviders.add((PackageProvider)containerProvider);

38.        }

39.     }

40.     //处理来自插件的PackageProvider,同上的处理数据

41.     Set<String>packageProviderNames =       container.getInstanceNames(PackageProvider.class);

42.     for (String name : packageProviderNames) {

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

44.        provider.init(this);

45.        provider.loadPackages();

46.        packageProviders.add(provider);

47.     }

48.     rebuildRuntimeConfiguration();

49.     return packageProviders;

50.  }

以StrutsXmlConfigurationProvider为例

1.   publicvoid loadPackages()throws ConfigurationException{

2.      List<Element> reloads =newArrayList<Element>();

3.      verifyPackageStructure();

4.      //逐个文档处理对象

5.      for (Document doc :documents) {

6.         Element rootElement =doc.getDocumentElement();

7.         NodeList children =rootElement.getChildNodes();

8.         int childSize = children.getLength();

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

10.           Node childNode = children.item(i);

11.           if (childNodeinstanceof Element) {

12.              Element child =(Element) childNode;

13.              final String nodeName =child.getNodeName();

14.              if ("package".equals(nodeName)){  //处理包节点下的数据

15.                 PackageConfig cfg =addPackage(child);     

16.              }

17.           }

18.        }

19.     }

20.     documents.clear();

21.     declaredPackages.clear();

22.     configuration =null;

23.  }

以下过程是按照不同的类型加载包节点下的相应的节点信息

1.  protected PackageConfigaddPackage(Element packageElement) {

2.      String packageName =packageElement.getAttribute("name");

3.      PackageConfig packageConfig =configuration.getPackageConfig(packageName);

4.      PackageConfig.Builder newPackage =buildPackageContext(packageElement);

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

6.      addResultTypes(newPackage, packageElement);

7.      // load theinterceptors and interceptor stacks for this package

8.      loadInterceptors(newPackage, packageElement);

9.      // load the default interceptor reference for thispackage

10.     loadDefaultInterceptorRef(newPackage,packageElement);

11.     // load the defaultclass ref for this package

12.     loadDefaultClassRef(newPackage,packageElement);

13.     // load the globalresult list for this package

14.     loadGlobalResults(newPackage,packageElement);

15.     // load the global exception handler list for thispackage

16.     loadGobalExceptionMappings(newPackage,packageElement);

17.     // get actions

18.     NodeListactionList = packageElement.getElementsByTagName("action");

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

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

21.        addAction(actionElement, newPackage);

22.     }

23.     // load the defaultaction reference for this package

24.     loadDefaultActionRef(newPackage,packageElement);

25.     PackageConfig cfg = newPackage.build();

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

27.     return cfg;

28. }

至此配置文件的加载过程完毕

运行过程:doFilter方法

1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {  

2.    HttpServletRequest request = (HttpServletRequest) req;  

3.    HttpServletResponse response = (HttpServletResponse) res;  

4.    //设置编码和国际化  

5.    prepare.setEncodingAndLocale(request, response);  

6.    //创建Action上下文(重点)  

7.    prepare.createActionContext(request, response);  

8.    //以初始化的dispatcher为模板构复制一个dispatcher给线程

9.    prepare.assignDispatcherToThread();  

10.     request = prepare.wrapRequest(request);  

11.     //根据请求从configureManager获得数据,创建mapping对象

12.     ActionMapping mapping = prepare.findActionMapping(request, response, true);

13.     //根据mapping执行映射的action

14.     execute.executeAction(request, response, mapping);  

15.  }  

 

1. //Sets the request encoding and locale on the response 

2. public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {  

3.         dispatcher.prepare(request, response);  

4. }  

   下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:

1. public   void  prepare(HttpServletRequest request, HttpServletResponse response) {  

2.    String encoding = null ;  

3.    if  (defaultEncoding !=  null ) {  

4.         encoding = defaultEncoding;  

5.     }  

6.     Locale locale = null ;  

7.     if  (defaultLocale !=  null ) {  

8.         locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  

9.     }    

10.    if  (encoding !=  null ) {  

11.         request.setCharacterEncoding(encoding);  

12.     }  

13.     if  (locale !=  null ) {  

14.         response.setLocale(locale);  

15.     }    

16.     if  (paramsWorkaroundEnabled) {  

17.         request.getParameter("foo" );  // simply read any parameter (existing or not) to "prime" the request      

18.      }  

19.}

   Action上下文创建(重点)

      ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信息。其实质是一个Map,key是标志request、session、……的字符串,值是其对应的对象:

1. static  ThreadLocal actionContext =  new  ThreadLocal();  

2. Map<String, Object> context;  

 下面我们看下如何创建action上下文的,代码如下:  

1. //创建Action上下文,初始化thread local   

2. public  ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {  

3.     ActionContext ctx;  

4.     Integer counter = 1 ;  

5.     Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);  

6.     if  (oldCounter !=  null ) {  

7.         counter = oldCounter + 1 ;  

8.     }  

9.     //ThreadLocal中获取此ActionContext变量   

10.    ActionContext oldContext = ActionContext.getContext();  

11.    if  (oldContext !=  null ) {  

12.        // detected existing context, so we are probably in a forward   

13.        ctx = new  ActionContext( new  HashMap<String, Object>(oldContext.getContextMap()));  

14.    } else  {  

15.        ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class ).createValueStack();  

16.         //将数据放入stack._values

17.        stack.getContext().putAll(dispatcher.createContextMap(request, response, null , servletContext));  

18.        //stack.getContext()返回的是一个Map<StringObject>,根据此Map构造一个ActionContext

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

20.    }  

21.    request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);  

22.    //ActionContext存如ThreadLocal   

23.    ActionContext.setContext(ctx);  

24.    return  ctx;  

25.}  

dispatcher.createContextMap,如何封装相关参数:

1.  public  Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,ActionMapping mapping, ServletContext context) {  

2.     Map requestMap = new  RequestMap(request);     

3.     Map params = new  HashMap(request.getParameterMap());     

4.     Map session = new  SessionMap(request);    

5.     Map application = new  ApplicationMap(context);  

6.     //requestMapparamssession等封装为map逐个放入extraContext

7.     Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);    

8.    if  (mapping !=  null ) {  

9.         extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);  

10.   } 

11.   return  extraContext;  

12.

ActionMapping的映射关系的查找过程

1. publicActionMappingfindActionMapping(HttpServletRequest request, HttpServletResponse response,booleanforceLookup)
{

2.    mapping =dispatcher.getContainer().getInstance(ActionMapper.class)

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

4.    if(mapping !=null) {

5.    request.setAttribute(STRUTS_ACTION_MAPPING_KEY,mapping);

6.    }

7.    returnmapping;

8. }

1. publicActionMappinggetMapping(HttpServletRequest request, ConfigurationManager configManager) {

2.     ActionMapping mapping = newActionMapping();

3.     //request获取uri

4.     Stringuri = getUri(request);

5.     intindexOfSemicolon =uri.indexOf(";");

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

7.     //去除扩展名,".xhtml"

8.     uri = dropExtension(uri,mapping);

9.     //根据最长匹配从configureManager获取actionnamespace,并放入mapping

10.    parseNameAndNamespace(uri,mapping, configManager);

11.    //处理特殊格式的请求参数

12.    handleSpecialParameters(request,mapping);

13.    //如果有DMC的调用则,解析method

14.    return parseActionName(mapping);

15.}

下面是源码展示了如何执行Action控制器:

1. public  void  executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) {  

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

3. }  

4.   

5. public void  serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping)
{  

6.      //封装执行的上下文环境,主要讲相关信息存储入map   

7.      Map<String, Object> extraContext = createContextMap(request, response, mapping, context);    

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

9.     ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);  

10.    boolean  nullStack = stack ==  null ;  

11.    if  (nullStack) {  

12.         ActionContext ctx = ActionContext.getContext();  

13.         stack = ctx.getValueStack();  

14.    }  

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

16.    //获取命名空间   

17.    String namespace = mapping.getNamespace();  

18.    //获取action配置的name属性   

19.    String name = mapping.getName();  

20.    //获取action配置的method属性   

21.    String method = mapping.getMethod();    

22.     Configuration config = configurationManager.getConfiguration();  

23.     //根据执行上下文参数,命名空间,名称等创建用户自定义Action的代理对象   

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

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

26.     //执行execute方法,并转向结果   

27.     proxy.execute();  

28.}  

 

下面是ActionProxy创建的过程

1.   public ActionProxycreateActionProxy(String namespace, String actionName, String methodName,Map<String, Object> extraContext,boolean
executeResult, boolean cleanupContext) {

2.       ActionInvocation inv =newDefaultActionInvocation(extraContext,true);

3.       container.inject(inv);

4.       return createActionProxy(inv, namespace,actionName, methodName, executeResult, cleanupContext);

5.   }

ActionProxy的执行过程

1.   public String execute()throws Exception {

2.       ActionContext previous =ActionContext.getContext();

3.       ActionContext.setContext(invocation.getInvocationContext());

4.       returninvocation.invoke();

5.   }

如果截拦器全部执行完毕,则执行invokeActionOnly()方法执行Action,invokeActionOnly()方法基本没做什么工作,只调用了invokeAction()方法。为了执行Action,必须先创建该对象,该工作在DefaultActionInvocation的构造方法中调用init()方法早早完成。调用过程是:DefaultActionInvocation()->init()->createAction()。

ActionProxy的invoke函数执行过程如下:

1.   public String invoke()throws Exception {

2.       //递归的执行拦截器,当拦截器执行完执行action

3.       if (interceptors.hasNext()) {

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

5.       String interceptorMsg ="interceptor: "+ interceptor.getName();

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

7.       } else {

8.       resultCode = invokeActionOnly();

9.       }

10.          //action执行完后如果存在结果监听器则实行PreResultListener

11.      if (preResultListeners !=null){

12.          for (Object preResultListener :preResultListeners){

13.              PreResultListenerlistener = (PreResultListener) preResultListener;

14.              listener.beforeResult(this,resultCode);

15.          }

16.      }

17.      //最后根据结果生成Result,即,渲染引擎对象并执行渲染和页面返回。

18.      if (proxy.getExecuteResult()) {

19.      executeResult();

20.   

抱歉!评论已关闭.