- 浏览: 64725 次
- 性别:
- 来自: 北京
最新评论
-
wucaifang819787:
你好!麻烦问下不知道哪个图片行不行的:http://dl.it ...
struts2源码浅析(四) -
ChenXzh:
高手,佩服得五体投地
关于struts2报There is no Action mapped for namespace / and action name xxx_xxx
接上一篇http://mazhiyuan.iteye.com/blog/1202064,这一篇先讲讲init方法中的7步
首先是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; }
接下来第三步:init_LegacyStrutsProperties()
调用的是调用的是LegacyPropertiesConfigurationProvider
通过比较前面DefaultPropertiesProvider与调用的是LegacyPropertiesConfigurationProvider.发现DefaultPropertiesProvider继承自后者,但重写了register()方法,主要是生成PropertiesSetting的不同,前者是根据org/apache/struts2/default.properties后者是根据struts.properties
展开register()中的Settings.getInstance(),最后是调用getDefaultInstance()
private static Settings getDefaultInstance() { if (defaultImpl == null) { // Create bootstrap implementation //不带参数的DefaultSettings(),区别与DefaultPropertiesProvider中直接带default.properties参数 //不带参数就是默认为struts.propertes,并且加载struts.custom.properties所定义的properties文件 defaultImpl = new DefaultSettings(); // Create default implementation try { //STRUTS_CONFIGURATION为:struts.configuration //在struts.proterties中查找struts.configuration的值,这个值必须是org.apache.struts2.config.Configuration接口的实现类 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 = (Settings) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className), null); } catch (Exception e) { LOG.error("Settings: Could not instantiate the struts.configuration object, substituting the default implementation.", e); } } } catch (IllegalArgumentException ex) { // ignore
第五步是自定义的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 prov = (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; } public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { props.putAll(initParams);//在这里实现滴~ } }); }
第七步:init_AliasStandardObjects,使用BeanSelectionProvider
这是将配置文件中定义的<bean>与实际的类相映射,就是注入bean的依赖关系,这部分以后有时候再研究Container
接下来是看怎样调用这些ConfigurationProviders
展开init_PreloadConfiguration()
private Container init_PreloadConfiguration() { Configuration config = configurationManager.getConfiguration(); Container container = config.getContainer(); boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD)); LocalizedTextUtil.setReloadBundles(reloadi18n); return container; } //再看getConfiguration() public synchronized Configuration getConfiguration() { if (configuration == null) { setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName)); try { //重点就是这个reloadContainer configuration.reloadContainer(getContainerProviders()); } catch (ConfigurationException e) { setConfiguration(null); throw new ConfigurationException("Unable to load configuration.", e); } } else { conditionalReload(); } return configuration; }
展开DefaultConfiguration中的reloadContainer
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { packageContexts.clear(); loadedFileNames.clear(); List<PackageProvider> packageProviders = new ArrayList<PackageProvider>(); //Struts2(xwork2)用Container来完成依赖注入的功能 //首先初始化一个ContainerBuilder,再由builder来保存接口与实现类或工厂类的对应关系 //然后通过builder.create(boolean)方法产生container //由container.getInstance(Class);就可以得到接口的实现实例了 //这一部分比较复杂,后面研究完成了,会单独拿出来讲,这里先弄清楚Xwork依赖注入的实现步骤就可以了 ContainerProperties props = new ContainerProperties(); ContainerBuilder builder = new ContainerBuilder(); for (final ContainerProvider containerProvider : providers) { //循环调用ConfigurationProvider的init和register方法,明白了吧,在这里统一循环调用 containerProvider.init(this); containerProvider.register(builder, props); } props.setConstants(builder); //注入依赖关系,在这里并不产生实例 builder.factory(Configuration.class, new Factory<Configuration>() { 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已经注入依赖关系的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); //调用PackageProvider的loadPackages()方法,这里主要是针对XmlConfigurationProvider和StrutsXmlConfigurationProvider ((PackageProvider)containerProvider).loadPackages(); packageProviders.add((PackageProvider)containerProvider); } } // Then process any package providers from the plugins Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class); if (packageProviderNames != null) { for (String name : packageProviderNames) { PackageProvider provider = container.getInstance(PackageProvider.class, name); provider.init(this); provider.loadPackages(); packageProviders.add(provider); } } rebuildRuntimeConfiguration(); } finally { if (oldContext == null) { ActionContext.setContext(null); } } return packageProviders; }
init7步执行完之后,struts2做好了接受request的准备了,下一篇会着重讲讲filter在struts中的使用。
下一篇:http://mazhiyuan.iteye.com/blog/1202104
发表评论
-
JAVA多线程-厕所问题
2012-11-22 11:55 2010在http://my.oschina.net/xpbug/bl ... -
第八章 最大自序列和
2012-11-01 20:29 927第八章的问题是常见的---最大自序列和 的问题 书中提 ... -
第二章 旋转字符串的思考
2012-10-26 16:09 902编程珠玑第二章旋转字符串,abcdefg向左旋转3位,变为de ... -
Mongdb的upsert出现E11000 duplicate key errors的错误分析
2012-10-25 17:36 9241昨日上线的系统,今天查日志时发现有不少E11000 dupli ... -
开源的Mongodb java client -- mango发布
2012-07-20 21:53 1889Mango ---- 一个非常简单的操作mongodb的 ... -
SOAP消息
2012-03-05 20:37 1290本文转自:http://blog.csdn.net/chang ... -
wsdl文档结构
2012-03-05 20:32 1560本文转自:http://blog.csdn.net/chang ... -
浅出Apache Cxf
2012-03-05 20:14 0由于业务需要,开放了系统的 Web Se ... -
struts2源码浅析(四)
2011-10-19 17:15 1613接上一篇讲了filter后,现在request到了action ... -
struts2源码浅析(三)
2011-10-19 16:50 1624接上篇http://mazhiyuan.iteye.com/b ... -
struts2源码浅析(一)
2011-10-19 16:18 17921. Struts2架构图 请求首先通过Filter ... -
struts2.1权威指南-笔记
2010-12-19 22:36 11371.struts 1.x 和 struts 2.x的 ... -
Hibernate学习总结4---对象状态
2010-12-10 16:14 1003session 的几个主要方法: 1,save方法和persi ... -
Hibernate学习总结3 --配置文件
2010-12-10 16:10 1021如果不希望使用默认的hibernate.cfg.xml 文件作 ... -
Hibernate 学习总结一
2010-12-10 14:54 905引入: 模型不匹配(阻 ... -
HF servlet&jsp 前6章要点总结
2010-11-21 11:58 953今天有时间把前6章主要讲servlet的内容坐下总结。好了,开 ... -
jquery源码分析之属性篇
2010-11-20 20:09 1967jquery提供了一些快捷函 ... -
HF servelt&jsp 定制标记开发 要点总结
2010-11-13 11:41 13431.标记文件使用一个页 ... -
bean相关标准动作总结+复习
2010-11-07 23:22 8041.<jsp:useBean>动作会定义一个变量, ... -
HF servlet&jsp ---include 指令和动作元素
2010-11-07 23:02 8471.include的2种方式 include多用于网站中可重用 ...
相关推荐
Struts2 源码分析 Struts2 是一个基于MVC 模式的Web 应用程序框架,它的源码分析可以帮助我们更好地理解框架的内部机制和工作流程。下面是Struts2 源码分析的相关知识点: 1. Struts2 架构图 Struts2 的架构图...
这篇博文“Struts2源码解读”深入剖析了Struts2的核心机制,帮助开发者更好地理解和利用这个框架。源码分析是提升编程技能和解决问题的关键,特别是对于复杂的框架如Struts2,理解其内部工作原理能够帮助我们优化...
通过阅读Struts2的源码,我们可以深入了解框架如何处理请求、如何调度Action以及如何应用拦截器来扩展功能。这有助于开发者更好地定制和优化他们的应用程序,提高代码质量和性能。在实际开发中,对源码的理解能帮助...
最新版的Struts2源码可以从GitHub的Apache官方仓库获取,这为我们提供了深入理解其内部工作原理和定制功能提供了可能。 Struts2的核心特性包括: 1. **Action与结果**:在Struts2中,业务逻辑处理主要由Action类...
struts2源码详细解析51CTO下载-struts2源代码分析(个人觉得非常经典)
在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了显著的变化,这使得它成为一个独立且成熟的框架。 首先,Struts2的架构基于WebWork的核心,这意味着...
将Struts 2源码导入Eclipse工程,对于学习和理解框架的工作原理以及进行自定义开发具有重要意义。 首先,导入Struts 2源码到Eclipse需要遵循以下步骤: 1. 下载Struts 2的源码包,通常可以从Apache官方网站获取...
STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析STRUTS2源码解析...
Struts2是一个流行的Java Web框架,它简化了MVC(模型-视图-控制器)架构的实现。本文将深入探讨Struts2的...通过深入研究Struts2的源码,我们可以发现其内部工作原理,这对于解决复杂问题和开发自定义插件非常有帮助。
压缩包中的"org"目录可能包含了Struts2框架的源码文件,按照包结构组织。这通常包括核心组件、拦截器、结果类型、动作支持、配置处理等模块的源代码。开发者可以深入研究这些源码,了解其工作原理,进行自定义扩展...
深入理解Struts2的源码对于提升Java Web开发技能,尤其是在面试中讨论底层实现时,具有非常重要的价值。 首先,我们来看看Struts2的核心组件和设计理念: 1. **Action**:在Struts2中,Action类是业务逻辑处理的...
本项目源码提供了一个基础的Struts2应用程序实例,对于初学者来说,这是一个很好的学习资源,可以深入理解Struts2的工作原理和架构。 Struts2的核心组件包括: 1. **Action类**:Action类是业务逻辑的载体,它是...
在深入研究Struts2源码时,我们可以关注以下几个关键部分: 1. **org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter**:这是Struts2的核心过滤器,它初始化并调用Struts2的生命周期。 2. **...
在"struts2源码解析.pdf"文档中,主要探讨了以下几个关键组件及其功能: 1. **ActionContext**: - `ActionContext`是Struts2的核心上下文,它存储了与当前Action执行相关的所有信息,如请求参数、session数据等。...
在深入理解Struts 2的源码之前,我们需要先了解其核心概念和组件。 1. **Action类与ActionMapping** Struts 2的核心是Action类,它是业务逻辑处理的中心。每个Action类对应一个用户请求,处理后返回一个Result。...
在“浪曦struts2源码第二课”中,我们将会深入探讨Struts2的核心概念、工作原理以及源码分析。 首先,让我们了解Struts2的基本架构。Struts2的核心组件包括Action、Result、Interceptor(拦截器)等。Action是业务...
深入研究Struts2源码有助于提升对Java Web开发的理解,尤其是对于MVC框架的设计思想、AOP(面向切面编程)的应用以及依赖注入等方面有深刻认识。同时,源码学习也能帮助你更好地定位和解决问题,提高开发效率。
深入学习Struts2的源码,有助于理解其运行机制,从而更好地优化代码、调试问题,甚至开发自己的扩展。对于Java Web开发者来说,掌握Struts2的基本原理和使用技巧,能够显著提高开发效率和应用质量。
此压缩包文件包含的是Struts2的源码,特别适合初学者研究和学习,其中涵盖了拦截器和验证等关键组件的实现。 首先,我们来深入了解Struts2的核心概念: 1. **Action类**:在Struts2中,业务逻辑通常由Action类执行...