- 浏览: 220091 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
狂盗一枝梅:
先 收 藏 了再说,struts2太复杂了
Struts2源码阅读(六)_ActionProxy&ActionInvocation -
jingwangfei:
Struts2源码阅读(二)_ActionContext及CleanUP Filter -
liguanqun811:
nbboy 写道"Dispatcher等都是通过Th ...
Struts2源码阅读(三)_Dispatcher&ConfigurationProvider -
nbboy:
"Dispatcher等都是通过ThreadLoca ...
Struts2源码阅读(三)_Dispatcher&ConfigurationProvider -
左脚穿右鞋:
请问我想在tomcat上做应该怎么配置?
JMS应用示例教程
首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起,先看其构造函数:
//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方 public Dispatcher(ServletContext servletContext, Map<String, String> initParams) { this.servletContext = servletContext; //配置在web.xml中的param参数 this.initParams = initParams; }
我们再看在FilterDispatcher创建Dispatcher的:
protected Dispatcher createDispatcher(FilterConfig filterConfig) { Map<String, String> params = new HashMap<String, String>(); 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); }
创建Dispatcher之后,来看init()方法
init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.
主要分七步走,看下面注释
public void init() { if (configurationManager == null) { //设置ConfigurationManager的defaultFrameworkBeanName. //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等 configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } //读取properties信息,默认的default.properties, init_DefaultProperties(); // [1] //读取xml配置文件 init_TraditionalXmlConfigurations(); // [2] //读取用户自定义的struts.properties init_LegacyStrutsProperties(); // [3] //自定义的configProviders init_CustomConfigurationProviders(); // [5] //载入FilterDispatcher传进来的initParams init_FilterInitParameters() ; // [6] //将配置文件中的bean与具体的类映射 init_AliasStandardObjects() ; // [7] //构建一个用于依赖注射的Container对象 //在这里面会循环调用上面七个ConfigurationProvider的register方法 //其中的重点就是DefaultConfiguration的#reload()方法 Container container = init_PreloadConfiguration(); container.inject(this); init_CheckConfigurationReloading(container); init_CheckWebLogicWorkaround(container); if (!dispatcherListeners.isEmpty()) { for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this); } } }
分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.
将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.
最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.
下面将分析这七层功夫是怎样一步步练成的.
首先是init_DefaultProperties()
private void init_DefaultProperties() { configurationManager.addConfigurationProvider(new DefaultPropertiesProvider()); } //直接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了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 new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e); } loadSettings(props, defaultSettings); }
//PropertiesSettings构造方法 //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写 public PropertiesSettings(String name) { URL settingsUrl = ClassLoaderUtils.getResource(name + ".properties", getClass()); if (settingsUrl == null) { LOG.debug(name + ".properties missing"); settings = new LocatableProperties(); return; } settings = new LocatableProperties(new LocationImpl(null, settingsUrl.toString())); // Load settings InputStream in = null; try { in = settingsUrl.openStream(); settings.load(in); } catch (IOException e) { throw new StrutsException("Could not load " + name + ".properties:" + e, e); } finally { if(in != null) { try { in.close(); } catch(IOException io) { LOG.warn("Unable to close input stream", io); } } } } //loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props //这个props是register的一个入参. 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.getImpl(name), settings.getLocationImpl(name)); } }
再来看第二步:init_TraditionalXmlConfigurations()
private void init_TraditionalXmlConfigurations() { //首先读取web.xml中的config初始参数值 //如果没有配置就使用默认的DEFAULT_CONFIGURATION_PATHS:"struts-default.xml,struts-plugin.xml,struts.xml", //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了 //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可 String configPaths = initParams.get("config"); if (configPaths == null) { configPaths = DEFAULT_CONFIGURATION_PATHS; } String[] files = configPaths.split("\\s*[,]\\s*"); for (String file : files) { if (file.endsWith(".xml")) { if ("xwork.xml".equals(file)) { //XmlConfigurationProvider负责解析xwork.xml configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false)); } else { //其它xml都是由StrutsXmlConfigurationProvider来解析 configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext)); } } else { throw new IllegalArgumentException("Invalid configuration file name"); } } }
对于其它配置文件只用StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProvider接口。
类XmlConfigurationProvider负责配置文件的读取和解析,
首先通过init()中的loadDocuments(configFileName);利用DomHelper中的
public static Document parse(InputSource inputSource, Map<String, String> dtdMappings) 将configFileName配置文件通过SAX解析方式按照DtdMappings解析成Document对象.
然后通过Provider的register()方法加载"bean"和"constant"属性,再通过loadPackages()加载package及package中的属性
addAction()方法负责读取<action>标签,并将数据保存在ActionConfig中;
addResultTypes()方法负责将<result-type>标签转化为ResultTypeConfig对象;
loadInterceptors()方法负责将<interceptor>标签转化为InterceptorConfi对象;
loadInterceptorStack()方法负责将<interceptor-ref>标签转化为InterceptorStackConfig对象;
loadInterceptorStacks()方法负责将<interceptor-stack>标签转化成InterceptorStackConfig对象。
而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。
protected PackageConfig addPackage(Element packageElement) throws ConfigurationException { PackageConfig.Builder newPackage = buildPackageContext(packageElement); if (newPackage.isNeedsRefresh()) { return newPackage.build(); } // add result types (and default result) to this package addResultTypes(newPackage, packageElement); // load the interceptors and interceptor stacks for this package loadInterceptors(newPackage, packageElement); // load the default interceptor reference for this package loadDefaultInterceptorRef(newPackage, packageElement); // load the default class ref for this package loadDefaultClassRef(newPackage, packageElement); // load the global result list for this package loadGlobalResults(newPackage, packageElement); // load the global exception handler list for this package loadGobalExceptionMappings(newPackage, packageElement); // get actions NodeList actionList = packageElement.getElementsByTagName("action"); for (int i = 0; i < actionList.getLength(); i++) { Element actionElement = (Element) actionList.item(i); addAction(actionElement, newPackage); } // load the default action reference for this package loadDefaultActionRef(newPackage, packageElement); PackageConfig cfg = newPackage.build(); configuration.addPackageConfig(cfg.getName(), cfg); return cfg; } //loadConfigurationFiles解析读取xml中的内容 private List<Document> loadConfigurationFiles(String fileName, Element includeElement) { ... //通过DomHelper调用SAX进行解析xml doc = DomHelper.parse(in, dtdMappings); ... Element rootElement = doc.getDocumentElement(); NodeList children = rootElement.getChildNodes(); int childSize = children.getLength(); for (int i = 0; i < childSize; i++) { Node childNode = children.item(i); if (childNode instanceof Element) { Element child = (Element) childNode; final String nodeName = child.getNodeName(); if ("include".equals(nodeName)) { String includeFileName = child.getAttribute("file"); //解析每个action配置是,对于include文件可以使用通配符*来进行配置 //如Struts.xml中可配置成<include file="actions_*.xml"/> if (includeFileName.indexOf('*') != -1) { ClassPathFinder wildcardFinder = new ClassPathFinder(); wildcardFinder.setPattern(includeFileName); Vector<String> wildcardMatches = wildcardFinder.findMatches(); for (String match : wildcardMatches) { //递归Load子file中的<include/> docs.addAll(loadConfigurationFiles(match, child)); } } else { docs.addAll(loadConfigurationFiles(includeFileName, child)); } } } } docs.add(doc); loadedFileUrls.add(url.toString()); ... return docs; }
评论
不对吧,Dispatcher对象是在filter init创建的,每个http请求调用dofilter的时候将此dispather对象传到了PrepareOperations对象中,然后assignDispatcherToThread方法又将此对象放置到threadlocal对象的内置map中,多个请求过来调用filter.dofilter时 其实各个请求线程从threadlocal内置的map中取得的对象都是指向在filter.init中创建的一个共享的Dispatcher对象
同意你的观点,但是我不明白既然共享dispatcher,为什么要把dispatcher放入threadlocal
不对吧,Dispatcher对象是在filter init创建的,每个http请求调用dofilter的时候将此dispather对象传到了PrepareOperations对象中,然后assignDispatcherToThread方法又将此对象放置到threadlocal对象的内置map中,多个请求过来调用filter.dofilter时 其实各个请求线程从threadlocal内置的map中取得的对象都是指向在filter.init中创建的一个共享的Dispatcher对象
这个方法并不是读取用户自定义的struts.properties 而是读取StrutsConstants类中的常量。
不知说的是否正确,希望和搂主探讨探讨。
发表评论
-
Struts2源码阅读(六)_ActionProxy&ActionInvocation
2009-10-23 22:04 9923下面开始讲一下主菜ActionProxy了.在这之前最好先去了 ... -
Struts2源码阅读(五)_FilterDispatcher核心控制器
2009-10-22 20:55 4631Dispatcher已经在之前讲过,这就好办了。FilterD ... -
Struts2源码阅读(四)_Dispatcher&ConfigurationProvider续
2009-10-20 16:48 3789接下来第三步:init_LegacyStrutsPropert ... -
Struts2源码阅读(二)_ActionContext及CleanUP Filter
2009-10-16 16:58 54801. ActionContext ActionContex ... -
Struts2源码阅读(一)_Struts2框架流程概述
2009-10-16 15:25 53161. Struts2架构图 请求首先通过Filter ... -
Struts2中文教程电子书下载
2009-10-16 14:57 4678Struts2中文程程电子书下载 -
在Struts 2.0中国际化(i18n)你的应用程序
2009-10-09 09:29 1408国际化是商业系统中不可或缺的一部分,所以无论您学习的是什么We ... -
OGNL中的#,%,$
2009-10-09 09:14 1345OGNL的用法 OGNL是通常要结合Struts 2的标志 ... -
ValueStack 与 OGNL
2009-10-08 12:53 1916ValueStack 与 OGNL 值栈的含义正如它的名字所 ... -
Struts2 Tags API
2009-10-08 10:57 2768本来想写一篇Struts2 标签的,今天突然得到一份Strut ... -
Struts2 references
2009-10-08 10:22 907Struts2 Guide Home:http://strut ... -
struts.xml配置详解
2009-10-08 09:01 1425<?xml version="1.0" ... -
Struts1与Struts2的特点与比较
2009-10-06 10:57 4198一.MVC的特点:— 多个视图可以对应一个模型。按MVC设计模 ... -
struts.properties详解
2009-10-05 20:49 1136项目中常用的配置如下 struts.objectFactor ... -
Struts2+Spring2.5 web.xml配置
2009-10-05 20:44 2235搭建struts2框架只必需五个jar包:commons-lo ... -
Struts2 源码分析
2009-09-22 19:33 0http://blog.csdn.net/hanxs/arch ...
相关推荐
struts.xml文件中新增以下内容: <!-- 为修复struts2 s2-016、s2-017...struts2_s2-016&017_patch.jar拷贝到lib目录下。 ognl-2.6.11.jar直接覆盖掉原有文件。 使用工具进行测试漏洞是否依然存在。 2013年7月25日
<result name="upload" type="dispatcher"> /index.jsp return "upload"; 开始我这里没有返回值,直接return null,以为它是ajax异步请求,不需要返回到某个页面,最后也导致页面显示:HTTP ERROR! 如果还是...
资源来自pypi官网。 资源全名:faraday_agent_dispatcher-2.1.1-py2.py3-none-any.whl
<package name="struts2" extends="struts-default"> <result name="add_success" type="redirect">/common/pub_add_success.jsp <result name="del_success" type="redirect">/common/pub_del_success...
主要介绍了Zend Framework教程之分发器Zend_Controller_Dispatcher用法,结合实例形式详细分析了分发器Zend_Controller_Dispatcher的结构,功能,使用技巧与相关注意事项,需要的朋友可以参考下
event_dispatcher event_dispatcher gem 提供了一个简单的观察者实现,允许您以简单有效的方式订阅和侦听应用程序中的事件。 它受到强烈启发 安装 安装宝石: gem install event_dispatcher 访问宝石: ...
要安装启动所有工作程序的queue_worker_dispatcher脚本,请执行以下rake命令: rake queue_dispatcher: sync 数据库设置 用 rails g queue_dispatcher: migration 这将为模型Task和TaskQueues创建数据库迁移。 ...
Struts2源码分析 请求首先通过Filter chain,Filter 主要包括ActionContextCleanUp,它主要清理当前线 程的ActionContext 和Dispatcher;FilterDispatcher 主要通过AcionMapper 来决定需要调用哪 个Action。
org.apache.struts2.dispatcher.FilterDispatcher
SGDMA包含以下特性: l 根据描述符进行中断使能 l 包传输长度限制 l 视频帧缓冲驻留 l 不对齐存储器访问 l 静态和可编程突发处理 l 数据位宽高达1024-bit l 独立的收发描述符缓冲 l 支持64-bit地址 (必须使用 Qsys ...
at org.apache.struts2.dispatcher.Dispatcher.cleanUpRequest(Dispatcher.java:837) at org.apache.struts2.dispatcher.ng.PrepareOperations.cleanupRequest(PrepareOperations.java:103) at org.apache.struts2....
org.apache.struts2.dispatcher.ServletActionRedirectResult 16 plainText 16 显示源文件内容,如文件源码 16 org.apache.struts2.dispatcher.PlainTextResult 16 freemarker 16 处理FreeMarker模板 16 org.apache....
LteSocketServerChannel:lte_socket_dispatcher原始码
对于分派的任何方法,Dispatcher返回该方法的返回值或三个“ Exception”类之一的实例。 大多数错误将被合并到这些对象中,这样就不会引发运行时异常,而是有序地返回它们。 用法 一个简单的用法示例: import 'pa
本书是广受赞誉的Struts 2优秀教程,它全面而深入地阐述了Struts 2的各个特性,并指导开发人员如何根据遇到的问题对症下药,选择使用最合适的特性。作者处处从实战出发,在丰富的示例中直观地探讨了许多实用的技术,...
ReflectorDispatcher通过使用[package:reflectable]内省一个类实例来实现[Dispatcher]。 package:reflectable允许您通过实例的字符串名称来调用它们的方法。 使用类实例及其在根据Reflectable中的指示进行创建时...
thread_dispatcher:STA调度员
Apache的Struts2框架最近出了一个很严重的漏洞,可以直接执行系统命令 http://www.163.com?%28%27\u0023_memberAccess[\%27allowStaticMethodAccess\%27]%27%29%28meh%29=true&%28aaa%29%28%28%27\u0023context[\%27...