Webx学习笔记(三)Webx Framework

Webx Framework的任务

系统初始化 响应请求
初始化Spring容器 增强request/response/session的功能
初始化日志系统 提供pipeline流程处理机制
  异常处理
  开发模式

1 Webx的初始化

//初始化Spring容器 - /WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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
    ">
    ...
    <listener>
        <listener-class>com.alibaba.citrus.webx.context.WebxContextLoaderListener</listener-class>
    </listener>
    ...
</web-app>

Webx Framework将会自动搜索/WEB-INF目录下的XML配置文件,并创建下面这种级联的spring容器。

图 3.1. 级联的Spring容器

Webx Framework将一个WEB应用分解成多个小应用模块:app1app2,当然名字可以任意取。

  • 每个小应用模块独享一个Spring Sub Context子容器。两个子容器之间的beans无法互相注入。
  • 所有小应用模块共享一个Spring Root Context根容器。根容器中的bean可被注入到子容器的bean中;反之不可以。

将一个大的应用分解成若干个小应用模块,并使它们的配置文件相对独立,这是一种很不错的开发实践。然而,如果你的应用确实很简单,你不希望把你的应用分成多个小应用模块,那么,你还是需要配置至少一个小应用模块(子容器)。

//初始化日志系统 - /WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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
    ">
    ...
    <listener>
        <listener-class>com.alibaba.citrus.logconfig.LogConfiguratorListener</listener-class>
    </listener>
    ...
</web-app>
  • 假设你的应用依赖了logback的jar包,那么listener就会查找/WEB-INF/logback.xml,并用它来初始化logback;
  • 如果你的应用依赖了log4j的jar包,那么listener也会很聪明地查找/WEB-INF/log4j.xml配置文件。
  • 假如以上配置文件不存在,listener会使用默认的配置 —— 把日志打印在控制台上。
  • Listener支持对配置文件中的placeholders进行替换。
  • Listener支持同时初始化多种日志系统。

2. Webx响应请求

图 3.2. Webx Framework如何响应请求

当Webx Framework接收到一个来自WEB的请求以后,实际上它主要做了两件事:

  1. 首先,它会增强request、response、session的功能,并把它们打包成更易使用的RequestContext对象。
  2. 其次,它会调用相应子应用的pipeline,用它来做进一步的处理。
  3. 假如在上面的过程中出现异常,则会触发Webx Framework处理异常的过程。

此外,Webx Framework还提供了一组辅助开发的功能,例如查看环境变量,查看schema等。这些功能只在开发模式生效,生产模式下自动关闭。

增强request、response、session的功能

Webx Framework提供了一个request contexts服务。Request contexts服务利用HttpServletRequestWrapperHttpServletResponseWrapper对request和response对象进行包装,以实现新的功能。

//配置request contexts服务
<services:request-contexts xmlns="http://www.alibaba.com/schema/services/request-contexts">
    <basic />
    <buffered />
    <lazy-commit />
    <parser />
    <set-locale defaultLocale="zh_CN" defaultCharset="UTF-8" />
    ...
</services:request-contexts>

<services:upload sizeMax="5M" />

可用的RequestContext扩展

名称 说明
<basic> 对输入、输出的数据进行安全检查,排除可能的攻击。例如:XSS过滤、CRLF换行回车过滤等。
<buffered> 对写入response中的数据进行缓存,以便于实现嵌套的页面。
<lazy-commit> 延迟提交response,用来支持基于cookie的session。
<parser> 解析用户提交的参数,无论是普通的请求,还是multipart/form-data这样的用于上传文件的请求。
<set-locale> 设置当前请求的区域(locale)、编码字符集(charset)。
<rewrite> 改写URL及参数,类似于Apache HTTPD Server中的rewrite模块。
<session> 增强的Session框架,可将session中的对象保存到cookie、数据库或其它存储中。

Request contexts所有的功能都是可配置、可扩展的 —— 它是基于SpringExt的扩展机制。

Request contexts所增加的功能对于所有的基于标准Servlet API的应用都是透明的 —— 这些应用根本不需要知道这些扩展的存在。例如,假如你在request contexts服务中配置了增强的session框架,那么所有通过标准的Servlet API取得session的应用,都将获得新功能:

//取得增强的session对象
HttpSession session = request.getSession();

  再比如,只要你配置了upload服务,那么下面的调用将同样适用于multipart/form-data类型的请求(Servlet API本身是不支持upload表单的):

//取得upload表单的参数
String value = request.getParameter("myparam");
//webx中可以注入request、response、session
public class LoginAction {
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private HttpSession session;
    ...
}

  在这个例子中,LoginAction类可以是一个singleton。一般来说,你不能把request scope的对象,注入到singleton scope的对象中。但你可以把HttpServletRequestHttpServletResponseHttpSession对象注入到singleton对象中。为什么呢?原来,Request contexts服务对这几个常用对象进行了特殊处理,将它们转化成了singleton对象。

Pipeline流程机制

Webx Framework赋予开发者极大的自由,来定制处理请求的流程。这种机制就是pipeline。Pipeline的意思是管道,管道中有许多阀门(Valve),阀门可以控制水流的走向。Webx Framework中的pipeline可以控制处理请求的流程的走向。如图所示。

图 3.3. Pipeline工作原理示意

Webx Framework并没有规定管道的内容,然而Webx Framework提供了一系列通用valves,你可以使用它们:

分类 Valves 说明
循环 <while> 有条件循环
<loop> 无条件循环
选择分支 <if> 单分支
<choose><when><otherwise> 多分支
中断 <break> 无条件中断

<break-if>

<break-unless>

有条件中断
<exit> 无条件退出整个pipeline(结束所有的嵌套层次)
异常捕获 <try-catch-finally> 类似Java中的try-catch-finally结构
嵌套 <sub-pipeline> 创建嵌套的子pipeline。

  当应用发生异常时,Webx Framework可以处理这些异常。

条件 处理
开发模式 展示详细出错信息。
生产模式 假如存在exception pipeline 用exception pipeline来处理异常;
不存在exception pipeline 显示web.xml中定义的默认错误页面。

开发模式工具

Webx Framework提供了一个开关,可以让应用运行于“生产模式(Production Mode)”或是“开发模式(Development Mode)” 。

<services:webx-configuration>
    <services:productionMode>${productionMode:true}</services:productionMode>
</services:webx-configuration>//使用这行配置,并且在启动应用服务器时指定参数“-DproductionMode=false”,就会让Webx以开发模式启动。

  Webx Framework提供了一个接口:ProductionModeAware。Spring context中的beans,如果实现了这个接口,就可以感知当前系统的运行模式,从而根据不同的模式选择不同的行为 —— 例如:在生产模式中打开cache,在开发模式中关闭cache。

//利用ProductionModeAware接口感知运行模式,并自动开关cache
public class ModuleLoaderServiceImpl implements ProductionModeAware {
    public void setProductionMode(boolean productionMode) {
        this.productionMode = productionMode;
    }

    @Override
    protected void init() {
        ……
        if (cacheEnabled == null) {
            cacheEnabled = productionMode;
        }
        ……
    }
}

  响应和处理请求的更多细节

当一个HTTP请求到达时,首先由WebxFrameworkFilter接手这个请求:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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>webx</filter-name>
        <filter-class>com.alibaba.citrus.webx.servlet.WebxFrameworkFilter</filter-class>
        <init-param>
            <param-name>excludes</param-name>
            <param-value><!-- 需要被“排除”的URL路径,以逗号分隔,前缀!表示“包含”。例如/static, *.jpg, !/uploads/*.jpg --></param-value>
        </init-param>
        <init-param>
            <param-name>passthru</param-name>
            <param-value><!-- 需要被“略过”的URL路径,以逗号分隔,前缀!表示“不要略过”。例如/myservlet, *.jsp --></param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>webx</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    ...
</web-app>

  为什么使用filter而不是servlet呢?传统的WEB框架的控制器一般都是用servlet实现的。原因是:

  • Filter可以“返还控制” —— 上面的配置文件直接把“/*”映射到webx filter中,这意味着webx接管了这个应用的所有请求。静态页面和资源怎么办?没关系,如果webx发现这个请求不应该由webx来处理,就会把控制“返还”给原来的控制器 —— 可能是另一个filter、servlet或者返回给servlet引擎,以默认的方式来处理。而Servlet是不具备“返还控制”的机制的。
  • Servlet/Filter mapping的局限性 —— 标准的servlet引擎将URL映射到filter或servlet时,只支持前缀映射和后缀映射两种方式,非常局限。而实际情况往往复杂得多。Webx建议将所有请求都映射给webx来处理,让webx对请求做更灵活的映射。

如果你的web.xml中还有一些其它的servlet mappings,为了避免和Webx的URL起冲突,你可以把这些mapping加在excludespassthru参数里。这样,WebxFrameworkFilter就会排除或略过指定的URL。

passthru略过”和“excludes排除”的区别在于,如果一个servlet或filter接手被webx passthru的请求时,它们还是可以访问到webx的部分服务,对于一个被passthru的请求,webx的行为更像是一个普通的filter。而“排除”则不同,如果一个请求被“排除”,webx将会立即放弃控制,将请求交还给服务器。接手控制的servlet或filter将无法访问webx一切的服务。

下图是WebxFrameworkFilter处理一个WEB请求的过程。

WebxFrameworkFilter接到请求以后,就会调用WebxRootController,进入Spring的世界 — 此后所有的对象:WebxRootControllerWebxController、 RequestContext、 Pipeline 等,全部是通过SpringExt配置在Spring Context中的。

     WebxRootController对象存在于root context中,它被所有子应用所共享。它会创建RequestContext实例 —— 从而增强request、response、session的功能。接下来,WebxController对象会被调用。

     WebxController对象是由每个子应用独享的,子应用app1app2可以有不同的WebxController实现。默认的实现,会调用pipeline。

Pipeline也是由各子应用自己来配置的。假如pipeline碰到无法处理的请求,如静态页面、图片等,pipeline应当执行<exit/> valve强制退出。然后WebxRootController就会“放弃控制” —— 这意味着request将被返还给/WEB-INF/web.xml中定义的servlet、filter或者返还给servlet engine本身来处理。

3. 定制Webx Framework

//WebxRootController是被所有子应用所共享的逻辑。
<webx-configuration xmlns="http://www.alibaba.com/schema/services">
    <components>
        <rootController class="com.myframework.MyRootController" />
    </components>
</webx-configuration>

  创建自己的WebxRootController。最简便的方法是:扩展AbstractWebxRootController,免去了创建Servlet/Filter、初始化Spring容器、处理request、response等繁杂事务,并且完全支持SpringExt的所有功能,此外还包含了错误处理、开发模式等Webx Framework中的一切便利。

WebxController是用来控制子应用的。每个子应用可以拥有不同的WebxController实现。

Webx Framework默认的WebxController是调用pipeline。假如你不想用pipeline,而希望实现自己的针对子应用的逻辑,那么最简单的方法就是实现自己的WebxController或者扩展AbstractWebxController

//WebxController是用来控制子应用的。每个子应用可以拥有不同的WebxController实现。
<webx-configuration xmlns="http://www.alibaba.com/schema/services">
    <components defaultControllerClass="com.myframework.MyController"> //指定默认的WebxController实现类。
        <component name="app1">
            <controller class="com.myframework.MyController" /> //对特定子应用明确指定WebxController实现类。
        </component>
    </components>
</webx-configuration>

  Webx Framework提供了一个可剪裁、可扩展的处理WEB请求基本框架。它所提供的基本功能事实上是每个WEB框架都需要用到的。

 

时间: 2024-08-05 09:12:28

Webx学习笔记(三)Webx Framework的相关文章

Webx学习笔记(四)Webx Turbine

Webx Turbine建立在Webx Framework的基础上,实现了页面渲染.布局.数据验证.数据提交等一系列工作.Webx Turbine所遵循下面的设计理念包括:页面驱动约定胜于配置 页面布局: Screen,代表页面的主体.Layout,代表页面的布局.Control,代表嵌在screen和layout中的页面片段 1.webx设计理念: 页面驱动:         在程序员介入以前,让界面设计师可以直接创建模板,并展示模板的效果.页面驱动的反面,是程序驱动,或者是Action驱动

webx学习笔记

Webx学习笔记周建旭 2014-08-01 Webx工作流程 图 3.2. Webx Framework如何响应请求 当Webx Framework接收到一个来自WEB的请求以后,实际上它主要做了两件事: 1. 首先,它会增强request.response.session的功能,并把它们打包成更易使用 的RequestContext对象. #macro (registerMessage $field) #if (!$field.valid) $field.message #end #end

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle&lt;T&gt;

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T> 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现和源码 下一篇用它们做一个多语言的demo 这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突. 先看一下它的实现思想 在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

NFC学习笔记——三(在windows操作系统上安装libnfc)

本篇翻译文章: 这篇文章主要是说明如何在windows操作系统上安装.配置和使用libnfc. 一.基本信息 1.操作系统: Windows Vista Home Premium SP 2 2.硬件信息: System: Dell Inspiron 1720 Processor: Intel Core 2 Duo CPU T9300 @ 2.5GHz 2.5GHz System type: 32-bit Operating System 3.所需软件: 在windows操作系统上安装软件需要下列

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

加壳学习笔记(三)-简单的脱壳思路&amp;调试思路

首先一些windows的常用API: GetWindowTextA:以ASCII的形式的输入框 GetWindowTextW:以Unicaode宽字符的输入框 GetDlgItemTextA:以ASCII的形式的输入框 GetDlgItemTextW:以Unicaode宽字符的输入框 这些函数在使用的时候会有些参数提前入栈,如这函数要求的参数是字符串数目.还有大小写啦之类的东西,这些东西是要在调用该函数之前入栈,也就是依次push,就是说一般前面几个push接着一个call,那前面的push可能

【Unity 3D】学习笔记三十四:游戏元素——常用编辑器组件

常用编辑器组件 unity的特色之一就是编辑器可视化,很多常用的功能都可以在编辑器中完成.常用的编辑器可分为两种:原有组件和拓展组件.原有组件是编辑器原生的一些功能,拓展组件是编辑器智商通过脚本拓展的新功能. 摄像机 摄像机是unity最为核心组件之一,游戏界面中显示的一切内容都得需要摄像机来照射才能显示.摄像机组件的参数如下: clear flags:背景显示内容,默认的是skybox.前提是必须在render settings 中设置天空盒子材质. background:背景显示颜色,如果没

马哥学习笔记三十二——计算机及操作系统原理

缓存方式: 直接映射 N路关联 缓存策略: write through:通写 write back:回写 进程类别: 交互式进程(IO密集型) 批处理进程(CPU密集型) 实时进程(Real-time) CPU: 时间片长,优先级低IO:时间片短,优先级高 Linux优先级:priority 实时优先级: 1-99,数字越小,优先级越低 静态优先级:100-139,数据越小,优先级越高 实时优先级比静态优先级高 nice值:调整静态优先级   -20,19:100,139   0:120 ps