我使用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
每次,我们发送请求,在控制台中获得以下内容
已创建服务实例
创建控制器
我的问题
修改
根据@Harikrishnan提供的链接,为@Singleton
课程添加了Controller
。现在构造函数只调用一次(在第一次请求时 - 为什么不在服务器启动期间!!)。
但是为什么Service类构造函数调用每个请求(在将@Singleton添加到Controller之前的早期),即使它是单例?还有其他问题。
编辑2 :
谢谢@peeskillet。所以这些是我的结果。
这在第一次请求时只调用一次构造函数
bind(ReflectionService.class).to(ReflectionService.class).in(Singleton.class);
bind(Controller.class).to(Controller.class).in(Singleton.class);
这会在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
但没关系,因为
这个在服务器启动时调用的构造函数只有一次
bind(new ReflectionService()).to(ReflectionService.class);
bind(new Controller()).to(Controller.class);
这样,在启动时完成注入,但在http请求上有404错误。 (思想控制器在AppBinder中配置,然后在AppConfig中配置)
@ApplicationPath("/")
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(new AppBinder());
}
}
这就像你说的那样让它运行!
@ApplicationPath("/")
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(new AppBinder());
register(Controller.class);
}
}
最后这些都是我需要的
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);
}
}
答案 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,则应使用ResourceConfig
(Application
)扩展名而不是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