Jersey 2.x에 내장된 의존성 주입 기능 사용하기
Jersey는 Java의 REST 웹 서비스 표준인 JAX-RS의 레퍼런스 구현체입니다. Spring의 무거움이나 서블릿을 직접 쓸때의 번거로움이 덜해서 자주 사용하고 있습니다. 특히 Jersey와 몇몇 라이브러리의 통합을 제공하는 Dropwizard를 쓰면 REST 서비스를 빠르게 만들 수 있습니다.
Jersey 1.x에서는 Guice와의 연동을 지원했는데 2.0 이후에는 HK2라는 의존성 주입 프레임워크를 내장하게 되면서 다른 의존성 주입 라이브러리와는 통합이 쉽지 않게 되었습니다. Dropwizard도 0.8.0부터는 Jersey 2.x를 사 용하고 있기 때문에 뭔가 대책이 필요했습니다. jersey2-guice 같은 해결책도 있지만 그냥 HK2를 그대로 써도 되지 않을까 해서 조사를 해보았습니다.
리소스에 의존성 주입
TwitterClient
라는 인터페이스가 있다고 가정해봅시다. 리소스 클래스의 생성자에 javax.inject.Inject 어노테이션을 붙여서 객체를 주입할 수 있습니다.
@Path("/tweets")
public class TweetsResource {
private final TwitterClient twitterClient;
@Inject
public TweetsResource(TwitterClient twitterClient) {
this.twitterClient = twitterClient;
}
// ...
}
Guice와 별로 다를 것은 없습니다. 해보진 않았지만 아마 setter/field 인젝션도 가능할겁니다.
바인딩 설정
Jersey에서는 일반적으로 ResourceConfig 객체에 리소스를 등록합니다. (Dropwizard에서는 Environment#jersey()
를 통해 얻을 수 있습니다.)
ResourceConfig config = new ResourceConfig();
config.register(TweetsResource.class);
마찬가지로 바인딩 설정 또한 ResourceConfig
에 등록할 수 있습니다. Guice의 AbstractModule
과 유사한 AbstractBinder를 상속받고 바인딩 DSL을 사용해서 설정할 수 있습니다.
config.register(new AbstractBinder() {
// ...
});
HK2의 바인딩 DSL도 Guice와 상당히 비슷한데, HK2는 구현이 앞에 오고 인터페이스가 뒤에 온다는 차이가 있습니다. (HK2의 용어로는 인터페이스 = contract, 구현 = service입니다.)
bind(new TwitterClientImpl()).to(TwitterClient.class)
: TwitterClientImpl 인스턴스를 TwitterClient 인터페이스에 바인딩bind(TwitterClientImpl.class).to(TwitterClient.class)
: TwitterClient 인터페이스의 구현 클래스로 TwitterClientImpl을 바인딩 (주입 시마다 새로 인스턴스 생성)bind(TwitterClientImpl.class).to(TwitterClient.class).in(Singleton.class)
: TwitterClient 인터페이스의 구현 클래스로 TwitterClientImpl을 바인딩 (주입 시 하나의 싱글턴 인스턴스 공유)bindAsContract(TwitterClientImpl.class)
:bind(TwitterClientImpl.class).to(TwitterClientImpl.class)
와 같습니다.
그 밖에도 bindFactory 같은 것들이 제공되는데 HK2 문서가 그다지 친절하지 않아서 완전히 파악하지는 못했지만 웬만하면 문제는 없을 것 같습니다.