1. Webx和SpringExt分别是什么
Webx是一套基于Java Servlet API的通用Web框架。它在Alibaba集团内部被广泛使用。从2010年底,向社会开放源码。SpringExt则是Spring的一个扩展,在Spring的基础上提供了一种扩展功能的新方法,是Webx的基础。关于Webx和SpringExt的完整介绍,可以参考Webx的官方文档Webx和SpringExt
2. SpringExt中的基本概念
SpringExt中的两个核心概念是扩展点和捐献,其中扩展点(Configuration Point)代表一个可被扩展的接口,捐献(Contriubtion)则是对扩展点的具体扩展。一个扩展(个人倾向使用“扩展”,“捐献”听起来很别扭)一般对应着3个东西,分别是实现类、用于校验配置的Schema以及配置解析器,其中后两者是可选的,不过一般都会用到。关于SpringExt的原理和概念,官方文档已经有了很详细的说明,前面这些介绍性的文字很多都是从上面Copy的,大家可以直接查看SpringExt。
3. 一个简单的回显服务扩展
一个简单得不能再简单的服务,用于把传入的消息返回,没有什么特别的。如果你输入“XXXX”它将返回"[Echo]: XXXX",其中"["为preTitle,"Echo"为title,"]"为postTitle,":"为separator,它们都是可以在配置中自定义的。
3.1. 示例代码的获取以及使用
代码在Google Code上,对应SVN路径为http://joshuazhan.googlecode.com/svn/trunk/webx/springext/contribution.echo。Check Out后请使用Maven创建eclipse工程,类me.joshua.webx.springext.contribution.echo.Launcher包含Main函数,用于运行示例。关于具体SVN、Maven的使用请直接Google,需要注意的是我编写示例时用的是JDK1.7,如果你机器上的JDK不是1.7的,请在POM配置文件中把“java.version”的值修改成你对应的版本。
3.1.1. 类图
其中,EchoService和EchoServiceImpl分别是回显服务的接口和实现。EchoServiceImpl的静态内部类DefinitionParser为XML配置解析器,用于解析XML配置,生成回显服务的BeanDefinition,并注册到Spring容器中。DefinitionParser的父类是Webx提供的抽象基类,简化配置解析类的开发。
3.1.2. 资源文件
资源文件主要有4个,echo-service.xsd是回显服务配置的schema文件,用于定义和校验配置文件格式;services.bean-definition-parsers是解析器对应的配置文件;configuration.xml是项目运行时Bean的配置,Webx服务的配置也在其中;logback.xml则是日志的配置。
3.2. 示例说明
3.2.1. 扩展点
Webx的所有可用扩展点定义在spring.configuration-points文件中。
可以直接从Webx的Jar包中查看,包相对路径为“/META-INF/spring.configuration-points”。
Webx中的所有组件都是从services这个顶级扩展点派生出来的,它的定义如下
services=http://www.alibaba.com/schema/services; defaultElement=service
其中“services”是扩展点的名称,“http://www.alibaba.com/schema/services”为对应的namespace,“defaultElement”则指定了默认元素的名字,在这里是service。
3.2.2. 配置校验
Webx在解析配置前,首先会根据扩展点名称定位到扩展元素对应Schema的文件夹,再根据元素名寻找Schema进行格式校验,回显服务的Schema配置如下。
<?xml version="1.0" encoding="UTF-8"?>
<!--
定义echo-service元素的格式
包括一个title子元素和preTitle, postTitle,separator三个属性,属性都是可选的,且提供了默认值
-->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xsd:element name="echo-service" type="EchoServiceType" />
<xsd:complexType name="EchoServiceType">
<xsd:all>
<xsd:element name="title" type="xsd:string" default="Echo" />
</xsd:all>
<xsd:attribute name="preTitle" type="xsd:string" default="[" />
<xsd:attribute name="postTitle" type="xsd:string" default="]" />
<xsd:attribute name="separator" type="xsd:string" default=":" />
</xsd:complexType>
</xsd:schema>
Schema中定义了echo-service元素有一个title子元素以及三个可选属性,子元素和属性在解析时都会被设置到EchoService对象的属性中。
3.2.3. 配置解析
一个扩展点下定义了不同的元素,每个元素都对应一个解析器。services的元素解析器定义在services.bean-definition-parsers中,在Webx Jar包中的相对路径为“/META-INF/services.bean-definition-parsers”,其内容如下所示,里面指定了每个services Namespace下的元素的配置解析器类。
services=http://www.alibaba.com/schema/services; defaultElement=service
services/data-resolver/factories=http://www.alibaba.com/schema/services/data-resolver/factories; defaultElement=factory; nsPrefix=dr-factories
services/form/validators=http://www.alibaba.com/schema/services/form/validators; defaultElement=validator; nsPrefix=fm-validators
services/form/conditions=http://www.alibaba.com/schema/services/form/conditions; defaultElement=condition; nsPrefix=fm-conditions
……
因为示例的回显服务是services的扩展,所以需要在自己Jar包中对应的services.bean-definition-parsers文件(见3.1.2)中添加自定义标签的解析器配置。
# services命名空间下echo-service元素的解析器
echo-service=me.joshua.webx.springext.contribution.echo.EchoServiceImpl$DefinitionParser
解析器的代码如下
/**
* 用于解析Echo Service的XML配置,生成对应的Bean Definition
*/
public static class DefinitionParser extends
AbstractNamedBeanDefinitionParser<EchoServiceImpl> {
@Override
protected void doParse(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder) {
// 调用工具类SpringExtUtil中的方法,分别把子元素和属性值设置到EchoService中
subElementsToProperties(element, builder, sameNs(element));
attributesToProperties(element, builder, "preTitle", "postTitle",
"separator");
}
@Override
protected String getDefaultName() {
return EchoService.DEFAULT_NAME;
}
}
DefinitionParser本身只借助工具类SpringExtUtil完成XML元素的子元素和属性到类属性的设置,其余BeanDefinition的生成和注册都由抽象父类AbstractNamedBeanDefinitionParser完成。
3.2.4. 回显服务的实现以及运行测试
A. 回显服务
package me.joshua.webx.springext.contribution.echo;
……
/**
* EchoServiceImpl回显的内容示例如下:<br>
* <code>"[Echo]: XXXX"</code><br>
* 其中"["为preTitle,"Echo"为title,"]"为postTitle,":"为separator,"XXXX"则是消息内容
*
* @author <a href="mailto:daonan.zhan@gmail.com">Joshua Zhan</a> 2012-10-5
*/
public class EchoServiceImpl implements EchoService {
private String title;
private String preTitle;
private String postTitle;
private String separator;
@Override
public String echo(String message) {
StringBuilder sb = new StringBuilder();
sb.append(preTitle).append(title).append(postTitle).append(separator)
.append(' ').append(message);
return sb.toString();
}
……
}
B. 测试类
package me.joshua.webx.springext.contribution.echo;
……
/**
* 运行示例的类
*
* @author <a href="mailto:daonan.zhan@gmail.com">Joshua Zhan</a> 2012-10-5
*/
public class Launcher {
private final static String LINE_SEPARATOR = "============================";
private final static String GREETING_MESSAGE = "Hello World!";
public static void main(String[] args) {
ApplicationContext context = new XmlApplicationContext(
new ClassPathResource("configuration.xml"));
testEchoService(context);
}
public static void testEchoService(ApplicationContext context) {
EchoService echoService = (EchoService) context.getBean("echoService");
System.out.println();
System.out.println(LINE_SEPARATOR);
System.out.println(echoService.echo(GREETING_MESSAGE));
System.out.println(LINE_SEPARATOR);
}
}
Webx的使用和Spring基本一致,不同之处在于XmlApplicationContext是Webx扩展自Spring的实现。
C. 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.alibaba.com/schema/services http://localhost:8080/schema/services.xsd
http://www.springframework.org/schema/beans http://localhost:8080/schema/www.springframework.org/schema/beans/spring-beans.xsd"
>
<echo-service xmlns="http://www.alibaba.com/schema/services" >
<title>Echo</title>
</echo-service>
</beans>
Webx本身兼容Spring,它的配置也是写在Bean配置中,不同的地方在于使用了自己的标签,这点和Spring自身的扩展机制有些类似。在这个例子中,你可以自己尝试着给echo-service添加preTitle、postTitle的属性或是改变子元素title的值,看看输出效果的不同。
3.2.5. 运行结果
2012-10-06 18:22:26.079 : INFO [com.alibaba.citrus.springext.support.context.XmlApplicationContext] [main] Refreshing com.alibaba.citrus.springext.support.context.XmlApplicationContext@17df9ec: startup date [Sat Oct 06 18:22:26 CST 2012]; root of context hierarchy
2012-10-06 18:22:28.233 : INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] [main] Loading XML bean definitions from class path resource [configuration.xml]
2012-10-06 18:22:29.123 : INFO [com.alibaba.citrus.springext.support.context.InheritableListableBeanFactory] [main] Pre-instantiating singletons in com.alibaba.citrus.springext.support.context.InheritableListableBeanFactory@110609a: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,echoService,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
============================
[Echo]: Hello World!
============================
4. 其他
4.1. 小记
絮絮叨叨写了这些文字,目的是想锻炼一下自己写技术Blog的能力,同时也给大家介绍一下Webx这个框架。今后如果有时间,会陆续写一些文章来介绍Webx的其他方面。经验尚浅,难免会有些疏漏,欢迎大家指正及讨论。
4.2. Webx论坛
Webx官网上有一个小论坛http://openwebx.org/forum/,Webx的作者常年在上面解答问题,如果有对Webx的指教、问题或是建议都可以直接在上面提出来。
4.3. 参考
Webx文档http://openwebx.org/docs/index.html
4.4. 相关文章
在Webx中添加扩展点的示例http://my.oschina.net/joshuazhan/blog/84206