- 浏览: 253488 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
fjdingsd:
目前基于REST的Java框架不包括Jersey吗
Hello REST!!! -
qq690388648:
不错,说的很好!
Restlet实战(十四)如何在Restlet得到Servlet request和Session -
zhuanbiandejijie:
唉... 你09年就接触Restlet了.15年我才开始看Re ...
Hello REST!!! -
zmjiao:
client.options( 这个是那个包下面的? rest ...
Restlet实战(十八)Restlet如何产生WADL -
shihezichen:
对于最近很多人都在讨论的, 使用REST时就不应该掺杂事务的看 ...
Restlet实战(二十六)事务 (Transaction)
终于到了完结篇,也体会到写书人的痛苦,虽然我仅仅是写了几十篇博客。完结篇结合源代码分析Restlet的运行流程,也算是完美的结束。当然了,也不是说从此不再关注Restlet,后续如果有新的东西出来,比如现在2.0的版本就快release了,新功能,包括API都变动了不少,如果后续有时间的话,会继续写,但是会作为博客随笔,而不是作为实战系列了。
在分析之前,首先一个环境,因为毕竟不同的环境涉及到的源代码也不一样,比如,如果集成了Spring的话,那么客户端发起一个请求必然会涉及到SpringServlet这个类,而如果我们配置Component到restlet.xml里,则代码执行流程就不一样。所以,有必要给出这样的测试环境描述:
首先看一下我的环境里web.xml里面的配置(没有其它配置):
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>restlet</servlet-name> <servlet-class>com.noelios.restlet.ext.spring.SpringServerServlet</servlet-class> <init-param> <param-name>org.restlet.component</param-name> <param-value>component</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>restlet</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping>
为什么偏偏要集成Spring来做运行流程的源代码分析呢?当然了,之前的文章提到,配置ServerServlet来分析也是可以,但是集成Spring会复杂一点,涉及到的源代码的调用会多一点,基于此,对于以后无论使用Spring或者不使用Spring的读者都可以作为参考。
然后是spring配置文件的部分配置:
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-autowire="byName" > <bean id="component" class="org.restlet.ext.spring.SpringComponent"> <property name="defaultTarget" ref="defaultRouter" /> </bean> <bean id="defaultRouter" class="org.restlet.ext.spring.SpringRouter"> <property name="attachments"> <map> <entry key="/users"> <bean class="com.infosys.restlet.application.UserApplication"/> </entry> </map> </property> </bean> </beans>
UserApplication包含的代码:
@Override public synchronized Restlet createRoot() { Router router = new Router(getContext()); getDecoderService().setEnabled(false); Route route = router.attach("/{userId}", UserResource.class); route.extractQuery("query", "test", true); router.attach("/{userId}/orders", UserOrdersResource.class); return router; }
客户端发起的请求代码:
public void test(){ Reference reference = new Reference("http://localhost:8080/restlet/resources/users/1"); Client client = new Client(Protocol.HTTP); Representation representation =new StringRepresentation(getUserXml(), MediaType.TEXT_PLAIN); Response response = client.post(reference, representation); assertTrue(response.getStatus().isSuccess()); }
服务器端资源应答的代码:
@Override public void acceptRepresentation(Representation entity) throws ResourceException { try { String text = null; text = getRequest().getEntity().getText(); System.out.println(text); } catch (IOException e1) { e1.printStackTrace(); } }
当客户端发起请求,服务器接收请求后,会根据请求的URI把这个请求分发给我们配置在Web.xml中的SpringServlet来处理。做过Java Web开发的都知道Servlet的生命周期,首先从访问Servlet的init方法开始,ok,现在就让我们进入SpringServlet的init方法,如果你随后打开Springservlet这个类的源码,你会发现里面没有init,没关系,如果本类没有,会去调用父类的同名方法,而SpringServlet的父类就是ServerServlet,看一下ServerServlet里面的init方法:
@Override public void init() throws ServletException { if ((getComponent() != null)) { if ((getApplication() != null) && (getApplication().isStopped())) { try { getApplication().start(); } catch (Exception e) { log("Error during the starting of the Restlet Application", e); } } } }
代码比较简单,让我们跟随运行的流程深入到每一个方法,看看发生了什么,接下来是getComponet():
public Component getComponent() { Component result = this.component; if (result == null) { synchronized (ServerServlet.class) { if (result == null) { // Find the attribute name to use to store the component final String componentAttributeName = getInitParameter( NAME_COMPONENT_ATTRIBUTE, NAME_COMPONENT_ATTRIBUTE_DEFAULT); // Look up the attribute for a target result = (Component) getServletContext().getAttribute( componentAttributeName); if (result == null) { result = createComponent(); getServletContext().setAttribute( componentAttributeName, result); } } this.component = result; } } return result; }
为了更加清晰的理解这段代码,贴出里面调用的方法的代码:
public String getInitParameter(String name, String defaultValue) { String result = getServletConfig().getInitParameter(name); if (result == null) { result = getServletConfig().getServletContext().getInitParameter( name); } if (result == null) { result = defaultValue; } return result; } private static final String NAME_COMPONENT_ATTRIBUTE = "org.restlet.attribute.component"; private static final String NAME_COMPONENT_ATTRIBUTE_DEFAULT = "com.noelios.restlet.ext.servlet.ServerServlet.component";
结合上面两段代码,能看出,系统首先想获取组件的属性名字,按照我上面给出的配置,显而易见,我没有在web.xml中没有为servlet配置这个属性值,也没有配置一个context值,所以,代码运行到这里,必然会得到一个默认的组件属性名字,也就是上面代码的"com.noelios.restlet.ext.servlet.ServerServlet.component", 得到这个值以后,系统会根据这个值,来获取放到Servlet Context里的Component,当然了,如果是第一次请求的话,这个值肯定是空的,因为只有在创建完Component后,才会放到Servlet Context里。如果没有Component返回的话,则系统会开始创建一个新的Component,然后把创建好的Component放到Servlet Context里,以便下次再次请求的时候不需要重新创建。
下面看一下创建Component的源码,由于SpringServlet重写了父类的这个方法,所以将会读取本类的方法:
@Override public Component createComponent() { Component component = null; final String componentBeanName = getInitParameter( Component_BEAN_PARAM_NAME, null); // Not mentionned in the Spring javadocs, but getBean surely fails if // the argument is null. if (componentBeanName != null) { try { component = (Component) getWebApplicationContext().getBean( componentBeanName); } catch (BeansException be) { // The bean has not been found, let the parent create it. } } if (component == null) { component = super.createComponent(); } return component; }
上面这段代码首先还是得到Component Bean name,注意跟之前的Componet attribute name是不一样的。回到我刚开始给的web.xml中的配置,就会发现,这个属性名字我们在web.xml中已经配置了,对应的值是:component。得到这个值后,系统会到spring中寻找id是component的已经实例化的bean。同样,在上面给出的spring配置文件中,我们定义了一个id是component的Bean。如果一旦没找到,则会调用父类的createComponent方法创建一个新的Bean。按照我们上面的配置,肯定能从Spring配置中获得一个bean,而不会去调用父类的方法去创建一个新的component,但是下面我还是要解释一下父类的的这个方法,因为如果不使用Spring的话,这个方法就会被调用。
由于createComponent代码太长,这里就不全部贴出来,只对一些关键的代码做一个说明:
// Look for the Component XML configuration file. Client client = createWarClient(new Context(), getServletConfig()); Response response = client.get("war:///WEB-INF/restlet.xml"); if (response.getStatus().isSuccess() && response.isEntityAvailable()) { component = new Component(response.getEntity()); }
如果看过之前这个系列的文章,应该能记得有一篇文章专门讲如何在restlet.xml中配置相关component。这里是首先查找一个开发者是否在WEB-INF下放置了restlet.xml这个文件,并且分析文件里面是否已经配置了实体,如Application等。如果都满足情况,则使用配置的内容来构造一个Component。
如果没有发现使用restlet.xml来构造component,则会查找web.xml中是否配置了component的名字,查找的参数名字是org.restlet.component. 如果记得之前系列文章的例子,在web.xml中应该是这样:
<context-param> <param-name>org.restlet.component</param-name> <param-value>com.mycompany.MyComponent</param-value> </context-param>
如果你的web.xml有如上的配置,说明你想使用自己创建的Component,当然,系统就不会为你创建默认的了。接下去就会把自己创建的Component实例化,看如下代码:
if (component == null) { final String componentClassName = getInitParameter(COMPONENT_KEY, null); // Load the component class using the given class name if (componentClassName != null) { try { final Class<?> targetClass = loadClass(componentClassName); // Create a new instance of the component class by // invoking the constructor with the Context parameter. component = (Component) targetClass.newInstance(); ......
ok,我们继续分析,如果没有在web.xml中配置Component,那会怎么样呢?先看代码:
// Create the default Component if (component == null) { component = new Component(); // The status service is disabled by default. component.getStatusService().setEnabled(false); .....
是的,如果componet继续为空,则实例化一个新的Component,这个if判断的后面也会定义支持的客户端协议列表。
至此,我们知道,不管你自己是否配置了Component,这里都会有一个Component了(没有,系统创建一个默认的)。
创建Component方法后面的代码就相对简单了,就是把servlet的一些参数拷贝到Component的上下文中,包含了3种拷贝:
1. 拷贝所有的servlet容器的初始化参数
2. 拷贝所有的servlet应用的初始化参数
3. 拷贝所有的servlet上下文的属性
最后返回创建的Component,得到Component后,我们重新回到getComponent,因为createComponent的调用点在这个方法里。下面代码说明把得到的Component放到Servlet Context的attribute里。
result = createComponent(); getServletContext().setAttribute(componentAttributeName, result);
至此,getComponent方法我们已经分析完成,让我们回到init方法。既然getComponent返回的不是null,那么会调用运行如下代码:
if ((getApplication() != null) && (getApplication().isStopped())) { try { getApplication().start(); } catch (Exception e) {
注意,上面这段代码仍旧是init里面的代码,这里贴出来,只是为了更加清晰的描述代码运行的流程。显而易见,我们接下去要分析getApplication方法,下面就让我们进入这个方法,看看有什么东东在里面?
摘取这个方法部分代码:
if (isDefaultComponent()) { // Find the attribute name to use to store the // application final String applicationAttributeName = getInitParameter( NAME_APPLICATION_ATTRIBUTE, NAME_APPLICATION_ATTRIBUTE_DEFAULT); // Look up the attribute for a target result = (Application) getServletContext() .getAttribute(applicationAttributeName); if (result == null) { result = createApplication(getComponent() .getContext()); getServletContext().setAttribute( applicationAttributeName, result); } this.application = result; }
在这个方法里,首先判断当前的Component是否是default component,何谓default component?反过来理解一下,满足什么条件就不是default component呢?有两种情况,一个是通过restlet.xml配置component,一个是在web.xml配置了自己的component,实际上这两种情况在上面的代码已经分析过。根据上下文,我们知道,由于我们是结合spring,在spring配置文件配置了compoent,所以,显而易见不是default component。判断代码如下:
private boolean isDefaultComponent() { // The Component is provided via an XML configuration file. Client client = createWarClient(new Context(), getServletConfig()); Response response = client.get("war:///WEB-INF/restlet.xml"); if (response.getStatus().isSuccess() && response.isEntityAvailable()) { return false; } // The Component is provided via a context parameter in the "web.xml" // file. final String componentAttributeName = getInitParameter(COMPONENT_KEY, null); if (componentAttributeName != null) { return false; } return true; }
基于我的测试环境,既然不是default component,那么if判断体里面的代码就不会执行。这里还是做一下分析,毕竟将来我们的应用有可能会达到这个分支。那就假设现在是default component。系统会首先application的属性名称,然后根据这个属性名字到servlet context里面找是否已经有值,第一次肯定是空值,但是第一次访问之后会把application的值放到servlet context里,以便下次请求可以直接取值,优化性能。如果这个值为空,就会去创建一个application,然后放到servlet context里。代码见上面。
好了,就不多罗嗦了,按照我们测试的流程继续走,既然不是default component,那么通过getApplication就得不到application了,相应的也不需要调用application的start方法。
至此servlet的init方法分析完成。
发表评论
-
Restlet实战(三十)(完结篇)运行流程之源代码分析(续)
2009-08-24 14:25 4157前面一篇文章分析了servlet里init方法,包括init方 ... -
Restlet实战(二十八)源代码分析之压缩 (Compression)
2009-08-10 15:36 3260上篇文章我给出了如何 ... -
Restlet实战(二十七)压缩 (Compression)
2009-08-05 12:09 7202在进入代码部分之前,还是贴出<<RESTful W ... -
Restlet实战(二十六)事务 (Transaction)
2009-08-02 23:29 5388<<Restful Web Service> ... -
Restlet实战(二十五)缓存 (Cache)
2009-07-31 22:18 3989说明:以下部分文字说明摘自<<Restful We ... -
Restlet实战(二十四)获取参数值(续)
2009-07-31 14:44 10420这个系列之前已经有一篇文章写如何获取参数值,看Restlet实 ... -
欢迎加入Restlet圈子
2009-07-28 22:28 2817如果你进来是因为想看Restlet相关的文章,那么欢迎你加入r ... -
Restlet实战(二十三)实现条件GET (Conditional Get)
2009-07-28 17:47 5046先普及一下什么是条件GET,以下摘自<<Restf ... -
Restlet实战(二十二)仿造PUT和DELETE
2009-07-28 13:17 7186在Restlet实战(七)-提交和处理Web Form 中提到 ... -
Restlet实战(二十一)如何保护确定的资源(续)
2009-07-16 16:18 3999在Restlet实战(十七)如何保护确定的资源 中我给出一个如 ... -
Restlet实战(二十)使用Restlet之SSL
2009-07-15 21:37 3326待写 -
Restlet实战(十九)使用Restlet实现Web Service
2009-07-15 21:34 4350先说明本篇文章要实现的功能,仍然做一些假设,当前系统是基于Re ... -
Restlet实战(十八)Restlet如何产生WADL
2009-07-11 21:57 9835现在究竟REST是否需要WADL这种东西,有很多争论,有人说不 ... -
Restlet实战(十七)如何保护确定的资源
2009-07-11 21:55 3429在面向资源的架构中, ... -
Restlet实战(十六)结合源代码分析及使用Filter
2009-07-11 21:13 5735其实在Web应用中Filter对大家来说一点都不陌生,比如说在 ... -
Restlet实战(十五)如何与表示层交互
2009-07-10 13:51 5371首先还是设定一个应用场景,看看用restlet如何实现。 ... -
Restlet实战(十四)如何在Restlet得到Servlet request和Session
2009-07-09 16:39 11522如果你现在已经有一个web系统,而为了一些需求,你集成了res ... -
Restlet实战(十三)如何在Servlet中呼叫Restlet
2009-07-09 14:47 4524看到这个题目,或许你会问,你之前的很多文章不都是与servle ... -
Restlet实战(十二)获取参数值
2009-07-07 15:06 6949本篇文章将讲解三种不 ... -
Restlet实战(十一)结合源代码修改Restlet-Spring配置文件
2009-07-04 23:56 6168上篇文章结合了Restlet的源码分析了Restlet-spr ...
相关推荐
在《Restlet实战(二十六)事务 (Transaction)》这篇博文中,作者可能会详细讲解如何在Restlet框架中实现上述事务处理策略。Restlet是一个开源的Java框架,专门用于构建RESTful应用程序。它提供了丰富的API和工具,...
了解了这些基本概念后,你可以通过解压"restlet-jee-2.0.14"压缩包,查看源代码、例子和API文档,更深入地学习Restlet 2.0如何在Java EE环境中实现REST服务。这将有助于你开发出高效、灵活且易于维护的Web应用程序。
restlet源代码,描述了restlet框架中每个类的具体实现
通过阅读和运行这些代码,你可以深入理解Restlet的工作原理,并将其应用到自己的项目中。同时,这个项目也是学习RESTful服务设计和实现的一个宝贵资源,能够帮助你提升在Web服务开发领域的技能。
文件列表中的"RESTlet"可能是RESTlet框架的源代码、文档或示例应用。通过学习这些资料,开发者可以深入理解RESTlet的工作原理,掌握如何使用RESTlet构建RESTful服务和客户端应用,从而提升其在Web服务开发领域的专业...
restlet代码
Restlet Client插件是一款运行在chrome内核浏览器上的Web服务测试插件,该插件主要用于测试各种Web服务,能查看网站基本信息、浏览网页代码并能发送HTTP请求来测试网站Web服务,同时支持自动化API场景。用户在安装了...
5. **示例代码**:在`authorizationControl`这个文件夹中,可能包含了实现上述功能的Java源代码示例。例如,一个名为`BasicAuthenticator`的类,它继承了`Authenticator`,并在`authenticate`方法内进行用户验证。...
要确保把以下JAR包写在你的classpath中,才能成功编译并运行接下来的例子: * org.restlet.jar(Restlet API) * com.noelios.restlet.jar (Noelios Restlet Engine核心) * com.noelios.restlet.ext.net.jar ...
RestletClient允许你以文本、源代码或文件形式输入这些数据。 3. **发送请求**:完成配置后,点击“发送”按钮,RestletClient将执行请求,并显示服务器的响应。这包括状态码(如200表示成功,404表示未找到),...
本压缩包包含Restlet框架运行所需的全部jar文件,使得开发者可以便捷地在Java环境中开发、测试和部署RESTful服务。 Restlet框架的核心组件包括以下几个部分: 1. **客户端API**:提供了与REST服务器交互的能力,...
Restlet与Spring集成是将Restlet框架与Spring框架结合,以增强RESTful服务的开发能力。Restlet是一个轻量级的Java框架,专门用于构建REST(Representational State Transfer)架构风格的应用程序。它遵循JAX-RS...
### RESTLET框架学习知识点 #### 一、RESTLET框架概览 - **RESTLET框架简介**:RESTLET是一个面向对象的Java开源框架,用于构建RESTful应用和服务。它旨在简化Web应用开发,允许开发者充分利用REST架构的优势。...
为了使RESTlet能够在Spring环境中运行,我们需要在`web.xml`文件中加入以下代码: ```xml <servlet-name>restlet <servlet-class>org.restlet.ext.spring.RestletFrameworkServlet <param-name>org.restlet....
书中不仅介绍了Restlet框架的基本概念和技术细节,还通过丰富的示例代码展示了如何设计、实现和部署RESTful Web服务。 #### 二、Restlet框架简介 **Restlet** 是一个灵活且强大的Java框架,用于构建RESTful Web...
5. **运行应用**: 将Restlet附加到一个网络服务器(如Jetty或Grizzly),启动应用。 6. **测试**: 使用curl命令或Web浏览器测试Restlet服务,查看其是否按预期工作。 通过学习和实践"FirstRestlet"项目,开发者...
**Restlet Client插件安装包详解** 在现代的Web应用开发中,API(Application Programming Interface)扮演着至关重要的角色,尤其是RESTful API,它已成为构建分布式系统和微服务架构的标准。为了有效地测试和调试...
Restlet是一款开源框架,专为构建RESTful Web服务和客户端应用程序设计。REST(Representational State Transfer)是一种轻量级的架构风格,广泛用于构建互联网应用,因为它提供了高效、分布式的系统设计原则。本文...