首页 文章

Jersey框架如何在REST中实现JAX-RS API?

提问于
浏览
1

我知道这个问题有很多答案,但我仍然对JAX-RS API(规范)和Jersey框架(参考实现)之间的区别感到困惑 .

我读到了:

Jersey框架基本上使用com.sun.jersey.spi.container.servlet.ServletContainer servlet来拦截所有传入的请求 . 正如我们在项目web.xml中配置的那样,所有传入的rest请求都应由该servlet处理 . 有一个init-param配置了jersey servlet来查找REST服务类 . REST服务类不是Servlet,它们不需要像在代码中那样扩展HttpServlet . 这些REST服务类是简单的POJO注释,用于告诉jersey框架不同的属性,如路径,消耗,产生等 . 当您从服务方法返回时,jersey负责在定义的'PRODUCES'responseType中编组这些对象并编写它在客户端流上

我的问题是当你说:“泽西负责在定义的'PRODUCES'responseType中编组那些对象并将其写在客户端流上”,你的意思是泽西,什么是处理对象的实际类或库 .

当我读到泽西是处理JAX-RS API规范的引擎时,我很困惑 . 有人可以解释一下这句话中汗衫背后究竟是什么?来自 Jersey 的实际 class 在 Jersey 处理请求和回复的工作?

2 回答

  • 3

    规范和实现的概念实际上是非常基本的软件工程概念 . 您的规格是高级设计 . 为了帮助理解,我想出了一个非常简单的例子 .

    说我想要一个解析库 . 我知道我希望如何使用它 . 唯一的问题是我不擅长编写解析代码 . 所以我创建了一个高级规范,并将实现外包出去 . 以下是作为规范一部分的三个类 . 它们都包含在一个"API jar"中,比如 myparsers-api.jar

    public interface Parser {
        String[] parse(String s);
    }
    
    public interface ParserFactory {
        Parser getBySpaceParser();
        Parser getByCommaParser();
    }
    
    public class ParserDepot {
        private static ServiceLoader<ParserFactory> loader
                = ServiceLoader.load(ParserFactory.class);
    
        public static ParserFactory getDefaultParserFactory() {
            final List<ParserFactory> factories = new ArrayList<>();
            loader.forEach(factories::add);
            if (factories.isEmpty()) {
                throw new IllegalStateException("No ParserFactory found");
            }
            return factories.get(0);
        }
    }
    

    所以在这一点上,我实际上可以对这个jar进行编码 . 如果我现在在另一个项目中使用它,该项目将编译得很好 .

    ParserFactory factory = ParserDepot.getDefaultParserFactory();
    Parser parser = factory.getBySpaceParser();
    String[] tokens = parser.parse("Hello World");
    System.out.println(Arrays.toString(tokens));
    

    因此,即使没有实现此规范,我仍然可以对其进行编码,并针对它进行编译 . 但是当我尝试实际运行该程序时,它将无法工作,因为没有实现 . 您可以尝试运行此代码,您将获得 IllegalStateException (如果您不熟悉此模式,请参阅the docs for ServiceLoader) .

    所以我将实现外包给一家名为Stack Overflow的公司 . 他们得到我的myparsers-api.jar,他们需要给我一个实现 . 他们需要实现一个 ParserFactory 和几个 Parser . 他们可能看起来像这样

    public class SoByCommaParser implements Parser {
        @Override
        public String[] parse(String s) {
            return s.split("\\s+,\\s+");
        }
    }
    
    public class SoBySpaceParser implements Parser {
        @Override
        public String[] parse(String s) {
            return s.split("\\s+");
        }
    }
    
    public class SoParserFactory implements ParserFactory {
        @Override
        public Parser getBySpaceParser() {
            return new SoBySpaceParser();
        }
    
        @Override
        public Parser getByCommaParser() {
            return new SoByCommaParser();
        }
    }
    

    现在,Stack Overflow给了我一个jar(比如说 so-myparsers-impl.jar )这三个类和所需的META-INF / services文件(按照ServiceLoader模式),现在当我将so-myparsers-impl.jar添加到我的项目中时尝试再次运行它,该程序现在可以工作,因为现在它有一个实现 .

    这正是JAX-RS规范的工作原理 . 它只定义了它应该如何工作的高级设计 . 作为该设计一部分的类,接口和注释放在_2698334中,就像我的高级解析器被放入jar中一样 . 实现不能改变这些类 . 所有属于JAX-RS规范(版本2.x)的类都放在一个jar javax.ws.rs-api中 . 你可以针对那个jar进行编码,你的代码就可以编译得很好 . 但没有什么可以做到的"work" .

    您查看了the written specificationclasses defined by the specification,您会注意到源代码中包含的唯一类是规范中提到的类 . 但是你应该注意的是,书面规范没有提到任何关于它应该如何实现的内容 . 以下面的代码为例

    @Path("/test")
    public class TestResource {
        @GET
        public String get() {
            return "Testing";
        }
    }
    
    @ApplicationPath("/api")
    public class MyApplication extends Application {
        @Override
        public Set<Class<?>> getClasses() {
            Set<Class<?>> classes = new HashSet<>();
            classes.add(TestResource.class);
            return classes;
        }
    }
    

    现在规范声明这就是我们在servlet容器中运行JAX-RS应用程序所需的全部内容 . 这就是它所说的 . 它没有说明它应该如何工作 . 这就是它的设计工作方式 .

    那么,Java中有一些神奇的巫术,我们不知道这将使这个 Application 类启动一个服务器,并且一些hocus pocus会使一个 @Path 带注释的类自动接受请求 . 没有 . 有些身体需要提供引擎 . 引擎可能是20,000行代码,只是为了使上面的代码按指定的方式工作 .

    话虽这么说, Jersey 只是一个实施的名称 . 这就像我将解析器实现外包给Stack Overflow;名称Jersey本身就是项目的名称,就像Hadoop是项目的名称一样 . 在这种情况下,项目是JAX-RS规范的实现 . 而且因为JAX-RS只是一个规范,所以任何人都可以实现它 . 如果你愿意,你可以编写自己的实现 . 只要它的工作方式如何定义为在书面规范中工作,那么您可以说您的代码是JAX-RS的实现 . 那里不仅仅是 Jersey ;你也有RESTEasy,这是另一个实现 .

    至于 Jersey 如何实施引擎,这太过广泛了 . 我能做的是,让您高度了解幕后发生的事情 .

    JAX-RS应用程序定义为在servlet容器内运行 . 如果您了解servlet容器和servlet规范,那么您将知道处理请求的唯一方法是编写 HttpServletFilter . 因此,如果要实现JAX-RS,则需要能够通过 HttpServletFilter 处理请求 . 你提到的ServletContainer实际上都是 . 所以对于Jersey来说,这是关于Jersey应用程序的"entry point",就请求处理而言 . 它可以通过多种方式配置(我将这项研究留给您) .

    如果您了解如何编写自己的servlet,那么您知道所有获得的是 HttpServletRequestHttpServletResponse . 你需要弄清楚从那里做什么;从请求中获取请求信息,并在响应中发回响应信息 . 泽西处理所有这些 .

    如果你真的想深入了解幕后内容的细节,你只需要从入口点 ServletContainer 开始深入挖掘源代码 . 准备好花几个月时间来了解这一切是如何运作的 . 它's not something that can be explained in one Stack Overflow post, if that'是你所期待的 .

  • 1

    你已经指出JAX-RS是 specification 而Jersey是 implementation 这是Java如何特别是Java EE工作,也许这可以更好地解释.2698355_ .

    总结一下JAX-RS只是一个规范,没有真正的实现 . 真正的实现是由Jersey和其他遵循JAX-RS规范的库完成的 .

相关问题