注册MessageBodyReader和MessageBodyWriter实现的适当位置是什么?
我为com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader
实现了Javax WS RS API MessageBodyReader
为com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader
MessageBodyWriter
,这样我就可以轻松地在CMP over HTTP REST API中使用这些类型。 现在,要注册我创建META-INF/services/javax.ws.rs.ext.Providers
文件的类型并将类名放在那里。 一切正常,我可以使用API进行REST调用,除了:
-
IntelliJ IDEA(或我安装到其中的插件之一)抱怨说
注册的扩展应该实现javax.ws.rs.ext.Providers
在文件中的两行。 基于我在互联网上找到的资源,我认为添加
@Provider
和@Produces("application/pkixcmp")
注释就足够了。 -
我注意到FasterXML Jackson有
META-INF/services/javax.ws.rs.ext.MessageBodyReader
和META-INF/services/javax.ws.rs.ext.MessageBodyWriter
文件,这些文件似乎注册了一个实现接口的类同样。
所以我的问题是:
-
IntelliJ IDEA是正确还是错误,抱怨我没有实现
javax.ws.rs.ext.Providers
? -
注册
MessageBodyReader
和MessageBodyWriter
实现的正确文件是什么? -
什么是权威文档可以启发我这个?
IntelliJ IDEA是正确还是错误,抱怨我没有实现
javax.ws.rs.ext.Providers
?
META-INF/services
中的文件是我们通过使用ServiceLoader
创建可扩展应用程序的一部分。 它的工作原理是文件名应该是合同的名称,文件的内容应该是该合同的实现列表。 然后, ServiceLoader
将查看该文件并收集所有实现。 所以使用ServiceLoader
,我们可以做到
ServiceLoader readersLoader = ServiceLoader.load(MessageBodyReader.class);
基于传递给load
方法的类,Java将搜索该文件
META-INF/services/javax.ws.rs.ext.MessageBodyReader
并查看该文件的内容以查找它应加载的所有实现。
因此,基于该信息,您可以看到IntelliJ在抱怨中是正确的,因为您的读者和作者没有正确实现javax.ws.rs.ext.Providers
。
我应该指出的一点是,我不认为ServiceLoader
类是直接使用的,因为它要求服务实现具有无参数构造函数。 但这是用于META服务的确切模式。
注册
MessageBodyReader
和MessageBodyWriter
实现的正确文件是什么?
META-INF/services
文件的使用不是JAX-RS规范的一部分。 这是一个特定于JAX-RS实现的实现细节,尽管这种模式被大量使用。 您将主要看到可重用库中使用的文件,例如您提到的Jackson库1 。
如果提供者将成为我们应用程序的一部分,那么有更常见的方式来注册它。
-
您提到的
@Provider
注释是一个标记注释,用于检测应注册的提供者类。 启用扫描后,运行时将扫描使用@Provider
注释的类,然后将其与应用程序一起注册。当我们谈论扫描时,有几种不同的方式:类路径扫描和包扫描。 通过使用
@ApplicationPath
注释的空Application
类,在JAX-RS应用程序中启用类路径扫描。@ApplicationPath("/api/*") public class ApplicationConfig extends Application {}
这足以让JAX-RS应用程序配置2 。 将启用类路径扫描,它将扫描使用
@Path
和@Provider
注释的所有类的整个类路径并注册这些类。包扫描是针对Jersey实现的特定内容。 我们可以这样配置我们的应用程序
@ApplicationPath("api") public class ApplicationConfig extends ResourceConfig { public ApplicationConfig() { package("the.package.to.scan"); } }
在这里,我们告诉Jersey扫描
the.package.to.scan
和@Provider
类的the.package.to.scan
包以注册该应用程序。 -
注册我们的提供者的另一种方法是明确注册它们。 在
Application
子类中,您将覆盖getClasses()
或getSingletons()
以分别将它们注册为类或对象。@ApplicationPath("/api/*") public class ApplicationConfig extends Application { private final Set
> classes = new HashSet<>(); private final Set 请注意,一旦覆盖这些方法中的任何一个并返回非空集,就会自动禁用类路径扫描,并且您需要手动注册所有内容。
如果您正在使用Jersey实现,那么我们还可以通过Jersey特定方式明确注册资源和提供程序。 有关这方面的更多讨论,请参阅Jersey 2中的ResourceConfig类究竟是什么? 。
-
我可以考虑注册提供者的另一种方法是使用function。 我们可以使用vanilla
Feature
,也可以使用DynamicFeature
。使用
Feature
,我们在整个应用程序中注册提供程序// We should register the feature with our application public class MyFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(MyMessageBodyReader.class); } }
使用
DynamicFeature
我们可以选择性地使用特定的资源方法或资源类注册提供程序。 有关动态绑定的详情,请参阅Jersey文档 。 应该注意的是,动态绑定更多地用于filter和拦截器(这也是术语,提供者的一般意义上的),而不是实体提供者(MessageBodyReader / Writers)。 -
可能还有其他方式来注册您的提供程序,但上面提到的是您将在应用程序中看到它的主要方式。
什么是权威文档可以启发我这个?
我不确定在任何文档中有多少关于META-INF /服务文件的信息。 但是显式注册和类路径扫描,您可能会在JAX-RS规范或Jersey文档中找到
1 – 应该注意的是,仅仅因为文件存在,并不意味着它将被使用。 无论是否使用它,都取决于JAX-RS的实现。 例如,Jersey不会在MessageBodyReader
和编写器上使用它。
2 – 请参阅如何在没有web.xml的情况下将Jersey用作JAX-RS实现?