最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot集成jersey打包jar找不到class的處理方法

 更新時(shí)間:2024年03月21日 09:44:36   作者:mose-x  
這篇文章主要介紹了SpringBoot集成jersey打包jar找不到class的處理方法,文中通過代碼示例介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

環(huán)境 java17 + springboot 3.x

如題,簡單來說,jersey官方希望用戶通過 register 的方式,將所有的資源類注冊到j(luò)ersey中,但是,一般開發(fā)中,可能定義了N個(gè)Resource類,一個(gè)一個(gè)的加入,太麻煩,也可能遺漏,解決方案就是,寫個(gè)方法,掃描到resource包下的所有資源類,然后 register 到j(luò)ersey中

特別注意,是 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對應(yīng)的文件夾的文件,故自定義包掃描
     *
     * @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 轉(zhuǎn)換為 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() {
        // 注冊包掃描 這個(gè)方法在開發(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對象,在整個(gè)spring容器中撈我們需要的controller
        // 傳入的第二個(gè)參數(shù)是可變參數(shù),字符串,用于傳入需要掃描的包路徑
        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一下,我使用的時(shí)候,只有第一個(gè)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() {
    // 。。。 其他的 。。。
    }
}

完結(jié)?。?!

以上就是SpringBoot集成jersey打包jar找不到class的處理方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot jersey找不到class的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一篇文章弄懂JVM類加載機(jī)制過程以及原理

    一篇文章弄懂JVM類加載機(jī)制過程以及原理

    JVM原理對于初學(xué)者而言,比較晦澀難以理解,概念繁多又比較抽象,很多時(shí)候感覺看不見摸不著,還不好驗(yàn)證,下面這篇文章主要給大家介紹了關(guān)于如何通過一篇文章弄懂JVM類加載機(jī)制過程及原理的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • mybatis-plus IdWorker生成的Id和返回給前臺的不一致的解決

    mybatis-plus IdWorker生成的Id和返回給前臺的不一致的解決

    這篇文章主要介紹了mybatis-plus IdWorker生成的Id和返回給前臺的不一致的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • java制作帶界面的聊天工具

    java制作帶界面的聊天工具

    這篇文章主要教大家如何利用java制作帶界面的聊天工具,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Java中ThreadLocal的用法及原理詳解

    Java中ThreadLocal的用法及原理詳解

    這篇文章主要介紹了Java中ThreadLocal的用法及原理詳解,在并發(fā)編程中,如果一個(gè)類變量被多個(gè)線程操作,會造成線程安全問題,使用ThreadLocal可以讓每個(gè)線程擁有線程內(nèi)部的變量,防止多個(gè)線程操作一個(gè)類變量造成的線程安全問題,需要的朋友可以參考下
    2023-09-09
  • mybatis-plugin插件執(zhí)行原理解析

    mybatis-plugin插件執(zhí)行原理解析

    這篇文章主要介紹了mybatis-plugin插件執(zhí)行原理,我們就需要來研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler這4個(gè)對象的具體跟sql相關(guān)的方法,然后再進(jìn)行修改,就可以直接起到aop的作用,需要的朋友可以參考下
    2022-10-10
  • Java中將字符串String轉(zhuǎn)換為整數(shù)int的多種方法

    Java中將字符串String轉(zhuǎn)換為整數(shù)int的多種方法

    在Java中將String類型轉(zhuǎn)換為int類型是一個(gè)常見的操作,下面這篇文章主要給大家介紹了關(guān)于Java中將字符串String轉(zhuǎn)換為整數(shù)int的多種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Java的Spring框架的三種連接池的基本用法示例

    Java的Spring框架的三種連接池的基本用法示例

    這篇文章主要介紹了Java的Spring框架的三種連接池的基本用法示例,Spring框架是Java下注明的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-11-11
  • java中如何區(qū)分==和equals

    java中如何區(qū)分==和equals

    這篇文章主要介紹了java中如何區(qū)分==和equals,文中講解的非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • JAVA實(shí)現(xiàn)下載文件功能的兩種方法

    JAVA實(shí)現(xiàn)下載文件功能的兩種方法

    這篇文章主要介紹了JAVA實(shí)現(xiàn)下載文件功能的兩種方法,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換)

    Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換)

    這篇文章主要介紹了Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04

最新評論

乐都县| 盐津县| 固原市| 沧源| 历史| 金乡县| 南宫市| 八宿县| 海原县| 水城县| 辉县市| 榆社县| 个旧市| 乃东县| 石城县| 巴青县| 民权县| 彰化县| 怀柔区| 铜山县| 富宁县| 永年县| 友谊县| 富民县| 承德市| 阿鲁科尔沁旗| 德昌县| 新乐市| 高安市| 林周县| 桃园市| 陈巴尔虎旗| 外汇| 霞浦县| 陕西省| 蓝田县| 府谷县| 专栏| 秦皇岛市| 三门县| 汾西县|