Springboot集成jersey打包jar找不到class处理
环境 java17 + springboot 3.x
如题,简单来说,jersey官方希望用户通过 register 的方式,将所有的资源类注册到jersey中,但是,一般开发中,可能定义了N个Resource类,一个一个的加入,太麻烦,也可能遗漏,解决方案就是,写个方法,扫描到resource包下的所有资源类,然后 register 到jersey中
特别注意,是 registerClasses 方法,不是 register 方法
以下两种方法
- 使用java自带的扫描
1.1 核心代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.util.ClassUtils;import java.io.IOException;
import java.util.HashSet;
import java.util.Set;@Slf4j
public class ClassUtil {/*** 由于spring boot 打包为jar包,jersey packages 无法扫描jar对应的文件夹的文件,故自定义包扫描** @return class[]*/public static Set<Class<?>> findAllClasses(String... scanPackages) {Set<Class<?>> classes = new HashSet<>();for (String scanPackage : scanPackages) {ClassLoader loader = ClassUtil.class.getClassLoader();Resource[] resources = new Resource[0];try {resources = scan(loader, scanPackage);} catch (IOException e) {log.error("加载class异常", e);}classes.addAll(convert(loader, resources));}return classes;}/*** 扫描 jar 包** @param loader ClassLoader* @param packageName packageName*/private static Resource[] scan(ClassLoader loader, String packageName) throws IOException {ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(loader);String pattern = "classpath*:" + ClassUtils.convertClassNameToResourcePath(packageName) + "/*.class";return resolver.getResources(pattern);}/*** 加载 class** @param loader ClassLoader* @param resource resource*/private static Class<?> loadClass(ClassLoader loader, Resource resource) {try {CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(loader);MetadataReader reader = metadataReaderFactory.getMetadataReader(resource);return ClassUtils.forName(reader.getClassMetadata().getClassName(), loader);} catch (LinkageError | ClassNotFoundException e) {if (log.isDebugEnabled()) {log.debug("Ignoring candidate class resource " + resource + " due to " + e);}return null;} catch (Throwable e) {if (log.isWarnEnabled()) {log.warn("Unexpected failure when loading class resource " + resource, e);}return null;}}/*** resources 转换为 Set<Class>** @param loader ClassLoader* @param resources Resource*/private static Set<Class<?>> convert(ClassLoader loader, Resource[] resources) {Set<Class<?>> classSet = new HashSet<>(resources.length);for (Resource resource : resources) {Class<?> clazz = loadClass(loader, resource);if (clazz != null) {classSet.add(clazz);}}return classSet;}}
1.2 使用
@Configuration
public class JerseyConfig extends ResourceConfig {public JerseyConfig() {// 注册包扫描 这个方法在开发使用没问题,但是打包jar后,找不到 class 文件
// packages("com.xxx.xxx.api");// 定义扫描包含接口资源包registerClasses(ClassUtil.findAllClasses("com.xxx.xxx.api"));}
}
- 使用JerseyScan
2.1 核心代码
注意中间的 scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class)); 这一行代码!!!
public class JerseyServiceAutoScanner {private JerseyServiceAutoScanner() {}public static Class[] getPublishJerseyServiceClasses(ApplicationContext context, String... scanPackages) {// 传入applicationContext对象,在整个spring容器中捞我们需要的controller// 传入的第二个参数是可变参数,字符串,用于传入需要扫描的包路径List<Class> jerseyServiceClasses = new ArrayList<>();if (scanPackages == null || scanPackages.length == 0) {return jerseyServiceClasses.toArray(new Class[jerseyServiceClasses.size()]);}ClassPathScanningCandidateComponentProvider scanner = new JerseyScanningComponentProvider(false);// 我只需要扫描使用了@Path注解的controller,如果还有其他的组合条件,可以在这里增加scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class));for (var scanPackage : scanPackages) {jerseyServiceClasses.addAll(scanner.findCandidateComponents(scanPackage).stream().map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), applicationContext.getClassLoader())).collect(Collectors.toSet()));}// 返回符合条件的spring容器中的全部的类对象return jerseyServiceClasses.toArray(new Class[jerseyServiceClasses.size()]);}private static class JerseyScanningComponentProvider extends ClassPathScanningCandidateComponentProvider {public JerseyScanningComponentProvider(boolean useDefaultFilters) {super(useDefaultFilters);}@Overrideprotected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {AnnotationMetadata metadata = beanDefinition.getMetadata();// 注意这里的值,最好debug一下,我使用的时候,只有第一个metadata.isIndependent()是truereturn (metadata.isIndependent() && metadata.isAbstract() && !beanDefinition.getMetadata().isAnnotation());}}
}
2.2 引用
@Configuration
public class JerseyConfig extends ResourceConfig implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@PostConstructpublic void init() {registerClasses(JerseyServiceAutoScanner.getPublishJerseyServiceClasses(applicationContext, "com.xxx.xxx.api"));}public JerseyConfig() {// 。。。 其他的 。。。}
}
完结!!!
相关文章:
Springboot集成jersey打包jar找不到class处理
环境 java17 springboot 3.x 如题,简单来说,jersey官方希望用户通过 register 的方式,将所有的资源类注册到jersey中,但是,一般开发中,可能定义了N个Resource类,一个一个的加入,太…...

基于springboot和vue的旅游资源网站的设计与实现
环境以及简介 基于vue, springboot旅游资源网站的设计与实现,Java项目,SpringBoot项目,含开发文档,源码,数据库以及ppt 环境配置: 框架:springboot JDK版本:JDK1.8 服务器…...
Python编程异步爬虫——协程的基本原理
Python编程之异步爬虫 协程的基本原理 要实现异步机制的爬虫,自然和协程脱不了关系。 案例引入 先看一个案例网站,地址为https://www.httpbin.org/delay/5,访问这个链接需要先等5秒钟才能得到结果,这是因为服务器强制等待5秒时…...

基于springboot+vue的旅游推荐系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 主要内容:毕业设计(Javaweb项目|小程序|Pyt…...
Debezium日常分享系列之:Debezium2.5稳定版本之Monitoring
Debezium日常分享系列之:Debezium2.5稳定版本之Monitoring 一、Snapshot metrics二、Streaming metrics三、Schema history metrics Debezium系列之:安装jmx导出器监控debezium指标 除了 Zookeeper、Kafka 和 Kafka Connect 提供的对 JMX 指标的内置支持…...

GuLi商城-商品服务-API-三级分类-网关统一配置跨域
参考文档: https://tangzhi.blog.csdn.net/article/details/126754515 https://github.com/OYCodeSite/gulimall-learning/blob/master/docs/%E8%B0%B7%E7%B2%92%E5%95%86%E5%9F%8E%E2%80%94%E5%88%86%E5%B8%83%E5%BC%8F%E5%9F%BA%E7%A1%80.md 谷粒商城-day04-完…...

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!
1,视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 【ai技术】(4):在树莓派4上,使用ollama部署qwen0.5b大模型chatgptweb前端界面,搭建本地大模型聊天工具,速度飞快 2,下载…...
深入理解PHP+Redis实现分布式锁的相关问题
概念 PHP使用分布式锁,受语言本身的限制,有一些局限性。 通俗理解单机锁问题:自家的锁锁自家的门,只能保证自家的事,管不了别人家不锁门引发的问题,于是有了分布式锁。分布式锁概念:是针对多个…...
perl:获取同花顺数据--业绩预告
perldoc LWP::UserAgent 如果没有安装,则安装模块,运行 cpanm LWP::UserAgent 。 编写 get_yjyg_10jqka.pl 如下 #!/usr/bin/perl # perl 获取同花顺数据--业绩预告 use LWP::UserAgent; use Encode qw(decode encode); use POSIX; use Data::Dump…...
如何对比引用传参和值传参两者的效率
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或…...
探索软件工程:构建可靠、高效的数字世界
软件工程是一门涵盖了设计、开发、测试、维护和管理软件的学科,它在如今数字化时代的发展中扮演着至关重要的角色。随着科技的不断进步和社会的不断变迁,软件工程的意义也愈发凸显。本文将探索软件工程的重要性、原则和实践,以及其对当今社会…...
超越肉眼:深入计算机视觉的奇妙之旅
揭秘计算机视觉的奥秘:从基础到前沿的探索之旅 引言:一、计算机视觉的基础1. 图像处理基础2. 特征提取与描述3. 基本模式识别 二、机器学习在计算机视觉中的应用1. 深度学习革命2. 迁移学习与多任务学习3. 强化学习与主动学习4. 无监督学习和自监督学习 …...

mac 安装 nvm 【真解决问题】
前提 没有node环境已有git 下载 我用的gitee极速下载 git clone https://gitee.com/mirrors/nvm.git ~/.nvm && cd ~/.nvm && git checkout git describe --abbrev0 --tags配置 1. 配置变量 在用户的目录下新增文件 .zshrc export NVM_DIR"$HOME/…...

【Godot 3.5控件】用TextureProgress制作血条
说明 本文写自2022年11月13日-14日,内容基于Godot3.5。后续可能会进行向4.2版本的转化。 概述 之前基于ProgressBar创建过血条组件。它主要是基于修改StyleBoxFlat,好处是它几乎可以算是矢量的,体积小,所有东西都是样式信息&am…...
第十届蓝桥杯大赛个人赛省赛(软件类)真题- CC++ 研究生组
第十届蓝桥杯大赛个人赛省赛(软件类)真题- C&C 研究生组-立方和 第十届蓝桥杯大赛个人赛省赛(软件类)真题- C&C 研究生组-字串数字 第十届蓝桥杯大赛个人赛省赛(软件类)真题- C&C 研究生组-质数…...

Linux:Gitlab:16.9.2 创建用户及项目仓库基础操作(2)
我在上一章介绍了基本的搭建以及邮箱配置 Linux:Gitlab:16.9.2 (rpm包) 部署及基础操作(1)-CSDN博客https://blog.csdn.net/w14768855/article/details/136821311?spm1001.2014.3001.5501 本章介绍一下用户的创建,组内设置用户&…...

【数据挖掘】实验5:数据预处理(1)
实验5:数据预处理(1) 一:实验目的与要求 1:熟悉和掌握数据预处理,学习数据清洗、数据集成、数据变换、数据规约、R语言中主要数据预处理函数。 二:实验内容 【缺失值分析】 第一步࿱…...
383.赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 思路:将magazine 中字…...
Python 3 教程(8)
heisenbug601 601***902@qq.com 参考地址 311 tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字: 代码如下: >>> classmates = (Michael, Bob, Tracy) 现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法…...

Mysql数据库深入理解
目录 一、什么是数据库 二、Mysql基本架构图 1.Mysql客户端/服务器架构 2.客户端与服务器的连接过程 3.服务器处理客户端请求 4.一条查询SQL执行顺序 4.1连接器 4.2查询缓存 4.3解析器 4.4执行器 4.4.1预处理阶段 4.4.2优化阶段 4.4.3执行阶段 5.一条记录如何存…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...