第二弹:如何动态切换中间件(web容器)

0、场景说明

前几天,博主接到了迄今为止最为奇葩的一个需求,要求是在项目上线后,在不能改动任何原有代码(包括pom文件)的情况下,解决可以动态切换启动容器(就是tomcat、jetty等等)的问题,形式和方法不限(言外之意就是目前公司没人做过但是理论上应该可以,然后让你自己去琢磨),只能是jar包不能是war包,这个需求让原本只需要在pom文件改几行重新打包发布或者打个war包放在外置容器里启动的简单方式不复存在。

进入主题:为了能更有带入感,博主模拟一个场景,假如A是客户,B是开发人员,A啥也不懂,只有一个能简单操作电脑的运维,现在B把项目的jar包给了A,A的运维把项目部署在他们的服务器上然后java -jar 启动了,过了一段时间,A突然觉得tomcat不咋好用了,给他的运维说:你给我把这个web容器换成jetty,但是运维不会啊,pom文件已经打包进jar包了也没法改,现在呢运维就说是开发考虑的不全面,然后B做为乙方,就只能背锅优化了(B的心里一万匹***奔腾),所以要解决这个问题,就需要让A的运维在一些简单易懂的操作或不用操作的情况下将这个web容器给换为jetty。

好了,啰嗦了这么多,其实就一个目的,想让看到我本片文章的朋友们理解这个需求和需求背景,因为我也问过身边朋友,很多人不太理解这个需求。

1、梳理思路

首先,我们知道Spring boot(下面简称boot)是有自己内嵌的web容器,并且可以通过排除内嵌的容器,导入其他已经与boot做好适配的中间件依赖就可以做到切换容器启动,那么我们就需要了解以下几点:(1)、boot是如何将中间件的依赖注入到项目中的(boot自动化配置原理) (2)、boot加载容器的整体流程是怎样的(boot启动加载tomcat原理) 了解这两点后,我们就大概可以看出可以从哪入手去做这个需求了,上面的两点不了解的可自行百度,日后博主有时间也可能会发一篇自己的,要是发了会上链接。

思路1:从boot自动化配置可以假设如果可以将其他容器的依赖模仿自动化配置,原本项目是用内嵌的容器启动的,但是如果在项目启动进行自动化配置前加一层判断,判断是否除了原有的容器的依赖是否还有其他容器的依赖存在,如果有就用其他的,如果没有,就不做处理继续启动

思路2:boot在打包时会将项目依赖的jar位置写入classpath中,能否通过自定义classpath的指向来做到切换容器

2、实现过程

目前博主测试了第一种,理论上应该可以通过重写代码做到切换的,但是失败了,可能时逻辑上有问题,或者这个思路错了,所以我决定,先把第二种写下来,以防我日后忘记。
(博主将第一种方法的实现单独写了一篇文章–>https://blog.csdn.net/qq_51785096/article/details/127090376?spm=1001.2014.3001.5501)

首先,博主肝了一下加载boot加载容器流程的代码后发现EmbeddedWebServerFactoryCustomizerAutoConfiguration这个类是重点,不论是什么容器,都需要经过这个类去创建容器的Bean,因为代码很长,下方以tomcat为例
在这里插入图片描述

//解释一下上面几个注解(从上往下)
//该类为自动注入的类
@AutoConfiguration
//该类只有在项目为web项目时才会生效
@ConditionalOnWebApplication
//让被 @ConfigurationProperties 注解的类生效。
@EnableConfigurationProperties(ServerProperties.class)


//发现Tomcat.class和UpgradeProtocol.class的类时,该类生效(!!!重点)
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })

由此可见,boot判断需要创建哪个类的Bean时,是根据扫描到的容器依赖中的某几个类去判断的,也就是说,如果我们的容器已经适配了boot,那么完全可以通过替换已经打好jar包的项目中容器的依赖包去骗过这层代码,从而实现切换。

我们在打包时,可以通过maven提供的插件去选择jar包或是war包,但是项目所需的依赖和项目是在同一个jar包中的,这样就无法实现替换依赖包了。

不过,天无绝人之路,博主在度娘的帮助下成功发现maven同样也提供了可以将项目所需的所有依赖和可执行项目的jar包分开打包的插件,我们将他们分别打包,在需要切换容器时,把项目停下来,将依赖所在文件夹中的容器依赖包换成我们想换的容器的依赖,理论上在boot在重启项目,再次扫描依赖时判断一下几个可证明容器身份的类,就会为容器创建相对应的Bean,这样就成功切换了。

好了 分析需要做的事情之后,直接上代码

2.0、前期准备

首先我们需要一个Spring boot的项目

其次项目中包含一个测试用的简单的接口,如图
在这里插入图片描述

2.1、下面的代码是开启依赖的热部署以及将依赖包和项目的可执行jar包分离且输出至指定位置
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <!--使热部署的devtools生效-->
            <configuration>
                <fork>true</fork>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
                <layout>ZIP</layout>
                <includes>
                    <include>
                        <groupId>non-exists</groupId>
                        <artifactId>non-exists</artifactId>
                    </include>
                </includes>
            </configuration>
        </plugin>
        <!--拷贝第三方依赖文件到指定目录-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.8</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <!--target/libs是依赖jar包的输出目录,根据自己喜好配置-->
                        <outputDirectory>target/libs</outputDirectory>
                        <excludeTransitive>false</excludeTransitive>
                        <stripVersion>false</stripVersion>
                        <includeScope>runtime</includeScope>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
2.2、排除掉内嵌的tomcat
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
2.3、找出启动容器的依赖(演示tomcat和jetty的切换)

首先我们要知道,pom文件中使用的boot的启动依赖stater,这个只是boot将该boot版本需要的该依赖版本统一了而已,所以spring-boot-stater-tomcat的依赖包对于目前的操作没有用
在这里插入图片描述

我们以tomcat中间件为例,先将中间件的依赖在pom文件中导入,然后运行项目进行测试,没有问题后,开始打包,打包完成后我们target目录中出现项目的可执行jar包及libs的文件夹
在这里插入图片描述

pom文件配置如下

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--排除内嵌的tomcat-->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--tomcat的启动依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>

    <!--Test依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

打包前务必先在idea里面测试项目是否可以成功运行没有问题后再进行下面的操作

在target目录输入cmd进行测试

java -Dloader.path=(libs文件夹所在全路径),resources,lib -jar ***.jar

如图启动成功
在这里插入图片描述
我们将此时的libs文件夹拷贝一份,在外建一个tomcat的文件夹存入,现在的libs中就是与项目适配成功的依赖,并且是以tomcat中间件启动

随后我们将pom文件中tomcat的依赖全部删除,换为jetty的依赖

pom文件配置如下

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--排除内嵌的tomcat-->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--jetty依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>

    <!--Test依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

打包前务必先在idea里面测试项目是否可以成功运行没有问题后再进行下面的操作

我们重新打包,打包及测试与示例的方法一样(注:记得要关闭上次命令窗口测试时正在运行的项目(ctrl + c)一次不行就多按几次、关闭命令窗口以及在Idea中clean一次,不然打包后的libs文件夹中还是会有之前tomcat的依赖)

在tomcat和jetty的命令窗口都测试成功后

我们现在只将内嵌的tomcat排除掉,不添加任何中间件的依赖

pom文件配置如下

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!--排除内嵌的tomcat-->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--Test依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

和之前的操作一样,idea测试,测试成功后重新打包(此次不一样的地方在于没有中间件就不会出现启动容器成功的日志,如下图即为成功)

在这里插入图片描述
cmd窗口测试

在这里插入图片描述
与idea控制台输出的一样,即为成功

不要关闭命令窗口,往下看

2.4、测试动态切换中间件

先测试tomcat

java -Dloader.path=(tomcat的libs文件夹所在全路径),resources,lib -jar ***.jar

在这里插入图片描述

根据日志可观察到已经使用tomcat中间件启动成功

将项目停下来,再测试Jetty

java -Dloader.path=(jetty的libs文件夹所在全路径),resources,lib -jar ***.jar

在这里插入图片描述
根据日志可观察到已经使用Jetty中间件启动成功

3、写在最后

到这里动态切换中间件的方法说明结束,理论上其他已经与spring boot适配好的中间件都可以这样操作,后续博主可能会出一期操作教程发在哪到时候再看,发出来后会将链接更新在本篇文章中。

最后说明,创作不易,若转载请标明出处或原文链接!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式数据库架构是指在多个数据库之间分配和存储数据的一种架构方式。它将数据分散存储在多个节点上,以提高系统的可扩展性、可用性和性能。 Mycat是一种开源的分布式数据库中间件,它基于MySQL实现分布式数据库功能。它具有负载均衡、数据分片和数据复制等特性,能够有效地分配和管理数据。它还提供了分布式事务的支持,保证了数据的一致性和可靠性。 在企业实践中,分布式数据库架构和Mycat中间件被广泛应用于大规模业务系统中。首先,它能够解决单点故障问题,提高系统的可用性。将数据分散存储在多个节点上,当某个节点发生故障时,其他节点可以继续提供服务,保证系统的正常运行。 其次,分布式数据库架构和Mycat中间件能够提高系统的性能。通过数据分片和负载均衡的技术,可以将负载均匀地分散到多个节点上,避免单个节点的资源瓶颈问题,提高系统的处理能力和响应速度。 此外,分布式数据库架构还能够实现数据的性扩展。当业务量增加时,可以根据需要新增节点,实现系统的水平扩展。同时,通过数据复制技术,可以提供数据的冗余存储,保证数据的安全性和完整性。 总的来说,分布式数据库架构和Mycat中间件为企业提供了一种可靠、高性能的数据存储和管理方案。它能够适应大规模业务系统的需求,提供可伸缩性和性扩展能力,成为企业在数据管理方面的重要工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值