轻量级仿 SpringBoot=嵌入式 Tomcat+SpringMVC

news2024/9/20 18:41:46

SpringBoot 嵌入了 Web 容器如 Tomcat/Jetty/Undertow,——这是怎么做到的?我们以 Tomcat 为例子,尝试调用嵌入式 Tomcat。

为了说明如何打造轻量级的 SpringBoot,本文分为“嵌入式 Tomcat”、“增强 SpringMVC”和“打包/部署”三个小节来介绍。

嵌入式 Tomcat

调用嵌入式 Tomcat,如果按照默认去启动,一个 main 函数就可以了。

简单的例子

下面是启动 Tomcat 的一个例子。

Tomcat tomcat = new Tomcat();
tomcat.enableNaming();
tomcat.getHost().setAutoDeploy(false);
tomcat.getHost().setAppBase("webapp");
// 在对应的 host 下面创建一个 context 并制定他的工作路径,会加载该目录下的所有 class 文件,或者静态文件
//        tomcat.setBaseDir(Thread.currentThread().getContextClassLoader().getResource("").getPath()); // 设置 tomcat 启动后的工作目录
//        System.out.println(Thread.currentThread().getContextClassLoader().getResource("").getPath());

// 读取项目路径
System.out.println(System.getProperty("user.dir"));
String jspDir = System.getProperty("user.dir");
StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(jspDir).getAbsolutePath());
ctx.setReloadable(false);// 禁止重新载入
WebResourceRoot resources = new StandardRoot(ctx);// 创建WebRoot
resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", new File("target/classes").getAbsolutePath(), "/"));// tomcat 内部读取 Class 执行

// 创建连接器,并且添加对应的连接器,同时连接器指定端口 设置 IO 协议
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(port);
connector.setThrowOnFailure(true);

tomcat.getService().addConnector(connector);// 只能设置一个 service,直接拿默认的
tomcat.setConnector(connector); // 设置执行器

try {
	tomcat.start(); // tomcat 启动
} catch (LifecycleException e) {
	throw new RuntimeException(e);
}

tomcat.getServer().await(); // 保持主线程不退出,让其阻塞,不让当前线程结束,等待处理请求

增强 SpringMVC

把应用原来的 src/main/webapp/WEB-INF,移动到 src/main/resources/WEB-INF下,把在src/main/webapp下面的所有文件,移动到 src/main/META-INF/resources 目录下。

打包与部署

Maven 打包

我们希望打出哪个环境的包,就只需要包含这个环境的配置文件即可,不想包含其他环境的配置文件,这时候可以直接在 maven 中使用 profiles 和 resources 来配置,打包时使用mvn package -P dev即可。

<profiles>
    <!--开发环境-->
    <profile>
        <id>dev</id>
        <properties>
            <spring.profiles.active>dev</spring.profiles.active>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <!--测试环境-->
    <profile>
        <id>test</id>
        <properties>
            <spring.profiles.active>test</spring.profiles.active>
        </properties>
    </profile>
    <!--生产环境-->
    <profile>
        <id>prod</id>
        <properties>
            <spring.profiles.active>prod</spring.profiles.active>
        </properties>
    </profile>
</profiles>
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources.${spring.profiles.active}</directory>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

原理如下:

maven 在构建项目时,默认是把main/resoures目录作为资源文件所在目录的,现在我们在main/conf目录下也存放了资源文件(即application.properites文件),因此需要告诉 maven 资源文件所在的目录有哪些,通过 build 元素中增加 resources 元素就可以达到这一目的。这里告诉 maven 有两个地方存在资源文件,一个是默认的 resources 目录,另一个是在src/main/conf/${env}目录下,而${env}引用的是上面 properties 元素中定义的 env 的值,而它的值引用的又是spring.profiles.active的值(其值为 dev、test 和 online 中的一个),因此,目录要么是src/main/conf/dev,要么是src/main/conf/test,要么是main/conf/online,这最终取决于参数spring.profiles.active的值。因此,根据参数spring.profiles.active的值的不同,在构建打包时最终会选择 dev、test 和 online 这三个目录中的一个中的application.properties打包到项目中来。

将应用打成一个 fat jar 的方式,可以用 Spring 的:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>1.3.3.RELEASE</version>
  <configuration>
    <mainClass>com.demo.proj.Main</mainClass>
  </configuration>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>repackage</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Profiles

在实际使用环境中,我们同一个应用环境可能需要在不同环境运行(开发、测试、生产等),每个环境的参数都有可能不同(连接参数、日志级别等),使用 Profiles 可以将不同环境下的参数进行拆分,并指定加载。

IDEA 配置,在 src 目录下创建 profiles 目录,安排如下图的配置文件。

在这里插入图片描述
然后 Maven Profile 打勾即可。

在这里插入图片描述

启动参数

开始以为要 run 配置中加入--spring.profiles.active=dev参数,其实不用,还是在 IDEA 里面选 profile 打勾即可。

小结

啥?Spring Boot 不用?——对。就只是使用 Spring MVC,而不用 Boot。为啥?——Boot 太重了:)

这是反智吗?Spring Boot 好好的就只是因为太重就不用?——请允许我跟你说,MVC 几乎能做到 Boot 的事情,而且它更轻量级,何乐不为呢?Yes,让我们试试:Spring Framework without Spring Boot!

参考

  • SpringMVC 纯注解配置
  • 仿SpringBoot的启动方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1132807.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LDO基础知识

LDO基础知识 线性稳压器基本上由输入IN、输出OUT、GND引脚所构成 可变线性稳压器则在输出增加输出电压的反馈&#xff08;feed back&#xff09;引脚 (通过分压电阻来进行调节输出电压的大小) LDO 线性稳压器内部电路如下图所示。 基本上由误差放大器&#xff08;误差检测用…

行情分析——加密货币市场大盘走势(10.25)

目前大饼继续上涨&#xff0c;还没有看到震荡盘整的迹象。从MACD日线来看&#xff0c;连续绿色实心柱已经10天。现在有点上涨无力了&#xff0c;而现在入场做空性价比更高&#xff0c;看反弹到33000-32000。如果谨慎点&#xff0c;可以继续等待。 以太目前来看和大饼一样那个也…

MySQL中的Base64函数

编码函数to_base64() select to_base64("123") 解码函数from_base64() select from_base64("MTIz")

leetcode:1662. 检查两个字符串数组是否相等(python3解法)

难度&#xff1a;简单 给你两个字符串数组 word1 和 word2 。如果两个数组表示的字符串相同&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 数组表示的字符串 是由数组中的所有元素 按顺序 连接形成的字符串。 示例 1&#xff1a; 输入&#xff1a;word1 […

AMS启动流程

本文均采用Android 14代码进行讲解&#xff0c;学习可以使用以下地址&#xff1a;Search 一、AMS启动流程 AMS的启动是在SyetemServer进程中启动的&#xff0c;从SyetemServer的main方法开始进入&#xff1a; 1.SystemServer.java main(String[] args) /*** The main entr…

Qt篇——子控件QLayoutItem与实际控件的强转

方法&#xff1a;使用qobject_cast<QLabel*>() &#xff0c;将通过itemAt(i)获取到的子控件(QLayoutItem)强转为子控件的实际类型(如QLineEdit、QLabel等)。 场景举例&#xff1a; QLabel *label qobject_cast<QLabel*>(ui->horizontalLayout_40->itemAt(0…

c#使用ExifLib库提取图像的相机型号、光圈、快门、iso、曝光时间、焦距信息等EXIF信息

近期公司组织了书画摄影比赛&#xff0c;本人作为摄影爱好者&#xff0c;平时也会拍些照片&#xff0c;这次比赛当然不能错过。为了提高获奖概率&#xff0c;选了19张图像作为参赛作品。但是&#xff0c;摄影作品要提交图像的光圈、曝光时间等参数。一两张还可以通过电脑自带软…

1024程序员节获奖名单公示~恭喜各位上榜同学

1024程序员节完美收官&#xff01; 恭喜各个分会场中奖的小伙伴~我们已于昨日的线下会场完成奖品及证书发放&#xff01; 更多优秀作品欢迎大家点击查看&#xff1a;卡奥斯开源社区 — 打造工业互联网顶级开源社区 颁奖典礼精彩回放&#xff1a;卡奥斯开源社区 — 打造工业互…

【ARM Coresight 系列文章 3.3 - ARM Coresight SWD 协议详细介绍】

文章目录 1.1 SWD 协议框图1.2 读/写时序及命令1.2.1 SWD 时序1.2.2 SWD 命令详情1.3 芯片探测1.3.1 获取芯片 ID1.4 读/写操作1.1 SWD 协议框图 SWD协议可以配置SoC内部几乎所有的寄存器。时钟信号由SWCLK 管脚输入,数据信号从SWDIO管脚输入输出。首先 HOST 对SW-DP 进行操作…

基于html5+javascript技术开发的房贷利率计算器

房贷计算器是一款专为购房者设计的实用工具应用&#xff0c;其主要功能是帮助用户详细计算房贷的还款金额、利息以及还款计划等。通过这款软件&#xff0c;用户可以更加便捷地了解到自己的还款情况和计划&#xff0c;从而更好地规划自己的财务。下面将对房贷计算器进行详细的介…

基于PHP的图像分享社交平台

有需要请加文章底部Q哦 可远程调试 基于PHP的图像分享社交平台 一 介绍 此图像分享社交平台基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。平台角色分为用户和管理员。用户可注册登录&#xff0c;发布图像&#xff0c;修改个人信息&#xff0c;评论图像…

家电翻页电子画册制作秘籍,轻松打造炫酷电子书!

在家电市场上&#xff0c;翻页电子画册已经成为了越来越多人的选择。它不仅具有传统纸质画册的优点&#xff0c;还具有更多的功能和特点&#xff0c;如翻页动画、音效等&#xff0c;让阅读变得更加有趣和生动。那么&#xff0c;如何制作一款炫酷的电子画册呢&#xff1f;今天就…

国产 87235系列USB平均功率探头

频率范围覆盖 功率测量准确度&#xff1a;0.2dB 10MHz&#xff5e;50GHz 87235系列 USB平均功率探头是一款基于USB 2.0接口的二极管检波式高精度、大动态范围平均功率测量仪器&#xff0c;可实现各种格式信号平均功率的准确测量。87235系列平均功率探头频率范围覆盖10MHz&am…

Spring Boot整合OAuth2实现GitHub第三方登录

Spring Boot整合OAuth2&#xff0c;实现GitHub第三方登录 1、第三方登录原理 第三方登录的原理是借助OAuth授权来实现&#xff0c;首先用户先向客户端提供第三方网站的数据证明自己的身份获取授权码&#xff0c;然后客户端拿着授权码与授权服务器建立连接获得一个Access Token…

【Note】链式存储结构

设计不同的结点结构&#xff0c;可以构成不同的链式存储结构。常用的有&#xff1a;二叉链表、三叉链表、线索链表&#xff08;用空链域存放指向前驱或后继的线索&#xff09;。 二叉链表存储 VS 一般二叉树 二叉链表 VS 二叉树 知识点&#xff1a; 一个二叉链表由根指针root…

2022年06月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 在Python编辑器中写好程序代码后&#xff0c;在Run菜单中&#xff0c;下列哪个命令可以用来执行程序&#xff1f;&…

消费大变革时代,三只松鼠的“高端性价比”如何突围制胜?

在浙江1天连开37家社区零食店&#xff0c;三只松鼠正在苏醒。 “三只松鼠去年是重创&#xff0c;可以讲是壮士断腕。”三只松鼠&#xff08;300783.SZ&#xff09;创始人、CEO章燎原在9月底接受红星资本局专访时总结。 过去几年&#xff0c;章燎原几乎没有接受过媒体采访。而…

计算机基础知识39

外键 外键字段>>>:部门编号 其实就是用来标识表与表之间的数据关系 # 简单的理解为该字段可以让你去到其他表中查找数据 表与表之间的关系 # 一对多、多对多、一对一、没有关系 ### 一对多的表关系&#xff1a; 员工表&#xff1a;一个员工一个部门 x …

如何使用 Pinia ORM 管理 Vue 中的状态

状态管理是构建任何Web应用程序的重要组成部分。虽然Vue提供了管理简单状态的技术&#xff0c;但随着应用程序复杂性的增加&#xff0c;处理状态可能变得更具挑战性。这就是为什么像Pinia这样的库被创建出来&#xff0c;以增强Vue的基本状态管理能力。然而&#xff0c;在大型应…

uni-app中tab选项卡的实现效果 @click=“clickTab(‘sell‘)“事件可传参数

一、效果图 二、代码 <template><view><view class"choose-tab"><view class"choose-tab-item" :class"chooseTab 0 ? active : " data-choose"0" click"clickTab">选项1</view><view …