SpringBoot整合DWR 3.0.2-RELEASE填坑日记

  • 填坑背景
  • 问题溯源
  • 填坑步骤
    • 一、示例代码结构
    • 二、示例代码说明
      • 1、框架配置代码编写
      • 2、后端服务代码编写
      • 3、后端服务注册配置
      • 4、框架服务初始配置
    • 三、框架源码改动
    • 四、示例运行效果
    • 五、示例资源代码
  • 填坑随记

填坑背景

由于最近在进行本公司一个老产品的技术升级改造工作,在原产品中使用了DWR,并且涉及到的代码量比较大,所以在本次使用SpringBoot重构时选择保留原有DWR相关的技术代码。自然就需要做SpringBoot和DWR的整合工作。本来一切无恙,很快就完成了这一块的技术改造工作,并且开发环境下一切运行良好。本以为改造工作就此结束,谁料想,在开发环境及其外置Tomcat运行良好的项目,打包成JAR包运行时,出问题了,DWR无法正常初始化及其调用,报错信息如下:

问题溯源

当遇到上面这个问题的时候,一开始还是比较懵的,怀疑是自己打包哪里出了问题,于是又反反复复折腾了好久,无果!都是一样的结果摆在眼前,那就是整合后的工程在开发环境下运行良好,打成WAR包部署到外置Tomcat下也运行正常,唯独使用内置Tomcat采用JAR的形式无法运行。
反反复复,从代码缺陷,运行环境,JDK版本、Tomcat版本、SpringBoot版本各方面去试图排查解决,结果都是一无所获。最终想到了找度娘,找谷歌,欲哭无泪,都是技术整合代码一箩筐,遇到该问题的较多,但实际解决的没有一个,于是在网上看到的很多都是建议直接部署到外置Tomcat下运行,这就完事了吗,问题是我们的项目有技术要求,不可以这么玩,那不是废了么,无奈只能考虑从源码入手,由于从2016年DWR 3.0.2-RELEASE发布至今基本后期维护较少,好在开源项目可以从源码入手,终于找到了该问题的根源所在。
由于DWR最后一个发布版本发布之时,SpringBoot并没有像现在这么大范围的应用起来,自然源码中有点缺陷也不足为奇。经过一翻阅读,最终定位到问题的根源所在尽然是由于类加载器不同而导致的,我们都知道SpringBoot项目中加载资源的方式如果你使用的是Jar方式运行,那么资源的读取都是无法使用文件路径再去定位的,都是要采用流的方式读取。
经过排查,在开发环境和外置Tomcat部署运行是,使用的类加载器主要为:
sun.misc.Launcher和TomcatEmbeddedWebappClassLoader
而采用SpringBoot的独立JAR方式运行时,使用的类加载器为
org.springframework.boot.loader.LaunchedURLClassLoader
既然找到了问题的根源所在,那就可以愉快的填坑了。

填坑步骤

一、示例代码结构

示例代码结构如下图所示,其中红色框起来的地方为整合的核心代码,从示例代码可以看出来整合中没有相关的配置文件,即以往DWR框架相关的配置文件如dwr.xml都是不需要的,我们都采用Java代码去实现这些配置工作。

二、示例代码说明

采用配置方式整合SpringBoot和DWR时,主要包括三个核心步骤,即:DWR框架配置、后端服务代码注册、DWR框架初始化三个环节。其中DwrEngineConfig.java主要罗列了DWR框架常用的一些配置,实际项目中可以根据需要进行配置使用,代码如下(注意:此处罗列了可能用到的相关配置,很多目前都是赋给的初始值,实际根据项目需要只配置其中个别配置项即可):
DWR框架配置示例代码如下:

1、框架配置代码编写

package com.sword.dwrdemo.config;import org.directwebremoting.servlet.DwrListener;
import org.directwebremoting.servlet.DwrServlet;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** @Description: SpringBoot整合Dwr框架核心配置类* @Author 刘剑涛* @Date 2021-02-27 00:50*/
@Configuration
public class DwrEngineConfig {@Beanpublic ServletRegistrationBean dwr() {ServletRegistrationBean servlet = new ServletRegistrationBean(new DwrServlet(), "/dwr/*");Map<String, String> initParam = new HashMap<>();/**===============以下列举所有可配置参数,根据需要选择配置===============*/// 1.是否支持JSONP,设置为true则支持JSONP。默认:falseinitParam.put("jsonpEnabled", "false");// 2.是否让DWR工作在Safari 1.x,设置为true则支持Safari 1.x,会稍微降低安全性。默认:falseinitParam.put("allowGetForSafariButMakeForgeryEasier", "false");// 3.是否支持跨域,设置为false则支持跨域请求。默认:trueinitParam.put("crossDomainSessionSecurity", "false");// 4.是否启用script标签的远程访问,设为true启用。默认:trueinitParam.put("allowScriptTagRemoting", "true");// 5.是否启用Debug模式,true标识启用。默认:falseinitParam.put("debug", "true");// 6.设置scriptSessions的超时时间。默认:1800000(表示30分钟)initParam.put("scriptSessionTimeout", "1800000");// 7.一次批量(batch)允许最大的调用数量。(帮助保护Dos攻击)。默认:20initParam.put("maxCallCount", "20");// 8.是否启用轮询和长连接,设置为true标识启用(2.0 RC3版本)。默认:falseinitParam.put("activeReverseAjaxEnabled", "true");// 9.是否启用轮询和长连接,设置为true标识启用(2.0 RC1版本)。默认:false,设置成true能增加服务器的加载能力,尽管DWR有保护服务器过载的机制。initParam.put("pollAndCometEnabled", "true");// 10.等待线程的最大数量。默认:100initParam.put("maxWaitingThreads", "100");// 11.每秒最大的访问数量。默认:40initParam.put("maxHitsPerSecond", "40");// 12.dwr服务端类的页面引用方式。默认:interfaceinitParam.put("generateDtoClasses", "interface");// 13.默认值支持最后修改,这样就允许服务器端对客户端请求较少资源。设置为true就能屏蔽支持。initParam.put("ignoreLastModified", "false");// 14.默认来说逆向Ajax对同一页面不同查询参数将会认为同一个页面。默认:falseinitParam.put("normalizeIncludesQueryString", "false");// 15.默认来说逆向Ajax对同一页面不同session id将会认为同一个页面。默认:falseinitParam.put("normalizeIncludesSessionID", "false");// 16.DWR通过检查文档和提取当前session ID支持URL重写。一些servlet引擎使用非标准的cookie名。initParam.put("sessionCookieName", "JSESSIONID");// 17.DWR能够执行简单的压缩,设置为true可以激活此功能。另外还有一个未公开的有关系的重要参数“compressionLevel”,此参数允许你配置压缩类型。initParam.put("scriptCompressed", "false");// 18.对一个打开流后的反应,等待的最大时间,默认值:1000(单位:毫秒)initParam.put("postStreamWaitTime", "1000");// 19.对一个打开流前的反应,等待的最大时间,默认值:29000(单位:毫秒)initParam.put("preStreamWaitTime", "29000");// 20.其余可配置参数及其自定义重写参数配置initParam.put("initApplicationScopeCreatorsAtStartup", "true");initParam.put("maxWaitAfterWrite", "1800000");initParam.put("disconnectedTime", "60000");initParam.put("classes", "java.lang.Object");//WARNinitParam.put("logLevel", "ERROR");//自定义配置,org.directwebremoting.impl.StartupUtil#configureFromInitParams name.equals("customConfigurator")initParam.put("customConfigurator", "com.sword.dwrdemo.config.DwrXmlConfig");servlet.setInitParameters(initParam);return servlet;}@Beanpublic ServletListenerRegistrationBean dwrListener() {return new ServletListenerRegistrationBean(new DwrListener());}}

2、后端服务代码编写

package com.sword.dwrdemo.web;import org.directwebremoting.Browser;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ScriptSessionFilter;
import org.directwebremoting.ScriptSessions;
import org.springframework.stereotype.Controller;import java.util.Map;/*** @Description: 待请求处理类* @Author 刘剑涛* @Date 2021-02-27 00:50*/
public class DwrDemoHandler{public String call(String name) {System.out.println("本次调用示例代码传递的参数为:" + name);return "您好,欢迎使用DWR!本次回声测试参数为:" + name;}}

3、后端服务注册配置

package com.sword.dwrdemo.config;import org.directwebremoting.Container;
import org.directwebremoting.create.NewCreator;
import org.directwebremoting.extend.Configurator;
import org.directwebremoting.extend.CreatorManager;/*** @Description: 配置原有的DwrXml文件内容* @Author 刘剑涛* @Date 2021-02-27 00:50*/
public class DwrXmlConfig implements Configurator {@Overridepublic void configure(Container container) {CreatorManager creatorManager = container.getBean(CreatorManager.class);NewCreator creator = new NewCreator();creator.setClass("com.sword.dwrdemo.web.DwrDemoHandler");creator.setJavascript("DwrDemoHandler");creatorManager.addCreator(creator);}}

4、框架服务初始配置

package com.sword.dwrdemo.config;import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;import javax.servlet.ServletContext;/*** @Description: 初始化DwrServlet* @Author 刘剑涛* @Date 2021-02-27 00:50*/
@Component
public class ContextInitListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {WebApplicationContext webApplicationContext = (WebApplicationContext)contextRefreshedEvent.getApplicationContext();ServletContext servletContext = webApplicationContext.getServletContext();servletContext.setAttribute("dwrServlet", "org.directwebremoting.servlet.DwrServlet");}}

三、框架源码改动

上面提到了由于框架本身缺陷导致的结果,在和SpringBoot做集成时,开发环境和外置Tomcat环境均运行正常,但是使用内置Tomcat以JAR包形式运行时则产生异常,导致DWR框架无法初始化,为了解决这点,主要修改了DWR源码中关于类加载器加载DWR相关资源文件的代码,由于源码涉及内容较多,我已经将修改过的DWR依赖重新打包,并上传到如下地址,
https://download.csdn.net/download/weixin_38122095/15499156
需要的朋友可以去下载,资源中包括上面示例的完整代码,以及修改后的dwr-3.0.2-RELEASE.jar资源包,及其示例代码可独立运行的示例JAR文件。

四、示例运行效果

示例的运行效果如下图所示:

服务端反馈信息:

DWR框架测试页面:

五、示例资源代码

由于涉及到DWR源码改动打包相关内容,此处不再详细阐述,我已经将本示例的完整代码及其修改后的dwr-3.0.2-RELEASE.jar资源文件上传,需要的朋友可以去下面的链接访问下载。
https://download.csdn.net/download/weixin_38122095/15499156

填坑随记

因为在网上找了很久没有找到开篇提到的问题的解决方案,所以就把自己解决该问题的完成过程记录在此,不管后续是否还有人再使用该框架,可能自己找到的只是其中一种解决方案,手敲不易,大家不喜勿碰哦。

SpringBoot整合DWR-3.0.2-RELEASE版本,以及解决项目在开发环境及其外置Tomcat运行正常,独立JAR形式内置Tomcat运行异常的问题相关推荐

  1. 教你如何使用android studio 4.0发布release 版本 学习记录 仅供参考

    教你如何使用android studio 4.0发布release 版本 学习记录 仅供参考 这是老师给我们布置的任务,我在这里做一个简单的总结,话不多说,直接上图上步骤吧 首先,在菜单栏中,点击 B ...

  2. 详解 springboot - 查看、修改内置 tomcat 版本

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 1.解析Spring Boot父级依赖 ? 1 2 3 4 5 6 <parent>   ...

  3. SpringBoot内置tomcat出现APR版本过低解决办法

    SpringBoot内置tomcat出现error:An incompatible version [1.1.32] of the APR based Apache Tomcat Native lib ...

  4. SpringBoot内置Tomcat浅析

    一.SpringBoot框架内置Tomcat,开发非常方便,随着SpringBoot的框架升级,内置Tomcat也更新版本.本文SpringBoot框架版本:2.2.10. 1.如何查看SpringB ...

  5. 优化之SpringBoot 内置tomcat 调优测试

    问题 怎么配置springBoot 内置tomcat,才能使得自己的服务效率更高呢? 基础配置 Spring Boot 能支持的最大并发量主要看其对Tomcat的设置,可以在配置文件中对其进行更改.我 ...

  6. SpringBoot内置tomcat启动原理

    前言 不得不说SpringBoot的开发者是在为大众程序猿谋福利,把大家都惯成了懒汉,xml不配置了,连tomcat也懒的配置了,典型的一键启动系统,那么tomcat在springboot是怎么启动的 ...

  7. SpringBoot内置Tomcat支持多大并发量和连接数

    SpringBoot内置Tomcat,再默认设置中,Tomcat的最大线程数是200,最大连接数是10000.支持的并发量是指连接数,200个线程如何处理10000条连接的? Tomcat有两种处理连 ...

  8. Spring Boot2.0之 原理—创建内置Tomcat容器

    前面所述的https://www.cnblogs.com/toov5/p/9823728.html 中的第一条先不赘述了,就是玩了maven 重点介绍后两条 首先内置Tomcat: SpringBoo ...

  9. SpringBoot内置tomcat出现error:An incompatible version [1.1.32] of the APR based Apache Tomcat Native lib

    SpringBoot内置tomcat出现error:An incompatible version [1.1.32] of the APR based Apache Tomcat Native lib ...

最新文章

  1. react遇到的各种坑
  2. “蓝桥杯”软件大赛入门训练4道题
  3. 双11行业“三连冠”,鞋王百丽走对了哪几步?
  4. 团队每日冲刺博客05
  5. loadrunner 场景设计-负载生成器管理
  6. android中资源文件的两种访问方式,在android开发中进行数据存储与访问的多种方式介绍...
  7. php rsa2 微博,微博登录分析
  8. 枯燥的计算机组成原理课.....!!! 看来只能自己看书消化了...!!!
  9. 《Word排版艺术》
  10. PHP根据经纬度计算距离
  11. linux 命令chmod 755的意思
  12. 蒟蒻的noip2015滚粗记
  13. 有哪些好用的视频录制工具?
  14. 100baseT、100baseFX、1000base-SX、100/1000base-T
  15. Facebook广告投放策略与优化Facebook广告成效的技巧方式
  16. Linux 安装 Intel 网卡驱动
  17. via导出书签html,书签助手,迈出换用 Via 浏览器的第一步 | App+1
  18. 学习USART自闭实录(stm32F411RE)Stm32cubemx
  19. 软阈值和硬阈值_设置阈值和资源组
  20. 关于打码机色带应用及其调整方法

热门文章

  1. 金融知识小科普 - 宽基指数
  2. android assets大小限制200m,使用 AssetsManager 解决微信小游戏包体积尺寸限制问题
  3. 如何通过企业微信便捷访问华为云、阿里云?
  4. 依锥彻怕燎方跃涣牧叵邻牟辟岗俅
  5. Linux上类似vbs脚本,VBS脚本常用经典代码收集
  6. 对AutoResetEvent和ManualResetEvent的理解
  7. Binding的详细说明
  8. linux认证教程,Linux认证考试:Linux系统的经典技巧
  9. js 获取计算机mac地址,JS获取计算机mac地址以及IP的实现方法
  10. Linux下集群的搭建