当前位置: 首页 > 知识库问答 >
问题:

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

吕文林
2023-03-14

我知道关于这个问题有很多答案,但我仍然不清楚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负责在定义的“产生”responseType中编组这些对象,并将其写入客户端流

我的问题是当您说:“jersey照顾编组定义的'Production'responseType中的那些对象并将其写入客户端流”时,您所说的jersey是什么意思,什么是实际的处理对象的类或库。

当我读到jersey是处理JAX-RS API规范的引擎时,我感到很困惑。谁能解释一下这个句子中jersey这个词后面到底是什么意思吗?泽西的实际类在泽西执行处理请求和响应的工作?

共有1个答案

常雅达
2023-03-14

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

假设我想要一个解析库。我知道我多么想用它。唯一的问题是我不太擅长写解析代码。所以我创建了一个高级规范,并外包了实现。下面是规范的三个类。它们都包含在一个“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));
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给我返回了一个包含这三个类和所需的Meta-INF/Services文件(按照ServiceLoader模式)的jar(比如so-myParsers-impl.jar),现在当我将so-myParsers-impl.jar添加到我的项目并尝试再次运行它时,程序现在可以工作了,因为它有了一个实现。

这正是JAX-RS规范的工作方式。它只定义了它应该如何工作的高级设计。作为设计一部分的类、接口和注释被放置在一个“API JAR”中,就像我的高级解析器被放置在一个JAR中一样。实现不能更改这些类。作为JAX-RS规范(版本2.x)一部分的所有类都被放入一个jarjavax.ws.rs-api中。您可以针对该jar编写代码,并且您的代码可以很好地编译。但没有什么能让它“起作用”。

您检查了编写的规范和规范定义的类,您会注意到源代码中包含的类只有规范中提到的那些。但是您应该注意到的是,编写的规范完全没有提到它应该如何实现。以以下代码为例

@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类启动一个服务器吗?还有一些诡计会让一个@path注释类自动接受请求。不。需要一些身体来提供引擎。引擎可能是20,000行代码,只是为了使上面的代码按照指定的方式工作。

话虽如此,泽西只是一个实现的名称。这就像当我将我的解析器实现外包给堆栈溢出时一样;Jersey这个名字本身只是项目的名字,就像Hadoop是项目的一个名字一样。在本例中,项目是JAX-RS规范的实现。而且因为JAX-RS只是一个规范,这意味着任何人都可以实现它。如果您愿意,您可以编写自己的实现。只要它是如何在书面规范中定义工作的,那么您就可以说您的代码是JAX-RS的实现。那里不仅仅是泽西;您还拥有RESTEasy,这是另一个实现。

至于泽西如何实现引擎,这是太宽泛了。我所能做的,是给你一个在场景后面发生的高水平的概览。

JAX-RS应用程序被定义为在servlet容器内部运行。如果您了解servlet容器和servlet规范,那么您就会知道处理请求的唯一方法是编写httpservletfilter。因此,如果您希望实现JAX-RS,那么您需要能够通过HttpServletfilter处理请求。您提到的ServletContainer实际上是两者兼而有之。所以对于Jersey来说,就请求处理而言,这是进入Jersey应用程序的“入口点”。它可以通过多种方式进行配置(我将研究留给您)。

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

如果您真的想深入了解引擎盖下发生的事情的血腥细节,那么您只需要从入口点ServletContainer开始深入了解源代码。准备好花几个月的时间来了解它是如何工作的。这不是一个堆栈溢出文章可以解释的,如果这是您所期望的。

 类似资料:
  • 我有一个使用ModelViewSet实现的模型。在这种情况下,GET and POST工作得很好。但是当我定义PUT时,我在rest客户机中得到以下响应: urls.py 有没有人可以建议我应该如何在这里实现update方法,以便下面的请求可以工作:

  • 还是不创建过滤器,并在每个请求中放置参数令牌?以便每个API首先检查令牌,然后执行一些内容以检索资源。

  • 就像Flask拥有来实现迁移一样。猎鹰有类似烧瓶的东西吗?

  • 如果我们有一个POJO类,那么我们可以用一些传入的JSON来映射它。我正在努力寻找一种方法,通过这种方法,我可以在内部包含所有普通的json值。 为了前任。

  • 问题内容: 我正在使用Django REST框架编写REST API 。该API将成为社交移动应用程序的后端。在学习了本教程之后,我可以序列化所有模型,并且能够创建新资源并对其进行更新。 我正在使用AuthToken进行身份验证。 我的问题是: 获得资源后,我希望应用程序用户能够注册。因此,拥有像这样的单独资源还是允许匿名用户将其发布到新资源更好? 此外,有关权限的一些指导也将非常有用。 问题答案

  • 我从JavaEE 6中读到了这一点。 所以如果没有web.xml,我如何告诉应用程序服务器使用Jersey作为JAX-RS规范的实现呢?