struts2 部分源码分析
来源:互联网 发布:亚马逊对网络的要求 编辑:程序博客网 时间:2024/05/05 18:22
Struts2是个非常优秀的开源框架,最近抽空看了一下源码,然后从互联网看了一下大家的总结,发现随着版本的更新,人的思想也需要及时更新啊。 关于其主要的工作原理,我也不想在阐述更多的了,如果你比较熟悉servlet,理解起来会更加容易,可以参考看一下CSDN的这篇文章: 参考文章
大概的工作原理从图片中描述得很清楚了。 在总结的过程发现Struts的版本更新也很快,web.xml文件中配置的过滤在2.1.2版本之前都是配置FilterDispatcher,但是在之后版本配置的是一个全新的过滤器:StrutsPrepareAndExecuteFilter,从字面上看貌似后者必前者功能更加强大。FilterDispatcher是struts2.0.x到2.1.2版本的核心过滤器。StrutsPrepareAndExecuteFilter是自2.1.3开始就替代了FilterDispatcher的。这样的改革当然是有好处的。我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了。
在web.xml中是这样配置的:
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在该过滤器中有一个初始化的方法 init(FilterConfig filterConfig);看看其作用
public void init(FilterConfig filterConfig) throws ServletException { //这只是一个普通类,封装下面的初始化函数,可以当做工具类一样 InitOperations init = new InitOperations(); try { //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在Iterator中,在后面的初始化dispatcher中使用 FilterHostConfig config = new FilterHostConfig(filterConfig); //初始化strut的内部日志 init.initLogging(config); //初始化dispatcher Dispatcher dispatcher = init.initDispatcher(config); //加载静态内容加载器 init.initStaticContentLoader(config, dispatcher); //初始化上面定义的prepare ,execute ,会在下面doFilter中使用到,看起参数,放置了两个重要的东西 prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher); execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher); this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); //这是一个回调方法 postInit(dispatcher, filterConfig); } finally { init.cleanup(); } }
创建dispatcher对象,并初始化
public Dispatcher initDispatcher( HostConfig filterConfig ) { //相当于初始两个参数ServletContext servletContext和Map<String, String> initParams Dispatcher dispatcher = createDispatcher(filterConfig); //包括初始换文件管理器,default.properties文件提供者,struts-default.xml,struts- //plugin.xml,struts.xml等文件,用户自己实现的ConfigurationProviders类,Filter的初始化参数等 dispatcher.init(); return dispatcher; } //将filterConfig 对象中参数去除并封装,然后new对象 private Dispatcher createDispatcher( HostConfig filterConfig ) { Map<String, String> params = new HashMap<String, String>(); for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) { String name = (String) e.next(); String value = filterConfig.getInitParameter(name); params.put(name, value); } return new Dispatcher(filterConfig.getServletContext(), params); }
总体上来说,这个init初始化还是做了很多事情的,大致会根据配置来初始换参数,初始化适配器,初始化加载各种文件等。
下面doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面也做了很多工作,具体如下:
//设置编码和国际化,底层执行 dispatcher.prepare(request, response);方法很简单只是设置了//encoding 、locale ,做的只是一些辅助的工作 prepare.setEncodingAndLocale(request, response); //创建Action上下文(重点) prepare.createActionContext(request, response);
创建ActionContext,ActionContext本来是一个容器,主要存储request、session、application、parameters等相关信息,并且它是一个线程的本地变量,不会造成线程之间的变量分享问题,这意味着不同的action之间不会共享一个ActionContext,当然不会存在线程安全的问题,
//创建Action上下文,初始化thread local public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) { ActionContext ctx; Integer counter = 1; Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER); if (oldCounter != null) { counter = oldCounter + 1; } ActionContext oldContext = ActionContext.getContext(); if (oldContext != null) { // detected existing context, so we are probably in a forward ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap())); } else { ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext)); ctx = new ActionContext(stack.getContext()); } request.setAttribute(CLEANUP_RECURSION_COUNTER, counter); //ActionContext保存到ThreadLocal ActionContext.setContext(ctx); return ctx; }
dispatcher是怎么createContextMap的呢?
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping, ServletContext context) { // request map wrapping the http request objects Map requestMap = new RequestMap(request); // parameters map wrapping the http parameters. ActionMapping parameters are now handled and applied separately Map params = new HashMap(request.getParameterMap()); // session map wrapping the http session Map session = new SessionMap(request); // application map wrapping the ServletContext Map application = new ApplicationMap(context); Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context); if (mapping != null) { extraContext.put(ServletActionContext.ACTION_MAPPING, mapping); } return extraContext; }
可以看到这里获取得到request和context中获取相关参数,封装为map,其中
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
再次将各个参数map再封装到另外Map中,得到extraContext变量。这里的ActionMapping mapping为空,不会做任何处理。
在prepare将适配器分给线程之后,开始查找本次请求的ActionMapping
ActionMapping mapping = prepare.findActionMapping(request, response, true);
这里暂时不详细讨论是怎么根据request相关参数来形成ActionMapping 的,但是我们应该有感觉,上面已经加载了struts的相关xml配置文件,这部分另外介绍。在找到ActionMapping 之后就是执行action了,execute.executeAction(request, response, mapping);这部分详细见后面一章吧。
- struts2 部分源码分析
- spring部分源码分析
- freediameter部分源码分析
- Listview部分源码分析
- Listview部分源码分析
- nova部分源码分析
- Ranklib部分源码分析
- Struts2之struts2源码分析
- struts2源码分析 serviceAction
- Struts2源码分析
- struts2源码分析
- Struts2源码分析
- Struts2源码分析一
- Struts2源码分析二
- struts2 源码分析
- struts2源码分析笔记
- Struts2源码分析
- struts2源码分析
- 1. Oracle概念笔记一序言
- 旭说数据结构之用两个栈实现队列
- 剑指Offer-18-树的子结构
- Spring中ServletContextAware接口使用理解
- iOS开发小技巧:刷新UITableView
- struts2 部分源码分析
- 利用java反射动态调整数组长度
- HibernateTransactionManager和DataSourceTransactionManager
- Java工作利器之常用工具类(三)——字符串工具类-智能截取
- Java Web性能优化之一:减少DAO层的调用次数
- 进击的KFC:UI(三)自定义视图、视图控制器
- Android M 新的运行时权限开发者需要知道的一切
- 开源混淆工具ProGuard配置详解及配置实例
- 微信分享回调