I've done projects using Spring Rest. Now we have a small rest project and planning to do with Jersey JAX-RS. I'm new to this and referred SO and other blogs to successfully implement a Rest api with dependency injection.
Have following code.
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
}
I assume that each instance of Controller and Service is created on Tomcat 8 server startup and dependency injection is done. But during startup, got this on console
INFO: Registering the Jersey servlet application, named com.sample.auto2.AppConfig, at the servlet mapping /*, with the Application class of the same name.
AppConfig
AppConfig
Nov 15, 2016 12:22:20 PM org.glassfish.jersey.server.ApplicationHandler initialize INFO: Initiating Jersey application, version Jersey: 2.6 2014-02-18 21:52:53...
AppFeature
AppBinder
Nov 15, 2016 12:22:21 PM org.apache.catalina.startup.HostConfig deployDirectory
Each time, we send a request, got following in console
Service instance created
Controller created
My Questions
- Service,Controller constructors is being called whenever we send an http request; does it create instances in each request or just calling constructor?
- Why System.out in AppConfig is called twice?
- Is there a better way for setting up my small project, which does not have any db access and only three post endpoints?
EDIT:
As per the links provided by @Harikrishnan, added @Singleton
for Controller
class. Now the constructors called only once (at the very first request - Why not during server startup!!).
But why Service class constructor called on each request (earlier before adding @Singleton to Controller), even if its singleton? Also the other problems remain.
EDIT 2:
Thanks @peeskillet. So these are the results for me.
This called constructors only once at very first request
bind(ReflectionService.class).to(ReflectionService.class).in(Singleton.class); bind(Controller.class).to(Controller.class).in(Singleton.class);
This give the error on http request
bind(ReflectionService.class).to(ReflectionService.class).in(Immediate.class); java.lang.IllegalStateException: Could not find an active context for org.glassfish.hk2.api.Immediate
But it's ok, because
This called constructor on server startup and only once
bind(new ReflectionService()).to(ReflectionService.class); bind(new Controller()).to(Controller.class);
By this, injection done on startup, but 404 error on http request. (Thought Controller is configured in AppBinder, then why in AppConfig)
@ApplicationPath("/") public class AppConfig extends ResourceConfig { public AppConfig() { register(new AppBinder()); } }
And this make it run, as you said!
@ApplicationPath("/") public class AppConfig extends ResourceConfig { public AppConfig() { register(new AppBinder()); register(Controller.class); } }
FINALLY THESE ARE ALL I NEEDED
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);
}
}