使用SpringExt扩展Webx的示例

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”的值修改成你对应的版本。

image

3.1.1. 类图

image

其中,EchoService和EchoServiceImpl分别是回显服务的接口和实现。EchoServiceImpl的静态内部类DefinitionParser为XML配置解析器,用于解析XML配置,生成回显服务的BeanDefinition,并注册到Spring容器中。DefinitionParser的父类是Webx提供的抽象基类,简化配置解析类的开发。

3.1.2. 资源文件

image

资源文件主要有4个,echo-service.xsd是回显服务配置的schema文件,用于定义和校验配置文件格式;services.bean-definition-parsers是解析器对应的配置文件;configuration.xml是项目运行时Bean的配置,Webx服务的配置也在其中;logback.xml则是日志的配置。

3.2. 示例说明

3.2.1. 扩展点

Webx的所有可用扩展点定义在spring.configuration-points文件中。

image

可以直接从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:[email protected]">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:[email protected]">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

你可能感兴趣的:(扩展,示例,webx,Contriubtion,SpringExt)