在 Jersey 2 + Spring 中使用 JSR-330 注释

Using JSR-330 annotations with Jersey 2 + Spring

我一直在尝试将 Spring 4 与 Jersey 2 一起使用,并注意到使用 jersey-spring3 扩展无法使 @Named 由 Spring 管理的注释资源。它们必须用 @Component 注释才能由 Spring 管理。

如果资源用 @Named 注释,HK2 似乎 "take over" 管理该资源。

资源

import com.example.jersey.spring.Greeting;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Named
@Singleton
@Path("resource")
public class Resource {

    private static final Logger logger = Logger.getLogger("Resource");

    public void init() {
        logger.info("Creating -> " + this + " injected with -> " + greeting);
    }

    @Inject
    private Greeting greeting;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        logger.info("Working on " + this + " Greeting " + greeting);
        return "Got it!";
    }
}

具有以下Spring applicationContext

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" 
   default-init-method="init">

    <context:component-scan base-package="com.example.jersey.webapp"/>
    <bean id="greeting" class="com.example.jersey.spring.Greeting"/>
</beans>

导致在启动时打印以下日志消息

Oct 18, 2017 3:11:44 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Oct 18, 2017 3:11:44 PM com.example.jersey.webapp.Resource init
INFO: Creating -> com.example.jersey.webapp.Resource@6e199bab injected with -> com.example.jersey.spring.Greeting@533b3005
Oct 18, 2017 3:11:45 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 249 ms

在几次 GET 调用之后。

Oct 18, 2017 3:11:56 PM com.example.jersey.webapp.Resource getIt
INFO: Working on com.example.jersey.webapp.Resource@40328bbc Greeting com.example.jersey.spring.Greeting@533b3005
Oct 18, 2017 3:12:03 PM com.example.jersey.webapp.Resource getIt
INFO: Working on com.example.jersey.webapp.Resource@40328bbc Greeting com.example.jersey.spring.Greeting@533b3005

看来 Spring 确实创建了 bean,但那不是用于为请求提供服务的那个。但是,如果使用 Component 而不是 Named,则整个生命周期由 Spring.

管理

有没有办法使用标准 @Named 注释并确保 Spring 完全管理资源的生命周期?

我认为没有办法禁用 HK2。

从最新的 Jersey-2 Userguide:

the resources must themselves be managed by Spring, by annotating with @Component, @Service, @Controller or @Repository

Spring 建议使用更具体的注释 @Service@Controller@Repository.

来自Spring 4.3.12 Documentation §7.10.1

@Component and further stereotype annotations

The @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions as described in Section 20.2.2, “Exception translation”.

Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases, for example, in the persistence, service, and presentation layers, respectively. Therefore, you can annotate your component classes with @Component, but by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository, @Service, and @Controller may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice. Similarly, as stated above, @Repository is already supported as a marker for automatic exception translation in your persistence layer.