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

 更新时间:2024年03月21日 09:44:36   作者:mose-x  
这篇文章主要介绍了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);
        }
        @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() {
    // 。。。 其他的 。。。
    }
}

完结!!!

以上就是SpringBoot集成jersey打包jar找不到class的处理方法的详细内容,更多关于SpringBoot jersey找不到class的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈Spring中几个PostProcessor的区别与联系

    浅谈Spring中几个PostProcessor的区别与联系

    这篇文章主要介绍了浅谈Spring中几个PostProcessor的区别与联系,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • spring boot 日志配置详解

    spring boot 日志配置详解

    本篇文章主要介绍了spring boot 日志配置 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • JAVA设计模式之建造者模式原理与用法详解

    JAVA设计模式之建造者模式原理与用法详解

    这篇文章主要介绍了JAVA设计模式之建造者模式,简单说明了建造者模式的原理、组成,并结合实例形式分析了java建造者模式的定义与用法,需要的朋友可以参考下
    2017-08-08
  • Java基于MySQL实现学生管理系统

    Java基于MySQL实现学生管理系统

    这篇文章主要为大家详细介绍了Java基于MySQL实现学生管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • java.io.IOException:你的主机中的软件中止了一个已建立的连接踩坑实战

    java.io.IOException:你的主机中的软件中止了一个已建立的连接踩坑实战

    最近在工作中遇到了个问题,分享给同样遇到问题的同学,这篇文章主要给大家介绍了关于java.io.IOException:你的主机中的软件中止了一个已建立的连接的踩坑实战记录,需要的朋友可以参考下
    2023-03-03
  • springboot整合webservice使用简单案例总结

    springboot整合webservice使用简单案例总结

    WebService是一个SOA(面向服务的编程)的架构,它是不依赖于语言,平台等,可以实现不同的语言间的相互调用,下面这篇文章主要给大家介绍了关于springboot整合webservice使用的相关资料,需要的朋友可以参考下
    2024-07-07
  • Java深入讲解AWT实现事件处理流程

    Java深入讲解AWT实现事件处理流程

    AWT的事件处理是一种委派式事件处理方式:普通组件(事件源)将整个事件处理委托给特定的对象(事件监听器);当该事件源发生指定的事件时,就通知所委托的事件监听器,由事件监听器来处理这个事件
    2022-04-04
  • 小程序与后端Java接口交互实现HelloWorld入门

    小程序与后端Java接口交互实现HelloWorld入门

    本文主要介绍了小程序与后端Java接口交互实现HelloWorld入门 ,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • Mybatis如何传入多个参数的实现代码

    Mybatis如何传入多个参数的实现代码

    这篇文章主要介绍了Mybatis如何传入多个参数的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • SpringBoot整合Jasypt实现配置加密的步骤详解

    SpringBoot整合Jasypt实现配置加密的步骤详解

    Jasypt是一个Java库,提供了一种简单的加密解密方式,可用于保护敏感数据,例如密码、API密钥和数据库连接信息等,本文给大家介绍了SpringBoot整合Jasypt实现配置加密的详细步骤,感兴趣的同学可以参考一下
    2023-11-11

最新评论