springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件

springmvc内嵌tomcat、tomcat整合springmvc、自研国产web中间件

这是由于公司老项目转化springboot存在太多坑,特别是hibernate事务一条就坑到跑路,你又不想搞没听说过的国产中间件兼容,又不想搞weblogic、WebSphere等中间件的适配,不如直接把提供给客户的产品内嵌于tomcat中,启动就是一个sh,同时让客户不用安装tomcat,释放你的维护时间

信创时,使用东方通(TongWeb)、宝兰德。有些名字你都没听过的
还有国外的IBM、weblogic等商用servlet容器
上面的容器或多或少都有各种坑,直接使用原方案tomcat部署,于是有了此文,将内嵌的tomcat直接运行springmvc项目。

此文优势

你可以根据此文章,自研一个国产中间件,它的功能照抄weblogic即可。用于加入信创项目赚钱自研产品。

前提条件

原springmvc项目转成springboot难度大,与其强行转不如折中转,质疑各种商用中间件、理解各种web商用中间件、放弃各种web商用中间件、成为各种web商用中间件提供商。

基础组成

项目框架组成:外置tomcat + spring5.3.x + springmvc +hibernate +mysql(oracle)
整改后:tomcat内嵌 + spring5.3.x + springmvc +hibernate +mysql(oracle)

特点

  • 老项目开发正常按照原来的开发模式,idea+tomcat。
  • 打包时,不是生成war,而是生成目录以及sh启动脚本。将内嵌tomcat打包到jar,同时添加sh启动脚本。(区别)

添加依赖

        <!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.84</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>9.0.84</version>
        </dependency>

2024-01-05 最新依赖,若spring版本较低,适当降低 tomcat-embed 版本

将打包类型改为jar

<packaging>jar</packaging>

移除原来的war插件:maven-war-plugin

添加下面的插件

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>3.6.0</version>
  <configuration>
    <appendAssemblyId>false</appendAssemblyId>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
    <archive>
      <!-- 此处,要改成自己的程序入口(即 main 函数类) -->
      <manifest>
        <mainClass>awb.TomcatServer</mainClass>
      </manifest>
    </archive>
    <descriptors>
      <!--assembly配置文件路径,注意需要在项目中新建文件package.xml-->
      <descriptor>${project.basedir}/src/main/resource/package/package.xml</descriptor>
    </descriptors>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

需要注意,老项目的resource是resource 最后面没有s,springboot项目是有s的。

src/main/resource/package/package.xml 配置如下

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    <!--
        assembly 打包配置更多配置可参考官方文档:
            http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
     -->
    <id>release</id>

    <!--
        设置打包格式,可同时设置多种格式,常用格式有:dir、zip、tar、tar.gz
            dir 格式便于在本地测试打包结果
            zip 格式便于 windows 系统下解压运行
            tar、tar.gz 格式便于 linux 系统下解压运行
     -->
    <formats>
        <format>dir</format>
        <!--<format>zip</format>-->
        <!-- <format>tar.gz</format> -->
    </formats>

    <!-- 打 zip 设置为 true 时,会在 zip 包中生成一个根目录,打 dir 时设置为 false 少层目录 -->
    <!--<includeBaseDirectory>true</includeBaseDirectory>-->

    <fileSets>
        <!-- src/main/resource 全部 copy 到 config 目录下 -->
        <fileSet>
            <directory>${basedir}/src/main/resource</directory>
            <outputDirectory>WebContent/WEB-INF/classes</outputDirectory>
            <includes>
                <!--包含那些依赖-->
            </includes>
        </fileSet>

        <!-- 项目根下面的脚本文件 copy 到根目录下 -->
        <fileSet>
            <directory>${basedir}/src/main/resource/package</directory>
            <outputDirectory></outputDirectory>
            <!-- 脚本文件在 linux 下的权限设为 755,无需 chmod 可直接运行 -->
            <fileMode>755</fileMode>
            <lineEnding>unix</lineEnding>
            <includes>
                <include>*.sh</include>
                <include>*.bat</include>
            </includes>
        </fileSet>

        <fileSet>
            <directory>${basedir}/WebContent/WEB-INF/lib</directory>
            <outputDirectory>WebContent/WEB-INF/lib</outputDirectory>
            <includes>
                <!--包含那些依赖-->
                <include>*.jar</include>
            </includes>
        </fileSet>
        <!-- 静态资源 -->
        <fileSet>
            <directory>${basedir}/WebContent</directory>
            <outputDirectory>WebContent</outputDirectory>
            <includes>
                <!--包含那些依赖-->
                <include>AFA_Management_Fonts/**</include>
                <include>compressor/**</include>
                <include>conf/**</include>
                <include>dependence/**</include>
                <include>elementui/**</include>
                <include>fonts/**</include>
                <include>icons/**</include>
                <include>image/**</include>
                <include>img/**</include>
                <include>module/**</include>
                <include>script/**</include>
                <include>*.js</include>
                <include>*.html</include>
                <include>*.css</include>
                <include>*.json</include>
                <include>WEB-INF/web.xml</include>
            </includes>
        </fileSet>


    </fileSets>

    <!-- 依赖的 jar 包 copy 到 lib 目录下 -->
    <dependencySets>
        <dependencySet>
            <outputDirectory>WebContent/WEB-INF/lib</outputDirectory>
        </dependencySet>
    </dependencySets>

</assembly>

src/main/resource/package/start.batsrc/main/resource/package/start.sh 分别对应Linux、window下的启动脚本

@echo off
setlocal & pushd

set MAIN_CLASS=awb.TomcatServer

set JAVA_OPTS=-Xms256m -Xmx2048m -Dfile.encoding=UTF-8

set APP_BASE_PATH=%~dp0
set CP=%APP_BASE_PATH%WebContent\WEB-INF\lib\*;%APP_BASE_PATH%WebContent\WEB-INF\classes

java -Xverify:none %JAVA_OPTS% -cp %CP% %MAIN_CLASS%
goto:eof

sh

#!/bin/bash
# ----------------------------------------------------------------------
#
# 使用说明:
# 1: 该脚本使用前需要首先修改 MAIN_CLASS 值,使其指向实际的启动类
#
# 2:使用命令行 ./start.sh start | stop | restart 可启动/关闭/重启项目
#
#
# 3: JAVA_OPTS 可传入标准的 java 命令行参数,例如 -Xms256m -Xmx2048m 这类常用参数
#
# 4: 函数 start() 给出了 4 种启动项目的命令行,根据注释中的提示自行选择合适的方式
#
# ----------------------------------------------------------------------

# 启动入口类,该脚本文件用于别的项目时要改这里
MAIN_CLASS=awb.TomcatServer

COMMAND="$1"


# Java 命令行参数,根据需要开启下面的配置,改成自己需要的
JAVA_OPTS="-Xms256m -Xmx2048m -Dfile.encoding=UTF-8"

# 生成 class path 值
APP_BASE_PATH=$(cd `dirname $0`; pwd)
CP=${APP_BASE_PATH}/WebContent/WEB-INF/lib/*:${APP_BASE_PATH}/WebContent/WEB-INF/classes

function start()
{
    # 运行为后台进程,并在控制台输出信息
    #java -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} &

    # 运行为后台进程,并且不在控制台输出信息
    # nohup java -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} >/dev/null 2>&1 &

    # 运行为后台进程,并且将信息输出到 output.log 文件
    nohup java -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} > output.out &

    # 运行为非后台进程,多用于开发阶段,快捷键 ctrl + c 可停止服务
    # java -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS}
}

function stop()
{
    # 支持集群部署
    kill `pgrep -f ${APP_BASE_PATH}` 2>/dev/null

    # kill 命令不使用 -9 参数时,会回调 onStop() 方法,确定不需要此回调建议使用 -9 参数
    # kill `pgrep -f ${MAIN_CLASS}` 2>/dev/null

    # 以下代码与上述代码等价
    # kill $(pgrep -f ${MAIN_CLASS}) 2>/dev/null
}

if [[ "$COMMAND" == "start" ]]; then
    start
elif [[ "$COMMAND" == "stop" ]]; then
    stop
else
    stop
    start
fi

awb.TomcatServer为启动类

启动类 TomcatServer

package awb;

import awb.operations.config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;

import java.io.File;

/**
 * @author lingkang
 * created by 2024/1/5
 */
@Slf4j
public class TomcatServer {
    public static void main(String[] args) throws Exception {
        log.info("服务启动中...");
        // 端口和上下文路路径
        int port = Integer.parseInt(GlobalConfig.PROP.getProperty("server.port", "8080"));
        String path = GlobalConfig.PROP.getProperty("server.context.path", "/afa");
        log.info("path={} , port={}", path, port);
        Tomcat tomcat = new Tomcat();
        tomcat.setHostname("0.0.0.0");
        // 端口监听
        Connector connector = tomcat.getConnector();
        connector.setPort(port);

        // WebContent 的名称要与打包的名称对上,使用当前路径
        String dir = System.getProperty("user.dir");
        log.info("dir : {}", dir);
        String WebContent = dir + File.separator + "WebContent";
        log.info("WebContent : {}", WebContent);
        tomcat.setBaseDir(WebContent);
        tomcat.addWebapp(path, WebContent);

        // 启动
        tomcat.start();

        // 服务连接
        tomcat.getService().addConnector(connector);
        log.info("web: http://localhost:" + port + path);
        tomcat.getServer().await();
    }
}

注意,上面的 GlobalConfig 是读取的一个配置文件,主要用于动态配置端口后访问上下文,可自定义或写死

项目结构是传统的servlet整合springmvc

image.png

打包

执行

mvn package

或者用idea的插件

image.png

输出如下:

image.png

window下双击 start.bat 启动

image.png

没毛病,能正常访问:http://localhost:8080/afa

还不影响xml等配置的修改

image.png

至此,自研国产web中间件完成。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容