总文档 :文章目录
Github : github.com/black-ant
一 . 前言
DWR 是一个可以用于前后端交互的工具 , 其本质是一个长连接 , 它具有以下的主要功能 :
- 前端JS直接调用后端方法
- 后端代码直接运行前端JS
DWR 这个工具是一个比较有历史的工具了 , 在集群或者其他特殊环境中 , 具有很大的局限性 , 相对而言其实有很多更合适的解决方案 , 这一篇主要是对其设计的思路进行一个分析 .
来看看早期的前后端强耦合的意义和设计思路.
二 . 使用
使用主要分为以下几个步骤 :
- 配置准备
- 准备 Java 端 service
- 准备 DwrScriptSessionManager 用于Java 端调用 Web 端
- 前端使用
2.1 配置准备
准备配置Bean
配置的 Bean 准备没有太多东西 , 这个Bean 主要用于生成一个 ServletRegistrationBean , 并且为其配置了多个属性
ServletRegistrationBean : ServletContextInitializer是用于在Servlet 3.0容器中注册 Servlet
1 | java复制代码 /** |
准备配置 XML : dwr-spring-config.xml
主要是开启注解 , 设置扫描路径
1 | XML复制代码<?xml version="1.0" encoding="UTF-8"?> |
注意要导入该配置 : @ImportResource(locations = "classpath:dwr-spring-config.xml")
2.2 准备 Java 端
- @RemoteProxy : 远程代理类
- @RemoteMethod : 远程方法
1 | java复制代码@Service |
2.3 其他类
DwrContainer : 用于扩展容器
- 从Spring上下文中指定的配置中查找所有bean
- 从Spring web应用程序上下文中加载配置
1 | java复制代码public class SpringDwrContainer extends SpringContainer { |
SpringDwrServlet : 构建 DWRServlet
DWRServlet 的主要实现 : 处理所有对DWR的调用的servlet
DWRServlet从Spring IoC容器中检索配置。这可以通过两种方式实现 :
- 使用Spring命名空间。当为DWR使用Spring名称空间时,这个servlet会自动获取DWR的配置
- 显式地指定要选取的配置。
1 | java复制代码@Component |
DwrScriptSessionManagerUtil : 添加 container
ScriptSessionListener : 该对象是一个监听器 , 当web应用程序中的活动会话列表发生更改时,将通知此接口的实现 , 即监听变化时处理
1 | java复制代码public class DwrScriptSessionManagerUtil extends DwrServlet { |
2.4 前端源码
其中主要是多个工具 js , 直接获取即可 :
1 | java复制代码<html> |
三 .简单看看前端源码
DWR 核心是建立一个长连接 , 通过其本身封装的 JS 和 Servlet ,通过 Invoke 代理类实现相互调用
以下是 DWR 的前端结构
先简单过一下前端 JS 的调用 :
可以看到每个 @RemoteProxy 标注的类都有一个 对应的 JS :
1 | java复制代码if (typeof dwr == 'undefined' || dwr.engine == undefined) throw new Error('You must include DWR engine before including this file'); |
核心都是通过一个 JS 对象 dwr.engine 来完成 , 这个 execute 做了这些事
1 | java复制代码 |
四 . 后端源码分析
4.1 一切的起点
核心还是通过一个 HttpServlet 类实现的 :
1 | java复制代码 |
4.2 核心逻辑
核心逻辑主要是以下几个步骤 :
Step 1 : Servlet 对请求做出拦截
Step 2 : 获取请求的属性 (UrlProcessor) , 获取一个 CreatorModule
Step 3 : 通过该 Module 获取其中的 creator (Module 类似于一个模块体系)
Step 4 : 通过 create 获取对应的 method ,反射调用接口
Step 1 : 核心注解的扫描
1 | java复制代码C02- AnnotationsConfigurator |
Step 3 : 请求的拦截调用
当我们访问一个 DWR 请求的时候 , 会被 DwrServlet 所拦截
1 | java复制代码C04- DwrServlet |
剩下一个 , Method 是怎么管理的
1 | java复制代码C07- DefaultRemoter |
CreatorModule 的管理逻辑
到这里 Method 的逻辑就清楚了 , 最后一步 , CreatorModule 的管理逻辑
1 | java复制代码 |
五 . 扩展
如何通过 DWR 实现扫码 :
Step 1 : 前端生成一个 id 向后端申请二维码
Step 2 : 后端通过ID等其他本地信息生成二维码提供给前端 (二维码中包含 : redirect_uri / 认证信息)
Step 3 : App 扫描 二维码 , 通过 认证信息认证 判断后 , 调用 redirect_uri回调
Step 4 : 后端拿到回调信息 , 其中会包含 Step 1 的ID , 通过 ID 来告知对应前端 (当然也可以群发前端自己认证)
总结
关于使用:
DWR 源码看完后 ,感觉逻辑并不复杂 , 像个容器管理框架一样 ,去代理和反射了一套类 ,通过其本身的一套请求路径机制 , 来调用本地的方法 . 耦合性颇高.
关于历史:
dwr 的使用其实和 rpc 有在’说黑话‘的思路上是一致的 , 都隐藏了网络层的具体逻辑 , 但是 rpc 仍然被 dubbo 作为主流 , 而dwr 却逐渐从大众视野里消失
想了一下 ,大概有以下几个原因 :
- DWR的发布周期慢
- 面对现在越来越复杂的网络环境 , dwr 的耦合性还是太强了 , 不便于开发和接口控制.
- 尤其是近年来发展了微服务 ,这种初期看起来很简单的直接调用带了了非常多的问题
- RPC 是为了解决更多的请求问题 ,它比 http 精简 , 保密 , 使调用简单化 , 而 DWR , 看多年前的吐槽就能发现 , 它会导致所有的 HTTP 请求被沾满 , 用法简单 ,但是使底层更加复杂
- rpc 是服务端互调 , 其要解决的是服务端互调的复杂性
- 前后端互调 , 本身就需要通过复杂性来控制业务能力 , 尤其是业务越来越复杂 , 其出发点主要集中在了简化 , 而没有提高可用性
总得来说 , 就是不够轻量级 , 比如看这些图 :
2009 年的时候 , 用 DWR 比 AJAX 更简单
2015 年 , 大家都认为它太笨重了
2020+ , JQuery 的笨重都被diss 到哪了 , 更轻量级的工具更受欢迎
~
大人 , 时代变了!!!
本文转载自: 掘金