jersey在 spring boot 添加 packages 扫描路径支持

最近公司内部系统要做数据对接,故使用 jersey 来做 restful webservice 接口设计。由于 spring boot 已经集成 jersey,估计直接导入 spring-boot-starter-jersey 就好了。

在测试时候除了遇到中文乱码之外花费了比较长的时间,其余暂时没遇到大的问题。然而发布的时候发现了一个坑。

public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        //registerClasses(findAllClasses());
        packages("com.xx");
        // 注册日志
        register(LoggingFeature.class);
        // 异常处理
        register(ExceptionHandler.class);
        // 跨域过滤器注册
        register(CorsFilter.class);

    }
}

jersey 是使用 register(Class clazz) 或者 packages("packageName") 来注册或者扫描来加载所需的类到容器中的。然而在实际项目中,使用 register(Class clazz) 会写大量的注册类,依赖性太强,而且在maven多模块中更不好处理。

而使用 packages 来扫描,在开发测试的时候倒没发现什么问题,但是使用 spring boot 打成 jar 包运行时,会产生 FileNotFound 的错误,这是因为 使用 jersey 的 packages 扫描的机制是无法扫描到 jar 中的 class 文件的。

由于使用的是 spring boot,spring 的 component scan 是可以做到的。故参考 spring 扫描机制的源码,将 jar 中的 class 文件加载进来就好了。

代码如下:

import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
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;

/**
 * @author gongtao
 * @version 2018-04-23 10:15
 **/
@Configuration
@Slf4j
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        //扫描注册
        registerClasses(findAllClasses());
        // 注册日志
        register(LoggingFeature.class);
        // 异常处理
        register(ExceptionHandler.class);
        // 跨域过滤器注册
        register(CorsFilter.class);

    }

    /**
     * 由于spring boot 打包为jar包,jersey packages 无法扫描jar对应的文件夹的文件,故自定义包扫描
     * @return
     */
    private Set<Class<?>> findAllClasses(){
        String scanPackages = "com.xxx.eoms.innerinterface.interfaces.resource.*";
        ClassLoader loader = this.getClass().getClassLoader();
        Resource[] resources = new Resource[0];
        try {
            resources = scan(loader, scanPackages);
        } catch (IOException e) {
            log.error("加载class异常",e);
        }
        return convert(loader, resources);
    }

    /**
     * 扫描 jar 包
     * @param loader
     * @param packageName
     * @return
     * @throws IOException
     */
    private 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
     * @param resource
     * @return
     */
    private 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
     * @param resources
     * @return
     */
    private 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;
    }

原文地址:https://www.cnblogs.com/suiyueqiannian/p/8946720.html

时间: 2024-08-24 07:58:58

jersey在 spring boot 添加 packages 扫描路径支持的相关文章

Spring boot 默认静态资源路径与手动配置访问路径的方法

这篇文章主要介绍了Spring boot 默认静态资源路径与手动配置访问路径的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在application.propertis中配置 ##端口号 server.port=8081 ##默认前缀 spring.mvc.view.prefix=/ ## 响应页面默认后缀 spring.mvc.view.suffix=.html # 默认值为 /** spring.mvc.static-path-pattern=/** # 这里设置要指向的路径,多个

Spring Boot 添加JSP支持【转】

Spring Boot 添加JSP支持 大体步骤: (1)            创建Maven web project: (2)            在pom.xml文件添加依赖: (3)            配置application.properties支持jsp (4)            编写测试Controller (5)          编写JSP页面 (6)          编写启动类App.Java 1,FreeMarker2,Groovy3,Thymeleaf (s

开发人员建议阅读:Spring Boot 架构中的国际化支持实践

pring Boot 主要通过 Maven 或 Gradle 这样的构建系统以继承方式添加依赖,同时继承了 Spring 框架中的优秀元素,减少了 Spring MVC 架构中的复杂配置,内置 Tomcat,Jetty 容器,使用 Java application 运行程序,而不是传统地把 WAR 包置于 Tomcat 等容器中运行,从而简化加速开发流程.此外,Spring Boot 学习简单.轻量级.容易扩展.基于这些优秀的特点,Spring Boot 成为了蓬勃发展的快速应用开发领域的领导者

spring boot: @EnableScheduling开启计划任务支持,@Scheduled计划任务声明

spring boot: @EnableScheduling开启计划任务支持, @Scheduled计划任务声明 1 package ch2.scheduler2; 2 3 //日期转换方式 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6 7 //计划任务声明 8 import org.springframework.scheduling.annotation.Scheduled; 9 //spring组件注解 10

spring boot 添加拦截器

构建一个spring boot项目. 添加拦截器需要添加一个configuration @Configuration @ComponentScan(basePackageClasses = Application.class, useDefaultFilters = true) public class ServletContextConfig extends WebMvcConfigurationSupport { 为了方便扫描位置,我们可以写一个接口或者入口类Application放置于最外

Spring Boot 添加jersey-mvc-freemarker依赖后内置tomcat启动不了解决方案

我在我的Spring Boot 项目的pom.xml中添加了jersey-mvc-freemarker依赖后,内置tomcat启动不了. 报错信息如下: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletCon

spring boot mybatis没有扫描jar中的Mapper接口

只需要在spring boot启动类上加上注解,并指定jar包中接口文件包路径即可 如下: @ComponentScan(basePackages = "com.xx") @MapperScan(basePackages = "com.xx.**.dao") @SpringBootApplication @EnableCaching @EnableDiscoveryClient public class EnterApplication { public stati

spring boot 添加整合ssl使得http变成https方法

1. https出现的背景:(1)都知道http传输协议是裸漏的,明文传输的,极易被黑客拦截,因此,(2)人们想出的使用加密,也就是 对称加密 例如aes,不过这个由于因为对称加密需要每个客户端和服务器有独立一套,当客户端多的时候维护困难,因此 有了 非对称加密 例如 RSA,RSA,这个是1977年 麻省理工学院三个程序员发明的,很厉害,目前还未被破解,扯远了 RSA是一种公钥密码体制,现在使用得很广泛.如果对RSA本身有兴趣的,后面看我有没有时间写个RSA的具体介绍. RSA密码体制是一种公

spring boot 添加监控

在application.properties中,添加 spring.application.name=Spring Boot Admin Web spring.boot.admin.url=http://localhost:${server.port} spring.jackson.serialization.indent_output=true endpoints.health.sensitive=false management.security.enabled=false ribbon.