阅读:20132次   评论:12条   更新时间:2011-06-01    
Struts2提供了一种非常灵活的扩展方式,这种被称之为plugin的扩展方式与Eclipse或者Firefox的plugin具备相同的概念,通过独立于主体之外的程序,来扩展或者增强主体的自身功能。

无疑,plugin的扩展方式是当前最为流行,也最为合理的一种扩展方式。通过plugin,你可以扩展、替换Struts2中的某些功能点,你也可以加入自己的实现类,从而使得Struts2具备新的功能。而plugin的方式也使得任何的功能扩展,都与Struts2的主体程序保持独立性。也使得任何人都可以按照自己的意愿去实现自己的plugin。

plugin的方方面面 Top

依赖关系

Struts2 Reference 写道
Plugins are not loaded in any particular order. Plugins should not have dependencies on each other. A plugin may depend on classes provided by Struts Core, but it should not depend on classes loaded by another plugin.


这段摘自Struts2自身reference的描述已经比较清晰的告诉我们:Struts2的plugin为Struts2的主程序本身提供额外的功能支持。所以plugin本身是依赖于Struts2的主程序,也就是struts-core.jar。当然,针对某个特定功能的plugin可能还会有其他的library的依赖,不过这些依赖绝不应该影响到Struts2主程序本身。但是,不同的plugin之间,互相之间不应该形成依赖。

表现形式

Struts2 Reference 写道
A Struts 2 plugin is a single JAR that contains classes and configuration that extend, replace, or add to existing Struts framework functionality.


很显然,Struts2的plugin以JAR包的形式存在。

安装使用

Struts2 Reference 写道
A plugin can be installed by adding a JAR file to the application's class path, in addition to the JAR files to fulfill whatever dependencies the plugin itself may have.


如果你要获得某个plugin的功能支持,你只需要将plugin的JAR包放到classpath下即可,同时别忘记了plugin自身所依赖的JAR包。

构成要素

Struts2 Reference 写道
To configure the plugin, the JAR should contain a struts-plugin.xml file, which follows the same format as an ordinary struts.xml file.

Since a plugin can contain the struts-plugin.xml file, it has the ability to:

* Define new packages with results, interceptors, and/or actions
* Override framework constants
* Introduce new extension point implementation classes


清楚的不要再清楚了。plugin的内部需要一个名为struts-plugin.xml的文件,这个文件与struts.xml的格式相同。在这个文件中,可以对这个plugin对Struts2的扩展点进行配置,而这些扩展点包含上面提到的三种不同的类型。

运行机制

Struts2 Reference 写道
The framework loads its default configuration first, then any plugin configuration files found in others JARs on the classpath, and finally the "bootstrap" struts.xml.

1. struts-default.xml (bundled in the Core JAR)
2. struts-plugin.xml (as many as can be found in other JARs)
3. struts.xml (provided by your application)

Since the struts.xml file is always loaded last, it can make use of any resources provided by the plugins bundled with the distribution, or any other plugins available to an application.


这段话也摘自Struts2自身的reference,它其实已经深刻的描述了Struts2内部是如何处理plugin的。从这里,我们也可以看到plugin之所以能够以JAR包的形式如此简单的对Struts2自身进行扩展,其核心原因在于Struts2会在系统启动的时候load所有自身以及plugin的配置文件,并且根据这些配置文件来决定Struts2运行期到底具备何种特性。

从这些话中,我们实际上也可以挖掘出来很多东西:

1. 位于struts-core.jar包内部的struts-default.xml永远会被先加载,从而保证Struts2具备许多默认的行为方式。

2. 所有的plugin互相之间是平等的,所以他们互相之间不应该存在依赖关系。同时,Struts2在系统启动时加载plugin的配置文件并没有特定的顺序。

3. Struts2最后会加载位于你自身程序classpath下的名为struts.xml的文件。所以,我见到论坛上有很多朋友问类似这样的问题,都可以迎刃而解了:

1)struts2默认的配置文件是不是只能叫"struts.xml"? ————
2)struts2默认的配置文件是不是只能放在classpath根目录下? ————

不过,struts2提供了完善的配置文件管理机制,所以,你可以在struts.xml中通过extends方式定义任何你需要覆盖其默认行为的配置方式,当然也可以通过import等方式将配置文件分开。

Struts2常见的plugin Top

Struts2 Reference 写道
Many popular but optional features of the framework are distributed as plugins. An application can retain all the plugins provided with the distribution, or just include the ones it uses. Plugins can be used to organize application code or to distribute code to third-parties.


按照Struts2的reference中的指示,其实许多常见的Struts2的扩展功能都是通过plugin来实现的,而这些常见的plugin已经由很多先辈贡献出来,并且作为Struts2的分发包的一部分共同发布,所以,其实你可以在Struts2的发布包中找到这些plugin以及他们的源码进行学习。

当然,你也可以自己实现自己的plugin。有很多的Struts2的plugin就不是hosting在apache上的,但是在apache的plugin的列表中,我们可以找到他们:

http://cwiki.apache.org/S2PLUGINS/home.html

面对这些纷繁复杂的plugin,许多程序员可能会不知所措。所以我在这里对plugin进行了简单的分类,并且列出一些典型的plugin,提供给大家进行学习:

1. 框架整合类

这类的plugin提供了Struts2与其他许多开源框架的整合方式。所以,那些在论坛上提问Struts2与Spring怎么整合、Struts2与DWR怎么整合的朋友,不妨先看看这些plugin的说明,试着跑一下这些plugin的例子,或许你会很有收获。

Spring Plugin: http://cwiki.apache.org/S2PLUGINS/spring-plugin.html

Guice Plugin:http://cwiki.apache.org/S2PLUGINS/guice-plugin.html

JRuby Plugin: http://cwiki.apache.org/S2PLUGINS/jruby-plugin.html

2. 简化配置类

这类的plugin的主旨是为了简化Struts2原有的配置结构,这些简化可能包含使用CoC的方式省略XML配置,使得Struts2支持Restful等等。不过这类的plugin中许多都会涉及到Struts2比较底层的内部实现,所以使用的时候请大家慎重选择。

Codebehind Plugin:http://cwiki.apache.org/S2PLUGINS/codebehind-plugin.html

SmartURLs plugin:http://cwiki.apache.org/S2PLUGINS/smarturls-plugin.html

Convention Plugin:http://cwiki.apache.org/S2PLUGINS/convention-plugin.html

3. 页面装饰类

这类plugin没什么好说的,是为了整合类似Tiles或者Sitemesh的框架,提供一个良好的页面结构化的环境整合。

Sitemesh Plugin:http://cwiki.apache.org/S2PLUGINS/sitemesh-plugin.html

Tiles Plugin:http://cwiki.apache.org/S2PLUGINS/tiles-plugin.html

4. 功能扩展类

这类的plugin最为丰富,包含了各种各样的额外功能扩展,例如整合JFreechart做图表整合输出、整合Open Flash Chart做Flash样式的报表输出、整合JasperReport做PDF输出等等。

JFreeChart Plugin:http://cwiki.apache.org/S2PLUGINS/jfreechart-plugin.html

JasperReports Plugin:http://cwiki.apache.org/S2PLUGINS/jasperreports-plugin.html

Connext Graph Plugin:http://cwiki.apache.org/S2PLUGINS/connext-graph-plugin.html


在之后的章节中,我会挑选其中几个觉有代表性的plugin做详细的分析和说明。

Struts2的扩展点 Top

上面我们看到了通过plugin,可以对Struts2的许多默认行为进行扩展。那么Struts2的哪些行为可以进行扩展呢?在Struts2的内部,又是如何支持这些扩展的呢?

我按照我的理解,将Struts2的可扩展点分成了三类:

1. 自定义Interceptor,Result等,对运行程序进行扩展

自定义的Interceptor和Result非常简单,只需要分别实现XWork的Interceptor接口和Result接口即可。然后,在你的struts.xml中,定义这些实现类,使得他们被Struts2默认加载。对于Interceptor,你可能需要特别留心它在整个Interceptor Stack中的位置。

这类扩展本身并不涉及到Struts2内部自身的运行机制,所改变的只是Action的运行方式和运行结构,所以,这类扩展属于应用级别的扩展

2. 覆盖Struts2的静态变量

Struts2内部定义了很多静态变量,这些静态变量定义了Struts2许多的默认行为。这些静态变量可以以多种不同的方式定义。下面的来自于Struts2 Reference的例子展示了在不同的的文件中定义这些静态变量。

这是在struts.xml中进行定义:
<struts>
  <constant name="struts.devMode" value="true" />
  ... 
</struts>


这是在struts.properties中进行定义:
struts.devMode = true


这是在web.xml中进行定义:
<web-app id="WebApp_9" version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        <init-param>
        	<param-name>struts.devMode</param-name>
        	<param-value>true</param-value>
        </init-param>
    </filter>
    ...
</web-app>


所有的这些定义都会被Struts2接受并作为参数改变Struts2的默认行为。不过,在Struts2启动的时候,会按照一定的顺序按文件进行加载。

Struts2 Reference 写道
Constants can be declared in multiple files. By default, constants are searched for in the following order, allowing for subsequent files to override previous ones:

1. struts-default.xml
2. struts-plugin.xml
3. struts.xml
4. struts.properties
5. web.xml


Struts2的reference告诉我们,Struts2默认按照上面的顺序去加载所有的静态变量的值,并且允许后加载的定义覆盖之前的定义。

由于我们无法修改struts-default.xml和struts-plugin.xml中的定义、而struts.xml通常又被用于放置应用程序相关的一些配置、与此同时,为了保持web.xml的独立性,所以,我们在这里可以总结出一条最佳实践来:把你自定义需要加载的静态变量定义或者需要覆盖struts默认的静态变量的定义尽量放在struts.properties中。这样就可以使得你的配置变得更加清晰。

3. 覆盖Struts2或者XWork自身的接口实现,替换默认行为机制

无论是Struts2还是XWork,都是面向接口编程的框架(请读者在读完这段后,自行理解面向接口的好处)。而这些定义的接口,我们可以编写自己的实现类实现这些接口,从而替换Struts的默认行为机制。

在Struts2的Reference中,也指出了一些Struts2的接口扩展点,请参考下面的链接:http://struts.apache.org/2.0.14/docs/plugins.html

在这里,我想提出的是,上面的链接其实只是列出了Struts2的一些可扩展接口,除此之外,还有XWork的很多接口也具备可扩展性。所以,我们还可以参考XWork的相关配置文件,寻找更多的扩展点,这些就留给读者自行去研究了。

在之后的章节,也会根据具体的实例进行讲解,如何扩展这些接口,从而替换Struts2的默认行为。
评论 共 12 条 请登录后发表评论
12 楼 rplees 2013-06-21 17:19
LZ,我想请教一个问题,我在独立的jar中定义了 struts-plugin.xml ,这个配置文件的 package啊,这类的都正常,当配置<include file="com/hlcto/frame/cfg/struts2/*.xml"  />时 就不会找当前jar中的这个位置的 xml,而是去找当前项目的路径。这种情况该怎么办?

struts版本 2.1.8.1
11 楼 wang1352083 2013-03-12 14:16
想知道struts怎么解析url的.比如我们常规都是按照规范写url请求.但是测试怎么方便测试呢?
10 楼 wang1352083 2013-03-12 12:41
看来我遇到的问题,5年前的高手已经探讨过了.
9 楼 SMCwwh 2011-10-19 15:47
[img][/img]
8 楼 myaimit 2011-04-20 17:30
灰常好,灰常好
7 楼 lixia0417 2010-05-14 03:17
楼主,文章非常不错,可是能不能多写几篇呢,期待您的大作啊!
6 楼 zhxing 2009-04-28 16:11
期待有这的文章。。。这几篇写的很不错。。花了一天的时间看完了。。结合源码的方式来写,写的很清晰。。
5 楼 downpour 2008-12-26 15:26
所以通过阅读源码,其实我们还是可以学到不少东西的。比如,ClassLoaderUtil这个类就教会了我如何查询包括jar包在内的classpath下的某个特定文件名的所有文件。一旦以后有类似的需求就可以拿过来直接用啦。
4 楼 kyo100900 2008-12-26 13:25
  我照着你说的,打了几个断点,在 getConfigurationUrls 方法中发现了这个类: ClassLoaderUtil, 里面有递归在classpath加载resources的方法:getResources 当然也包括在classpath查找指定类的方法:loadClass


最后,我随便弄了个jar包,里面包括了struts-default.xml文件,写了个简单的测试验证一下,看看能否找到:


	public void testXmls() throws IOException {
		Iterator<URL> urls = ClassLoaderUtil.getResources("struts-default.xml",
				ClassLoaderTest.class, false);

		while (urls.hasNext()) {
			URL url = urls.next();
			System.out.println(url.getPath());
			InputStream is = url.openStream();
			url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(is));
			String s;
			while ((s = in.readLine()) != null)
				System.out.println(s);

		}
	}




果然将 struts-default.xml 的路径输出了二次:
第一次在 /WEB-INF/lib/struts2-core-2.0.11.jar!/struts-default.xml 中
第二次在我自己的那个 /WebRoot/WEB-INF/lib/aa.jar!/struts-default.xml中


3 楼 downpour 2008-12-26 11:04
kyo100900 写道

是不是struts2在初始化的时候,会去遍历你 WEB-INF/lib 下的所有jar,找找有没有struts-plugin.xml,有的化就加载,没有话就继续找,直到所有的jar检查完为止?


你说得对!

其实Struts2在初始化的时候会做很多事情。我之后会对struts2初始化的源码进行具体的分析。

现在如果你要搞清楚这个问题,我提示你看以下几个类的方法,你就能明白:

org.apache.struts2.dispatcher.Dispatcher: init()、init_TraditionalXmlConfigurations()、init_PreloadConfiguration()

com.opensymphony.xwork2.config.ConfigurationManager: getConfiguration()

com.opensymphony.xwork2.config.impl.DefaultConfiguration: reload()

com.opensymphony.xwork2.config.providers.XmlConfigurationProvider: init()、loadDocuments()、getConfigurationUrls()

上面我列出来的是初始化的过程,在getConfigurationUrls()这个方法中,你可以看到struts2是如何得到所有满足条件的配置文件。你也可以把这个方法里面的实现单独抽出来跑一下,你就明白它是如何找到所有jar包中的struts-plugin.xml的了。


2 楼 kyo100900 2008-12-26 09:39
我有一个问题:

引用



The framework loads its default configuration first, then any plugin configuration files found in others JARs on the classpath, and finally the "bootstrap" struts.xml.

1. struts-default.xml (bundled in the Core JAR)
2. struts-plugin.xml (as many as can be found in other JARs)
3. struts.xml (provided by your application)

Since the struts.xml file is always loaded last, it can make use of any resources provided by the plugins bundled with the distribution, or any other plugins available to an application.


这段话也摘自Struts2自身的reference,它其实已经深刻的描述了Struts2内部是如何处理plugin的。从这里,我们也可以看到plugin之所以能够以JAR包的形式如此简单的对Struts2自身进行扩展,其核心原因在于Struts2会在系统启动的时候load所有自身以及plugin的配置文件,并且根据这些配置文件来决定Struts2运行期到底具备何种特性。



从这些话中,我们实际上也可以挖掘出来很多东西:

1. 位于struts-core.jar包内部的struts-default.xml永远会被先加载,从而保证Struts2具备许多默认的行为方式。

2. 所有的plugin互相之间是平等的,所以他们互相之间不应该存在依赖关系。同时,Struts2在系统启动时加载plugin的配置文件并没有特定的顺序。

3. Struts2最后会加载位于你自身程序classpath下的名为struts.xml的文件。所以,我见到论坛上有很多朋友问类似这样的问题,都可以迎刃而解了:






我想问的是, 是不是struts2在初始化的时候,会去遍历你 WEB-INF/lib 下的所有jar,找找有没有struts-plugin.xml,有的化就加载,没有话就继续找,直到所有的jar检查完为止?
1 楼 taupo 2008-12-25 21:23
 

发表评论

您还没有登录,请您登录后再发表评论

文章信息

  • downpour在2008-12-25创建
  • downpour在2011-06-01更新
  • 标签: struts2 plugin
Global site tag (gtag.js) - Google Analytics