Jersey 2.0을 사용한 종속성 주입


108

이전 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 에서 사용할 수 있습니다.

답변:


107

을 정의하고 AbstractBinderJAX-RS 애플리케이션에 등록해야합니다. 바인더는 종속성 주입이 클래스를 만드는 방법을 지정합니다.

public class MyApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(MyService.class).to(MyService.class);
    }
}

경우 @Inject형의 파라미터 또는 필드에서 검출 된 MyService.class그 클래스를 사용하여 인스턴스화된다 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");
    }
}

종속성 주입을 지정하는 바인더는 클래스의 생성자에 등록되며 메서드 호출을 MyResource사용하여 REST 리소스 (귀하의 경우 ) 를 찾을 위치를 애플리케이션에 알립니다 packages().


1
EntityManager는 어떻습니까? 바인딩하는 방법에 대한 힌트가 있으므로 @PersistenceContext를 통해 주입 할 수 있습니까?
Johannes Staehlin 2013 년

4
무엇인지 잘 모르겠지만 docs.oracle.com/javaee/6/api/javax/persistence/…로EntityManager 판단 하면 인터페이스 인 것 같습니다. 당신은 사용하여 결합 할 수있는 클래스를 바인딩 할 ( 인터페이스를 구현 . 당신이 공장을 사용해야하는 경우에 대해 살펴 에 . 당신이 도움을 필요로하는 경우, 새 질문을 만드십시오 (나는에 공간이되지 않습니다 댓글에 답변 bind(EntityManagerImpl.class).to(EntityManager.class)EntityManagerImplEntityManagerbindFactory()AbstractBinder
해주세요

예, EntityManager는 JPA (Java EE) 전용입니다. 의견을 보내 주셔서 감사합니다. 특정 문제가 발생하면 다른 질문을 드리겠습니다!
Johannes Staehlin

기록을 위해 JPA는 Java SE에서도 실행됩니다. oracle.com/technetwork/java/javaee/tech/…
prefabSOFT

2
bind는 무엇을합니까? 인터페이스와 구현이 있으면 어떻게합니까?
Dejell

52

먼저 accepts 답변의 주석에 대답하십시오.

"바인드는 무엇을합니까? 인터페이스와 구현이 있으면 어떻게합니까?"

단순히 읽습니다 bind( implementation ).to( contract ). 당신은 대체 체인 수 있습니다 .in( scope ). 기본 범위 PerLookup. 따라서 싱글 톤을 원한다면

bind( implementation ).to( contract ).in( Singleton.class );

또한 RequestScoped사용할 수 있습니다

또한, 대신 자동으로 싱글 톤이되는 bind(Class).to(Class)을 사용할 수도 bind(Instance).to(Class)있습니다.


수락 된 답변에 추가

AbstractBinderweb.xml에 구현 을 등록하는 방법을 알아 내려는 경우 (예 :를 사용하지 않음 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패키지 검사에 의해 선택되어야한다. 또는 패키지 스캔없이 명시 적으로에 등록 할 수 있습니다 Feature.web.xml

<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>

또한보십시오:

Jersey 문서의 일반 정보는


최신 정보

공장

허용되는 답변의 기본 바인딩 외에도 더 복잡한 생성 논리를 가질 수 있고 컨텍스트 정보를 요청하는 데 액세스 할 수있는 팩토리도 있습니다. 예를 들면

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 구현을 통해 바인더 클래스를 등록 할 수 있습니다. 피쳐 클래스가 필요하지 않았습니다.
Patrick Koorevaar 2016 년

on 이 호출 web.xml되어도 사용하면 리소스를 요청하면 . @PaulSamsothaconfigure()Hk2FeatureNullPointerException
bytesandcaffeine

12

선택한 답변은 오래 전부터 거슬러 올라갑니다. 사용자 정의 HK2 바인더에서 모든 바인딩을 선언하는 것은 실용적이지 않습니다. 저는 Tomcat을 사용하고 있으며 하나의 종속성을 추가해야했습니다. Glassfish 용으로 설계되었지만 다른 용기에 완벽하게 맞습니다.

   <dependency>
        <groupId>org.glassfish.jersey.containers.glassfish</groupId>
        <artifactId>jersey-gf-cdi</artifactId>
        <version>${jersey.version}</version>
    </dependency>

컨테이너도 올바르게 구성되었는지 확인하십시오 ( 문서 참조 ).


마지막 줄 (컨테이너도 올바르게 구성되었는지 확인)은 약간 모호합니다. 여기에 도움이 필요하십니까? 어디에서 어떤 주석을 사용합니까?
markthegrea

우리는 의존성 주입을 위해 Weld를 사용하고 있었는데, Tomcat (우리의 애플리케이션 "컨테이너")과 함께 작동하려면 특별한 설정이 필요했습니다. Spring을 사용하는 경우 즉시 작동합니다.
otonglet

5

늦었지만 이것이 누군가에게 도움이되기를 바랍니다.

내 JAX RS가 다음과 같이 정의되어 있습니다.

@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {

그런 다음 마침내 코드에서 다음을 삽입 할 수 있습니다.

@Inject
SomeManagedBean bean;

제 경우 SomeManagedBean에는 ApplicationScoped 빈입니다.

이것이 누구에게나 도움이되기를 바랍니다.


3

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() {..}
}

1
링크가
Hank


0

AbstractBinder내 웹 응용 프로그램에 다음 종속성을 포함하면 (Tomcat 8.5, Jersey 2.27에서 실행 됨) 작동하지 않습니다 .

<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 사용).


0

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() {
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.