SpringBoot集成jersey打包jar找不到class的處理方法
環(huán)境 java17 + springboot 3.x
如題,簡單來說,jersey官方希望用戶通過 register 的方式,將所有的資源類注冊到jersey中,但是,一般開發(fā)中,可能定義了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() { // 注冊包掃描 這個方法在開發(fā)使用沒問題,但是打包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); } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); // 注意這里的值,最好debug一下,我使用的時候,只有第一個metadata.isIndependent()是true return (metadata.isIndependent() && metadata.isAbstract() && !beanDefinition.getMetadata().isAnnotation()); } } }
2.2 引用
@Configuration public class JerseyConfig extends ResourceConfig implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @PostConstruct public void init() { registerClasses(JerseyServiceAutoScanner.getPublishJerseyServiceClasses(applicationContext, "com.xxx.xxx.api")); } public JerseyConfig() { // 。。。 其他的 。。。 } }
完結?。。?/p>
以上就是SpringBoot集成jersey打包jar找不到class的處理方法的詳細內容,更多關于SpringBoot jersey找不到class的資料請關注腳本之家其它相關文章!
相關文章
淺談Spring中幾個PostProcessor的區(qū)別與聯(lián)系
這篇文章主要介紹了淺談Spring中幾個PostProcessor的區(qū)別與聯(lián)系,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java基于MySQL實現(xiàn)學生管理系統(tǒng)
這篇文章主要為大家詳細介紹了Java基于MySQL實現(xiàn)學生管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01java.io.IOException:你的主機中的軟件中止了一個已建立的連接踩坑實戰(zhàn)
最近在工作中遇到了個問題,分享給同樣遇到問題的同學,這篇文章主要給大家介紹了關于java.io.IOException:你的主機中的軟件中止了一個已建立的連接的踩坑實戰(zhàn)記錄,需要的朋友可以參考下2023-03-03springboot整合webservice使用簡單案例總結
WebService是一個SOA(面向服務的編程)的架構,它是不依賴于語言,平臺等,可以實現(xiàn)不同的語言間的相互調用,下面這篇文章主要給大家介紹了關于springboot整合webservice使用的相關資料,需要的朋友可以參考下2024-07-07小程序與后端Java接口交互實現(xiàn)HelloWorld入門
本文主要介紹了小程序與后端Java接口交互實現(xiàn)HelloWorld入門 ,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07SpringBoot整合Jasypt實現(xiàn)配置加密的步驟詳解
Jasypt是一個Java庫,提供了一種簡單的加密解密方式,可用于保護敏感數據,例如密碼、API密鑰和數據庫連接信息等,本文給大家介紹了SpringBoot整合Jasypt實現(xiàn)配置加密的詳細步驟,感興趣的同學可以參考一下2023-11-11