Jersey 2.0 的依赖注入
Posted
技术标签:
【中文标题】Jersey 2.0 的依赖注入【英文标题】:Dependency injection with Jersey 2.0 【发布时间】:2013-04-19 11:11:19 【问题描述】:在没有任何以前的 Jersey 1.x 知识的情况下从头开始,我很难理解如何在我的 Jersey 2.0 项目中设置依赖注入。
我也知道 HK2 在 Jersey 2.0 中可用,但我似乎找不到有助于 Jersey 2.0 集成的文档。
@ManagedBean
@Path("myresource")
public class MyResource
@Inject
MyService myService;
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* @return String that will be returned as a text/plain response.
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/getit")
public String getIt()
return "Got it " + myService + "";
@Resource
@ManagedBean
public class MyService
void serviceCall()
System.out.print("Service calls");
pom.xml
<properties>
<jersey.version>2.0-rc1</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>$jersey.version</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jax-rs-ri</artifactId>
</dependency>
</dependencies>
我可以让容器启动并提供我的资源,但是只要我将@Inject 添加到 MyService,框架就会引发异常:
SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers=),position=-1,optional=false,self=false,unqualified=null,1039471128)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers=),position=-1,optional=false,self=false,unqualified=null,1039471128)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
我的入门项目在 GitHub 上可用:https://github.com/donaldjarmstrong/jaxrs
【问题讨论】:
【参考方案1】:您需要定义一个AbstractBinder
并将其注册到您的 JAX-RS 应用程序中。 binder 指定依赖注入应如何创建您的类。
public class MyApplicationBinder extends AbstractBinder
@Override
protected void configure()
bind(MyService.class).to(MyService.class);
当在MyService.class
类型的参数或字段上检测到@Inject
时,它会使用MyService
类进行实例化。要使用此绑定器,需要向 JAX-RS 应用程序注册。在您的 web.xml
中,像这样定义一个 JAX-RS 应用程序:
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.mypackage.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
实现MyApplication
类(在上面的init-param
中指定)。
public class MyApplication extends ResourceConfig
public MyApplication()
register(new MyApplicationBinder());
packages(true, "com.mypackage.rest");
指定依赖注入的绑定器在类的构造函数中注册,我们还使用packages()
方法调用告诉应用程序在哪里可以找到 REST 资源(在您的情况下为 MyResource
)。
【讨论】:
EntityManager 怎么样?任何提示如何绑定它,所以我可以通过 @PersistenceContext 注入它? 我不确定EntityManager
是什么,但从docs.oracle.com/javaee/6/api/javax/persistence/… 来看,它似乎是一个接口。您可以使用bind(EntityManagerImpl.class).to(EntityManager.class)
绑定它(这将绑定一个实现接口EntityManager
的类EntityManagerImpl
。如果您需要使用工厂,请查看AbstractBinder
中的bindFactory()
。如果您需要帮助这个,请创建一个新问题(我将没有空间在 cmets 中回答它)。另外,我不确定您是否应该使用 @PersistentContext,只需使用 @Inject 进行所有操作
是的,EntityManager 是特定于 JPA (Java EE) 的。感谢您的评论,如果我遇到特定问题,我会打开另一个问题!
仅作记录,JPA 也可以在 Java SE 上运行。 oracle.com/technetwork/java/javaee/tech/…
绑定有什么作用?如果我有一个接口和一个实现怎么办?【参考方案2】:
首先只是回答接受答案中的评论。
“绑定有什么作用?如果我有一个接口和一个实现怎么办?”
它只是读取bind( implementation ).to( contract )
。您可以替换链.in( scope )
。 PerLookup
的默认范围。所以如果你想要一个单例,你可以
bind( implementation ).to( contract ).in( Singleton.class );
还有一个RequestScoped
可用
另外,除了bind(Class).to(Class)
,你也可以bind(Instance).to(Class)
,它会自动成为一个单例。
添加到accepted answer
对于那些试图弄清楚如何在 web.xml 中注册AbstractBinder
实现的人(即您没有使用ResourceConfig
),似乎无法通过包扫描发现活页夹,即
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
your.packages.to.scan
</param-value>
</init-param>
或者这个
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.foo.YourBinderImpl
</param-value>
</init-param>
为了让它工作,我必须实现一个Feature
:
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
@Provider
public class Hk2Feature implements Feature
@Override
public boolean configure(FeatureContext context)
context.register(new AppBinder());
return true;
@Provider
注释应该允许 Feature
被包扫描拾取。或者不扫描包,你可以在web.xml
中显式注册Feature
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.foo.Hk2Feature
</param-value>
</init-param>
...
<load-on-startup>1</load-on-startup>
</servlet>
另请参阅:
Custom Method Parameter Injection with Jersey How to inject an object into jersey request context? How do I properly configure an EntityManager in a jersey / hk2 application? Request Scoped Injection into Singletons以及泽西文档中的一般信息
Custom Injection and Lifecycle Management更新
工厂
除了接受答案中的基本绑定之外,您还有工厂,您可以在其中拥有更复杂的创建逻辑,并且还可以访问请求上下文信息。例如
public class MyServiceFactory implements Factory<MyService>
@Context
private HttpHeaders headers;
@Override
public MyService provide()
return new MyService(headers.getHeaderString("X-Header"));
@Override
public void dispose(MyService service) /* noop */
register(new AbstractBinder()
@Override
public void configure()
bindFactory(MyServiceFactory.class).to(MyService.class)
.in(RequestScoped.class);
);
然后您可以将MyService
注入到您的资源类中。
【讨论】:
我可以通过 ResourceConfig 实现注册我的活页夹类,如接受的答案所示。不需要要素类。 使用web.xml
,即使Hk2Feature
上的configure()
被调用,请求资源也会抛出NullPointerException
。 @PaulSamsotha
嗯它只是读取并没有真正让我理解它的作用。此外,如果是bind(Instance).to(Class)
,您从哪里获得实例?因为我们在AbstractBinder
中谈论configure
,对吧?【参考方案3】:
所选答案可以追溯到不久前。在自定义 HK2 绑定器中声明每个绑定是不切实际的。 我正在使用 Tomcat,我只需要添加一个依赖项。即使它是为 Glassfish 设计的,它也可以完美地融入其他容器。
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>$jersey.version</version>
</dependency>
确保您的容器也已正确配置 (see the documentation)。
【讨论】:
最后一行(确保您的容器也已正确配置)有点含糊。这里有什么帮助吗?我们在哪里使用什么注解? 我们使用 Weld 进行依赖注入,这需要一些特殊的配置才能与 Tomcat(我们的应用程序“容器”)一起使用。如果您使用的是 Spring,它开箱即用。【参考方案4】:晚了,但我希望这对某人有所帮助。
我的 JAX RS 定义如下:
@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource
然后,在我的代码中我终于可以注入了:
@Inject
SomeManagedBean bean;
在我的例子中,SomeManagedBean
是一个 ApplicationScoped bean。
希望这对任何人都有帮助。
【讨论】:
【参考方案5】:Oracle 建议在将 JAX-RS 与 CDI 结合使用时,将 @Path 注解添加到所有要注入的类型: http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm 尽管这远非完美(例如,您会在启动时收到 Jersey 的警告),但我决定采用这条路线,这样我就无需在活页夹中维护所有支持的类型。
例子:
@Singleton
@Path("singleton-configuration-service")
public class ConfigurationService
..
@Path("my-path")
class MyProvider
@Inject ConfigurationService _configuration;
@GET
public Object get() ..
【讨论】:
链接失效,应该指向here【参考方案6】:如果你更喜欢使用 Guice 并且不想声明所有的绑定,你也可以试试这个适配器:
guice-bridge-jit-injector
【讨论】:
【参考方案7】:如果我在我的 Web 应用程序中包含以下依赖项(在 Tomcat 8.5、Jersey 2.27 上运行),它可以在没有 AbstractBinder
的情况下工作:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>$jersey-version</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x</artifactId>
<version>$jersey-version</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>$jersey-version</version>
</dependency>
它适用于我的 CDI 1.2 / CDI 2.0(分别使用 Weld 2 / 3)。
【讨论】:
【参考方案8】:jersey restful 服务所需的依赖关系,Tomcat 是服务器。 其中 $jersey.version 是 2.29.1
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>$jersey.version</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>$jersey.version</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>$jersey.version</version>
</dependency>
基本代码如下:
@RequestScoped
@Path("test")
public class RESTEndpoint
@GET
public String getMessage()
【讨论】:
以上是关于Jersey 2.0 的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
vue3.0 依赖注入 provide()和inject()使用教程
vue3.0 依赖注入 provide()和inject()使用教程
vue3.0 依赖注入 provide()和inject()使用教程