JAX-RS依赖注入

时间:2016-11-15 07:08:22

标签: java java-ee dependency-injection jersey jax-rs

我使用Spring Rest完成了项目。现在我们有一个小型休息项目,并计划与Jersey JAX-RS合作。我是新手,并引用SO和其他博客来成功实现具有依赖注入的Rest api。

拥有以下代码。

AppConfig.java

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class AppConfig extends Application {    
    @Override
    public Set<Class<?>> getClasses() {
        System.out.println("AppConfig");
        final Set<Class<?>> s = new HashSet<Class<?>>();
        s.add(Controller.class);
        s.add(AppFeature.class);
        return s;
    }
}

AppBinder.java

import org.glassfish.hk2.utilities.binding.AbstractBinder;

public class AppBinder extends AbstractBinder {
    @Override
    protected void configure() {
        System.out.println("AppBinder");
        bind(ReflectionService.class).to(ReflectionService.class);
    }
}

AppFeature.java

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

public class AppFeature implements Feature {
    @Override
    public boolean configure(FeatureContext context) {
        System.out.println("AppFeature");
        context.register(new AppBinder());
        return true;
    }
}

Controller.java

@Path("/")
public class Controller {   
    @Inject
    Service service;    
    public Controller(){
        System.out.println("Controller created");
    }
    // other methods
}

Service.java

@Singleton
public class Service    
    public Service(){
        System.out.println("Service instance created");
    }
    // other methods
}

我假设Controller和Service的每个实例都是在 Tomcat 8 服务器启动时创建的,并且完成了依赖注入。但在启动期间,在控制台上得到了这个

  

信息:注册名为的Jersey servlet应用程序   com.sample.auto2.AppConfig,在servlet映射/ *上,带有   同名的应用程序类。

     

的AppConfig

     

的AppConfig

     

2016年11月15日下午12:22:20 org.glassfish.jersey.server.ApplicationHandler初始化   信息:启动Jersey应用程序,版本泽西:2.6 2014-02-18   21时52分53秒...

     

AppFeature

     

AppBinder

     

2016年11月15日下午12:22:21   org.apache.catalina.startup.HostConfig deployDirectory

每次,我们发送请求,在控制台中获得以下内容

  

已创建服务实例

     

创建控制器

我的问题

  1. 每当我们发送一个服务器时,都会调用Controller构造函数 http请求;它是在每个请求中创建实例还是仅创建实例 调用构造函数?
  2. 为什么 AppConfig 中的System.out被调用两次?
  3. 有没有更好的方法来设置我的小项目,它没有任何数据库访问权限,只有三个帖子端点?
  4. 修改

    根据@Harikrishnan提供的链接,为@Singleton课程添加了Controller。现在构造函数只调用一次(在第一次请求时 - 为什么不在服务器启动期间!!)。

    但是为什么Service类构造函数调用每个请求(在将@Singleton添加到Controller之前的早期),即使它是单例?还有其他问题。

    编辑2

    谢谢@peeskillet。所以这些是我的结果。

    1. 这在第一次请求时只调用一次构造函数

      bind(ReflectionService.class).to(ReflectionService.class).in(Singleton.class);
      bind(Controller.class).to(Controller.class).in(Singleton.class);
      
    2. 这会在http请求中给出错误

      bind(ReflectionService.class).to(ReflectionService.class).in(Immediate.class);
      
      java.lang.IllegalStateException: Could not find an active context for org.glassfish.hk2.api.Immediate
      

      但没关系,因为

    3. 这个在服务器启动时调用的构造函数只有一次

      bind(new ReflectionService()).to(ReflectionService.class);
      bind(new Controller()).to(Controller.class);
      
    4. 这样,在启动时完成注入,但在http请求上有404错误。 (思想控制器在AppBinder中配置,然后在AppConfig中配置)

      @ApplicationPath("/")
      public class AppConfig extends ResourceConfig  {    
          public AppConfig() {
              register(new AppBinder());
          }
      }
      
    5. 这就像你说的那样让它运行!

      @ApplicationPath("/")
      public class AppConfig extends ResourceConfig  {        
          public AppConfig() {
              register(new AppBinder());
              register(Controller.class);
          }
      }
      
    6. 最后这些都是我需要的

      public class AppBinder extends AbstractBinder {
          @Override
          protected void configure() {
              bind(new ReflectionService()).to(ReflectionService.class);
              bind(new Controller()).to(Controller.class);
          }
      }
      
      @ApplicationPath("/")
      public class AppConfig extends ResourceConfig  {    
          public AppConfig() {
              register(new AppBinder());
              register(Controller.class);
          }
      }
      

2 个答案:

答案 0 :(得分:3)

  

每当我们发送http请求时,都会调用服务,Controller构造函数;它是在每个请求中创建实例还是只调用构造函数?

不幸的是,@Singleton在使用AbstractBinder绑定时没有任何效果。我们需要明确地说它应该是一个单身人士

bind(ReflectionService.class).to(ReflectionService.class).in(Singleton.class);

默认行为是“每个查找”范围,这意味着每次请求服务时都会创建一个新实例

  

(在第一次请求时 - 为什么不在服务器启动期间!!)

这是它的工作原理。还有ImmediateScope,这将导致它在启动时创建

 bind(ReflectionService.class).to(ReflectionService.class).in(ImmediateScope.class)

或者您可以只使用实例而不是类,它将自动成为单例

bind(new ReflectionService()).to(ReflectionService.class)
  

每当我们发送http请求时,都会调用服务,Controller构造函数;它是在每个请求中创建实例还是只调用构造函数?

这是默认行为。每个请求的资源类的新实例。如上所述,如果您只想要一次实例,请将其标记为@Singleton

  

为什么AppConfig中的System.out被调用两次?

不确定,可能只需要在bootstrap上进行Jersey内部处理

  

有没有更好的方法来设置我的小项目,它没有任何数据库访问权限,只有三个帖子端点?

您的设置很好,但如果您使用的是Jersey,则应使用ResourceConfigApplication)扩展名而不是Application

@ApplicationPath("/")
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        register(new AppBinder());
        register(Controller.class);
    }
}

有了这个,您无需将AppBinder包裹在AppFeature中。泽西岛已经知道如何处理AppBinder

答案 1 :(得分:0)

默认情况下,Jersey会为每个请求创建一个新的资源类实例。因此,如果您没有注释Jersey资源类,它会隐式使用@RequestScoped范围

请阅读https://stackoverflow.com/a/20505899/721597

另请参阅Jersey 2 singleton dependency injection creates multiple instances