当前位置: 首页 > news >正文

自定义maven插件,在项目中命令启动springboot并加载当前项目资源

背景

最近在制定团队内公用的基础框架,基于单应用多module的架构思路,使用maven管理项目依赖,在项目中定义了一个springboot模块,该模块依赖具体的业务实现模块,启动后通过扫描路径下的类加载服务,业务开发同事只需要开发具体业务模块即可。

但是在项目管理时,不期望业务开发同事关心和修改基础框架。最开始的做法是让业务开发同事在项目的module管理模块下新建业务module模块(见下描述),在不同分支开发不同的业务,开发自测的时候,需要在springboot模块中依赖具体业务module并启动。

gm-admin --------------------------------管理后台(springboot)服务,依赖gm-modules中的具体实现       
gm-common--gm-common-core ----------------------基础包,含最基础的基类、工具类、异常类等--gm-common-log  ----------------------日志实现包,通过注解,记录web调用参数和结果  --gm-common-ratelimit -----------------限流器实现,若需对用户进行限制则需要依赖gm-common-security模块     --gm-common-redis ---------------------redis缓存依赖和分布式锁工具类--gm-common-security ------------------基础安全模块,校验和设置用户信息、权限--gm-common-sftp ----------------------sftp工具 --gm-common-storage -------------------对象存储实现,目前支持本地存储和腾讯oss
gm-framework ----------------------------框架模块,主要实现数据源注入等
gm-gateway ------------------------------网关服务,实现报文加解密、限流、路由等
gm-modules--gm-mall -----------------------------商城模块--gm-partner --------------------------合伙人项目使用,非商城内容--gm-system ---------------------------系统管理模块,实现系统用户、角色、权限、菜单、机构等业务逻辑--gm-third ----------------------------第三方服务模块,实现对第三方服务的调用,如短信、积分--gm-wechat ---------------------------微信模块,实现微信用户授权、生成小程序码等与微信交互逻辑

这样的开发模式导致业务开发的同事实际上需要在“框架项目”中进行业务开发,虽然采用了module进行划分,但是在开发中遇到问题总会尝试或者难免会对框架代码进行修改、优化,最终导致冲突等问题。而我想达到的效果是“框架代码”对业务开发同事尽量透明,类似于之前使用dapeng soa框架开发应用时一样,不需要关心容器是怎么跑起来的,只需要关心本业务自身的业务和依赖。

大体思路是:开发一个自定义maven插件,将业务代码在单独的项目中进行开发,需要启动项目时,在项目目录下执行mvn命令,执行maven插件,这个插件会将当前项目的(类)资源和依赖的依赖包添加到类加载器,并启动springboot项目,实现在springboot项目启动当前项目的目的。

实现

具体代码步骤如下供参考:

Maven插件项目pom配置:

<packaging>maven-plugin</packaging>
<name>gm-maven-plugin</name><dependencies>...<!-- SpringBoot容器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.5.10</version></dependency><dependency><groupId>org.apache.maven</groupId><artifactId>maven-core</artifactId><version>3.5.2</version><scope>provided</scope></dependency><dependency><groupId>org.apache.maven</groupId><artifactId>maven-plugin-api</artifactId><version>3.5.2</version></dependency><dependency><groupId>org.apache.maven.plugin-tools</groupId><artifactId>maven-plugin-annotations</artifactId><version>3.5.2</version><scope>provided</scope></dependency><dependency><groupId>org.apache.maven</groupId><artifactId>maven-project</artifactId><version>2.2.1</version></dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-plugin-plugin</artifactId><version>3.5</version></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.6.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins>
</build>
</dependencies>

关键代码:

@Mojo(name = "run", threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST)
public class GmMavenPlugin extends AbstractMojo {
/*** 获取项目编译环境类路径*/
@Parameter(defaultValue = "${project}", readonly = true)
protected MavenProject project;@Overridepublic void execute() throws MojoExecutionException {try {// 获取应用程序的 classpathList<String> classpathElements = project.getRuntimeClasspathElements();URL[] urls = new URL[classpathElements.size()];for (int i = 0; i < classpathElements.size(); i++) {urls[i] = new File(classpathElements.get(i)).toURI().toURL();System.out.println("URL: " + urls[i]);}//            // 创建一个新的 ClassLoaderClassLoader classLoader = URLClassLoader.newInstance(urls, Thread.currentThread().getContextClassLoader());Class<?> applicationClass = classLoader.loadClass("com......GmAdminApplication");SpringApplication application = new SpringApplication(applicationClass);application.setResourceLoader(new DefaultResourceLoader(classLoader));application.setMainApplicationClass(applicationClass);application.run();// 挂起当前线程Thread.currentThread().join();} catch (Exception e) {throw new MojoExecutionException("Failed to start Spring Boot application", e);}}
...

编写完成后将该插件install到本地仓库(或推送到远端私库)。
新建一个业务项目,完成业务代码的开发和编译,如下:

@RestController
@RequestMapping("/tracking")
public class TrackingController {private static final Logger logger = LoggerFactory.getLogger(TrackingController.class);@PostConstructpublic void postConstruct() {logger.info("--------------------------------------------");logger.info("Tracking模块控制器被加载...");logger.info("--------------------------------------------");}
...

然后在项目目录下执行maven命令

mvn compile com.dt26:gm-maven-plugin:2.0.0-SNAPSHOT:run

项目即在springboot容器中启动,并可以看到日志如下:

...
[INFO] --------------------------------------------
[INFO] Tracking 模块控制器被加载...
[INFO] --------------------------------------------
[INFO] Exposing 1 endpoint(s) beneath base path '/actuator'
[INFO] Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
[INFO] Will not secure any request
[INFO] Starting ProtocolHandler ["http-nio-8080"]
[INFO] Tomcat started on port(s): 8080 (http) with context path '/admin'
...

整体的需求就算满足了,剩下就是优化代码使得更优雅。当前只能实现开发时启动项目,在实际打包发布到测试环境和生产时,仍然需要gm-admin项目中引入业务代码模块并打包成可执行包。这一步后续可以考虑使用maven命令等方式自动完成。

参考:https://www.cnblogs.com/coder-chi/p/11305498.html

相关文章:

自定义maven插件,在项目中命令启动springboot并加载当前项目资源

背景 最近在制定团队内公用的基础框架&#xff0c;基于单应用多module的架构思路&#xff0c;使用maven管理项目依赖&#xff0c;在项目中定义了一个springboot模块&#xff0c;该模块依赖具体的业务实现模块&#xff0c;启动后通过扫描路径下的类加载服务&#xff0c;业务开发…...

Linux系统【Centos7】更新内核更新软件详细教程

更新内核&#xff1a; 1. 打开终端&#xff0c;输入命令 sudo yum update&#xff0c;等待更新完成。 2. 重启系统&#xff0c;输入命令 sudo reboot。 3. 在 GRUB 引导界面&#xff0c;选择最新的内核版本&#xff0c;按下回车键进入系统。 4. 在终端中输入命令 uname -r&…...

C++ 中new/delete与malloc/free详解

文章目录前言一、new/delete1. 序言2. 使用方法2.1. new 和 delete 基本语法2.2. new 和 delete 的底层实现原理3. 底层原理3.1. operator new 和 operator delete3.2. new 和 delete 的底层实现原理4. 注意事项5. 总结二、malloc/free1. 序言2. 使用方法2.1. malloc 和 free 基…...

crm软件哪个好?该如何选择?

crm软件哪个好&#xff1f;该如何选择&#xff1f; 首先我们需要明确一下什么是好的CRM系统&#xff0c;优质的CRM系统应该具备以下优势&#xff1a; 1&#xff09;提高销售效率&#xff1a;通过CRM系统&#xff0c;销售人员可以跟踪客户互动历史和交易记录&#xff0c;了解客…...

蓝桥杯第22天(Python)(疯狂刷题第5天)

题型&#xff1a; 1.思维题/杂题&#xff1a;数学公式&#xff0c;分析题意&#xff0c;找规律 2.BFS/DFS&#xff1a;广搜&#xff08;递归实现&#xff09;&#xff0c;深搜&#xff08;deque实现&#xff09; 3.简单数论&#xff1a;模&#xff0c;素数&#xff08;只需要…...

软件测试面试常问的问题有哪些?

互联发展是很快的&#xff0c;每年都会有新语言的诞生。 我干测试已经三年了&#xff0c;主要负责web功能测试&#xff0c;java编写接口自动化&#xff0c;APP功能测试&#xff0c;APP 接口自动化&#xff08;也是用的java&#xff09;&#xff0c;面过得测试也差不多30个&…...

js之文件信息读取篇高级基础

文章目录js之文件信息读取&#xff08;FileReader&#xff09;获取文件相关信息的两种方式js原生拖拽事件js之文件信息读取&#xff08;FileReader&#xff09; 首先这里面会讲一些知识点 bolb 对象FileReader对象 let blob new Blob([heewwekgewgwer], { type: text/plain …...

SQL Server的死锁说明

死锁指南一、了解死锁二、检测并结束死锁2.1、可能死锁的资源三、处理死锁四、最大限度地减少死锁4.1、以相同的顺序访问对象4.2、避免事务中的用户交互4.3、保持交易简短且在一个批次中4.4、使用较低的隔离级别4.5、使用基于行版本控制的隔离级别4.6、使用绑定连接4.7、停止事…...

关于#define的一些小知识

目录 一&#xff0c;#define的声明格式&#xff1a; 二&#xff0c;#define宏的作用是为了完成替换 #define的替换规则&#xff1a; 三&#xff0c;#define使用时常犯的错误 四&#xff0c;宏与函数的比较 4.1&#xff0c;什么时候使用宏&#xff1f; 4.1&#xff0c;…...

rabbitmq普通集群与镜像集群搭建

1.准备三台centos7主机&#xff0c;并关闭防火墙与selinux 2.安装rabbitmq环境必备的Erlang(以下所有操作三台主机均需要执行) 执行以下命令下载配置erlang yum源 curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash使用yum命…...

session和jwt哪个更好

session和jwtsession优点缺点jwt优点缺点总结session 优点 原理简单&#xff0c;易于学习。用户信息存储在服务端&#xff0c;可以快速封禁某个用户。 缺点 占用服务端内存&#xff0c;硬件成本高。多进程&#xff0c;多服务器时&#xff0c;不好同步-需要使用第三方缓存&a…...

基于TPU-MLIR实现UNet模型部署-决赛答辩02

队伍&#xff1a;AP0200023 目录 初赛 一、 模型导出优化 1.1 直接倒出原始模型并转换 1.2 导出模型前处理 1.2.1 导出Resize 1.2.2 导出归一化 1.3导出模型后处理 1.3.1导出 Resize 与 1.3.2导出 ArgMaxout 1.3.3导出特征转RGB 复赛 一、 确定baseline 二、优化模…...

Maven高级-分模块开发依赖管理

Maven高级-分模块开发&依赖管理1&#xff0c;分模块开发1.1 分模块开发设计1.2 分模块开发实现1.2.1 环境准备1.2.2 抽取domain层步骤1:创建新模块步骤2:项目中创建domain包步骤3:删除原项目中的domain包步骤4:建立依赖关系步骤5:编译maven_02_ssm项目步骤6:将项目安装本地…...

《安富莱嵌入式周报》第308期:开源带软硬件安全认证的PLC设计,开源功率计,可靠PID实现,PR2机器人设计文件全开源,智能手表设计WASP-OS

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1F24y157QE 《安富莱嵌入式周报》第308期&#xff1a;开源带软…...

代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结

583. 两个字符串的删除操作 动规五部曲 1、确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;以i-1为结尾的字符串word1&#xff0c;和以j-1位结尾的字符串word2&#xff0c;想要达到相等&#xff0c;所需要删除元素的最少次数。 2、确定递推…...

Sip协议

简介 SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始协议&#xff09;是一个用于建立、更改和终止多媒体会话的应用 层控制协议&#xff0c;其中的会话可以是 IP 电话、多媒体会话或多媒体会议。SIP 是 IETF 多媒体数据和控 制体系结构的核心协议&#xff0…...

RandomAccessFile类 断点续传

文章目录学习链接RandomAccessFile构造方法实现的接口DataOutputDataInputAutoCloseable重要的方法多线程读写同一个文件&#xff08;多线程复制文件&#xff09;代码1代码2断点续传FileUtils学习链接 RandomAccessFile详解 Java IO——RandomAccessFile类详解 java多线程-断点…...

SpringCloud微服务技术栈的注册中心Eureka

文章目录SpringCloud微服务技术栈的注册中心Eureka简介Eureka特点操作步骤环境准备创建Eureka Server注册服务提供方调用服务消费方总结SpringCloud微服务技术栈的注册中心Eureka 简介 在微服务架构中&#xff0c;服务的数量庞大&#xff0c;而且每个服务可能会有多个实例。此…...

Unity最新热更新框架 hybridclr_addressable

GitHub:YMoonRiver/hybridclr_addressable: 开箱即用的商业游戏框架&#xff0c;集成了主流的开发工具。将主流的GameFramework修改&#xff0c;支持Addressable和AssetBundle&#xff0c;已完善打包工具和流程。 (github.com) # 新增GameFramework Addressables 开箱即用 # 新…...

【c语言】一维数组***特性、存储原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...