这是我参与更文挑战的第3天,活动详情查看: 更文挑战
总文档 :文章目录
Github : github.com/black-ant
一 . 前言
Spring Web Flow 是一个 Spring 的流处理框架 , 这是个使用不多的框架
一开始我也陷入一种误区 , 一直在查找他和 SpringMVC 的优劣 , 但是实际上 , 他们2者是不冲突的 .
SpringWebFlow 建立在 SpringMVC 之上,并允许实现 Web 应用程序的“流程”。流封装了指导用户执行某些业务任务的一系列步 .
也就是说 : 它可以作为一种完善 SpringMVC 的角色 , 以满足 SpringMVC 不能做到的复杂功能
作用官方说明 : Spring Web Flow 的最佳选择是有状态的 Web 应用程序,它具有可控导航,比如登机、申请贷款、购物车结账,甚至在表单中添加确认步骤 ,他们通常有以下特征 :
- 有一个清晰的起点和终点
- 用户必须按照特定的顺序浏览一组视图(表单)
- 直到最后一步,更改才最终确定
- 一旦完成,就不可能意外地重复一个事务
以上是官方说法 ,但是个人在生产中 , 也体验过该框架 , 说说感受 :
- 对视图依赖高 , 可以做到但是不好做到前后端分离 (视图不限定于 Thymeleaf 等引擎 , 但是如果不使用引擎 , 会丢失很多特性)
- invoke 代理复杂 , 对框架不熟悉基本是很难 debug 流程
- 只适合单流程 , 不易做到多人审批操作
- 没有可视化的配置途径 (至少我没看到)
但是他也有其他的优点:
- 在不考虑前后端分离时 , scope 域用来渲染参数很方便
- 集成简单 , 不需要对外部有过多依赖
- 当需要做一个负载的单流程时 , 可以最大化的梳理流程减少耦合提高可视度 (不考虑其他 Flow 插件)
- 与 MVC 无冲突
二 . 基础使用
2.1 Java Config 配置
1 | java复制代码@Configuration |
2.2 WebFlow xml 配置
1 | xml复制代码<?xml version="1.0" encoding="UTF-8"?> |
2.3 WebView 文件
其中包含 4 个 html 文件 , 可以查看源码获取 @GitHub 源码
三 . 源码解析
因为 Spring Web Flow 的文档较少 , 而如果因为一些原因而使用该框架 , 以下分析流程会对你有所帮助:
从上述流程中 ,可以看到配置了以下几个对象 , 按照依赖关系进行展示:
Step 1 : 配置和映射
- MvcViewFactoryCreator : View 创建工厂
- FlowBuilderServices : Web Flow build 构建
- FlowDefinitionRegistry : Flow Definition 创建
- FlowHandlerMapping : 映射处理器
Step 2 : 业务处理
- FlowExecutor : WebFlow 执行器
- flowHandlerAdapter : WebFlow 适配器
3.1 MvcViewFactoryCreator 的配置
Step 1 : 配置文件入口
1 | java复制代码@Bean |
Step 2 : MvcViewFactoryCreator 创建详情
功能 : 返回ViewFactory视图工厂,该视图工厂创建基于Spring的原生视图。SpringMVC的视图工厂来配置流的视图状态
使用 :
- 创建视图工厂,这些视图工厂通过加载流相关资源(比如位于流工作目录中的.jsp模板)来解析它们的视图
- 这个类还支持呈现由预先存在的Spring MVC ViewResolver视图解析器解析的视图
从下图的方法中 ,我们大概可以看到提供了以下主要的功能 :
- setDefaultViewSuffix : 设置视图的后缀
- setUseSpringBeanBinding : 设置是否启用Spring的BeanWrapper使用数据绑定
- setFlowViewResolver : 设置 View 解析器
- setViewResolvers : 使用不同的 SpringMVC 解析器 , 托解析由流选择的视图
- setMessageCodesResolver : 设置用于解析绑定和验证错误消息代码的消息代码解析器策略
小总结 : 可以看到 , 实际上 WebFlow 和 MVC 有很多共用的类 ,并不是2个完全独立的个体.
3.2 FlowBuilderServices 详情
FlowBuilderServices 是构建 Flow 的主流程 , 主要用于配置流构建器使用的服务的简单holder , 从其内部资源就可以看到一二 :
- FlowArtifactFactory : 封装中心流构件(如流和状态)创建的工厂
- ViewFactoryCreator : 视图工厂创建器,用于创建在流执行期间呈现的视图
- ConversionService : 用于从一种对象类型转换为另一种对象类型的转换服务
- ExpressionParser : 用于将表达式字符串解析为表达式对象的解析器。默认是Web Flow的默认表达式解析器实现
- Validator : 验证器实例,用于验证在视图状态上声明的模型
- ValidationHintResolver : 用于解析基于验证提示的字符串的ValidationHintResolver
- ApplicationContext : 主容器
PS : 这个类其实就是一个综合类 , 用于将多个业务处理类进行整合
3.3 FlowDefinitionRegistry 详情
Step 1 : 配置的入口
1 | java复制代码@Bean |
[Pro] : FlowDefinitionRegistry 的作用是什么 ?
FlowDefinitionRegistry 用于访问在运行时执行的注册流定义 , 该对象会扫描 xml 文件
Step 2 : Builder 构建流程
可以看到 , 就是 new 一个对象 , 包括当前的 ApplicationContext 以及 BuildService
1 | java复制代码protected FlowDefinitionRegistryBuilder getFlowDefinitionRegistryBuilder(FlowBuilderServices flowBuilderServices) { |
Step 3 : FlowDefinitionRegistryBuilder 构建
1 | java复制代码public FlowDefinitionRegistryBuilder(ApplicationContext appContext, FlowBuilderServices builderServices) { |
[Pro] : FlowDefinitionResourceFactory 作用 ?
用于创建流定义资源的工厂,这些资源用作指向外部流定义文件的指针
- setBasePath : 设置在确定默认流id时从流路径中删除的基础路径
- createResource: 从提供的路径位置创建流定义资源
- createFileResource : 从提供的文件路径创建基于文件的资源
- getFlowId :
Step 4 : FlowLocation 构建
每一个 Flow.xml 会被映射为一个 FlowLocation 对象 , 该对象映射一个 xml 文件
1 | java复制代码private static class FlowLocation { |
Step 5 : FlowLocation 的扫描
在 FlowDefinitionRegistryBuilder 中会扫描所有的 FlowLocation 对象 , 并且进行处理
1 | java复制代码private void registerFlowLocations(DefaultFlowRegistry flowRegistry) { |
[Pro] : registerFlowLocations 被调用的方式
在 build 方法中创建 FlowDefinitionRegistry
1 | java复制代码C- FlowDefinitionRegistryBuilder |
[Pro] : FlowDefinitionResource 构建方式
FlowDefinitionResource 通过其工程类构建 , FlowDefinitionResourceFactory在构造器中默认创建
this.flowResourceFactory = new FlowDefinitionResourceFactory(appContext);
1 | java复制代码public FlowDefinitionResource createResource(String path, AttributeMap<Object> attributes, String flowId) { |
Step 6 : Flow 注册
1 | java复制代码private void registerFlow(FlowDefinitionResource resource, DefaultFlowRegistry flowRegistry) { |
[Pro] : FlowModelBuilder 作用
用于构建流模型的构建器接口。构建流模型的过程包括以下步骤 >>
- 通过调用 #init()初始化这个生成器
- 调用#build()创建流模型
- 调用#getFlowModel()返回完全构建的FlowModel模型
- 释放此构建器,通过调用# Dispose()释放构建过程中分配的任何资源
Step 7 : FlowDefinitionRegistryImpl 注册
1 | java复制代码flowDefinitions.put(definitionHolder.getFlowDefinitionId(), definitionHolder) |
3.4 FlowHandlerMapping 构建
通过 FlowDefinitionRegistry 构建 FlowHandlerMapping , 用于后续处理
作用 : HandlerMapping的实现,遵循一个简单的约定,从注册的FlowDefinition的id来创建URL路径映射
返回 : 该实现返回一个FlowHandler,如果当前请求路径与配置的FlowDefinitionRegistry中的流的id匹配,该FlowHandler将调用流。
FlowUrlHandler 是一个接口 , 他有3个实现类 , 此处主要为 DefaultFlowUrlHandler
- DefaultFlowUrlHandler
- FilenameFlowUrlHandler
- WebFlow1FlowUrlHandler
1 | java复制代码// FlowHandlerMapping 属性 |
3.5 HandlerAdapter
作用 : 一个自定义的MVC HandlerAdapter ,封装了与Servlet环境中执行流相关的通用工作流。委托映射的FlowHandler流处理程序来管理与特定流定义执行的交互
此处主要使用 FlowHandlerAdapter , 简单看一下其主要方法就知道其作用了
1 | java复制代码// 可以看到还是使用 ModelAndView 返回视图对象 |
总结
总结一下 , FlowBuilderServices 作为全局业务类 , MvcViewFactoryCreator 用于创建 View 工厂 , ,通过 FlowHandlerMapping 拦截请求后, 再通过 FlowDefinitionRegistry 注册 Flow , 执行 FlowExecutor 和 flowHandlerAdapter 返回 view 对象
不过在我自己的使用中 , 通常会选用其他的 flow 框架 , Spring Flow 从社区到文档 , 都不是一个较好的选择 ,除非自己项目不想做的太复杂 , 也有相关的限制.
后续我会对比他和其他的 flow 框架的区别 , 拭目以待 >>>
本文转载自: 掘金