Rop开发手册(1):最简单的服务开放平台框架
Rop概述
Rop是Rapid Open Platform的简称,它不同于一般纯技术型的Web Service框架(如CXF,Jersey等),Rop致力于构建开放服务平台的框架,您可以使用Rop开发类似于淘宝开放服务平台这样的服务平台。Rop充分借鉴了当前大型网站的开放服务平台的设计思路,汲取了它们成功的实践经验,对开放服务平台的很多应用层领域问题给出了解决方案,开发者可以直接使用这些解决方案,也可以在此基础上进行个性化扩展。
Rop功能架构
CXF和Jersey是纯技术纯的Web Service框架,而在Rop中,Web Service只是核心,它提供了开发服务平台的诸多领域问题的解决方案:如应用认证、会话管理、安全控制、错误模型、版本管理、超时限制等。
下面通过图1了解一下Rop框架的整体结构:
图1
从图1中,可以看到Rop所提供的大部分功能都是偏“应用层”的,传统技术型的Web Service框架是不会僭越到这些“应用层”的问题的。但是,在实际开发中,这些应用层的问题不但不可避免,而且非常考验开发者的设计经验,此外,这些工作还会占用较大的开发工作量。Rop力图让开发者从这些复杂的工作中解脱出来,让他们可以真正聚焦服务平台业务逻辑的实现上。
Rop技术架构
Rop在技术实现上充分借鉴了Spring MVC的框架设计理念和实现技术,首先RopServlet类似于Spring MVC的DispatcherServlet,是Rop的门面Servlet,负责截获HTTP服务请求转由Rop框架处理。具体技术架构通过图2描述:
图2
Rop的配置信息统一在Spring配置文件中通过rop Schema命名空间定义。ServiceRouter是Rop框架的核心,它负责协调各组件的交互并最终完成服务处理的工作。RopServlet在启动时会从Spring容器中搜索出ServiceRouter的Bean实例并注册之。
在服务请求到达后,RopServlet截获请求并转交给ServiceRouter处理,ServiceRouter将服务请求封装成一个的RopRequestContext对象,RopRequestContext包含了服务请求的所有信息。而后,ServiceRouter使用SecurityManager检查服务请求的安全性,只有通过了SecurityManager的安全检查,才会调用目标服务处理方法执行服务,否则将阻止请求并返回错误响应信息。
完成SecurityManager的安全检查后,ServiceRouter通过ServiceMethodAdapter对目标的服务方法发起调用。由于具体服务方法的签名各不相同,因此必须采用反射机制进行适配调用。当返回响应对象后,ServiceRouter使用RopMarshaller将响应对象编组为特定的响应报文返回给客户端。
您会发现Rop的顶级框架接口类在Spring MVC中都能找到对应的对象:RopServlet对应DispatcherServlet,ServiceMethodAdapter对应HandlerAdapter,RopMarshaller对应ViewResolver,而ServiceRouter承担了HandlerMapping和部分DispatcherServlet的角色。因此,如果您在学习Spring MVC的框架后,理解Rop框架的实现原理将变得非常轻松。
使用Rop开发一个服务
将Rop项目克隆到本地
由于Rop托管在github (www.github.com)中,为了获取最新的Rop项目,必须在您的系统中安装Git客户端软件,我们推荐使用msysgit,它能够让我们在Windows系统中像Linux一样使用Git。
从http://code.google.com/p/msysgit/下载并安装git客户端msysgit,然而在开始菜单中找到并打开Git Bash,在命令窗口运行如下命令:
使用以下的Maven命令构建rop和rop-sample项目,打开DOS窗口,移到rop及rop-sample项目的pom.xml所在的目录,执行构建命令:
<dependency> <groupId>com.bookegou</groupId> <artifactId>rop</artifactId> <version>1.0</version> </dependency>
Rop的发布包已经发布到Maven的核心仓库中(org.sonatype.oss),因此你可以直接使用在pom.xml引用即可。
开发一个服务方法
rop-sample项目中有一个com.rop.sample.UserService的服务类,我们就通过这个服务类了解开发基于Rop的Web Service服务的过程。
UserService.java
package com.rop.sample;import com.rop.RopRequest;import com.rop.annotation.NeedInSessionType;import com.rop.annotation.ServiceMethod;import com.rop.annotation.ServiceMethodBean;import com.rop.sample.response.LogonResponse;import com.rop.session.SimpleSession;//①标注Rop的注解,使UserService成为一个Rop的服务Bean@ServiceMethodBean public class UserService { //②使该服务方法成为一个Web Service的方法。@ServiceMethod(method = "user.getSession", version = "1.0", needInSession = NeedInSessionType.NO)public Object getSession(LogonRequest request) {//创建一个会话SimpleSession session = new SimpleSession();session.setAttribute("userName",request.getUserName());request.getRequestContext().addSession("mockSessionId1", session);//返回响应LogonResponse logonResponse = new LogonResponse();logonResponse.setSessionId("mockSessionId1");return logonResponse;}
package com.rop.sample.request;import com.rop.AbstractRopRequest;import com.rop.annotation.IgnoreSign;import javax.validation.constraints.Pattern;public class LogonRequest extends AbstractRopRequest{ @Pattern(regexp = "\\w{4,30}") private String userName; @IgnoreSign @Pattern(regexp = "\\w{6,30}") private String password; //get/setter}
package com.rop.sample.response;import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlRootElement;@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(name = "logonResponse")public class LogonResponse{ @XmlAttribute private String sessionId; …}
<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:rop="http://www.bookegou.com/schema/rop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.bookegou.com/schema/rop ①引入Rop Schema定义文件 http://www.bookegou.com/schema/rop/rop-1.0.xsd"> <!--② 扫描Spring Bean--> <context:component-scan base-package="com.rop.sample"/> <!--③启动Rop框架 --> <rop:annotation-driven/></beans>
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:sampleRopApplicationContext.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!--①定义一个RopServlet,并指定其映射的URL--> <servlet> <servlet-name>rop</servlet-name> <servlet-class> com.rop.RopServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rop</servlet-name> <url-pattern>/router</url-pattern> </servlet-mapping></web-app>