问题
First of all, this is not opinionated question and I have read most of related questions in SO. I am seeking advise if below implemented solution is the right approach/method.
I have read many tutorials on how to implement DI in a jersey-based
webapp and most of them recommend that its a must to create a beans.xml
in WEB-INF/*
in order to enable CDI but, I wonder if using Jersey's AbstractBinder
achieve the same result?
I have a jersey-webapp that has the following in web.xml
<servlet>
<servlet-name>Test Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.config.AppConfig</param-value>
</init-param>
And com.test.config.AppConfig
as follow
public class AppConfig extends ResourceConfig {
public AppConfig() {
AbstractBinder binder = new AbstractBinder() {
@Override
protected void configure() {
bind(Impl.class).to(Interface.class).in(Singleton.class);
}
};
register(binder);
register(MultiPartFeature.class);
packages("..."); //packages
}
}
and then I annotate the interfaces and the implementation gets injected
@Inject
private SomeInterface someInterface;
Above works just fine. Whatever that I want to be injected, I include it in the binder
and then specify an injection point
and it gets injected.
There is no beans.xml
in WEB-INF/
directory and I wonder if using AbstractBinder
inside AppConfig
that extends ResourceConfig
eliminate the need to declare beans.xml
?
Adding beans.xml
would probably enable scanning of classes that would pave the way for DI when we annotate classes with @Component
or @ManagedBean
.
Regardless, I would be happy to hear your feedback/advise/suggestions/recommendations on whether to
- Stick with existing solution (shown above) for DI in Jersey because .... ?
- Switch to annotating classes (that needs to be injected) and use annotation-discovery of
beans.xml
because ... ? - Jersey uses
HK2
by default, is it worth using a different DI container or HK2 is good enough? - What is your view on Jersey's Spring DI in comparison with JavaEE 6 CDI only for DI purposes?
There are many tutorials stating that CDI is not supported by Tomcat? but worked above using AbstractBinder
and I guess its because I programmatically bind? Any comments.
回答1:
I do not have a clear answers and possibly there doesn't exist a correct one. Not least because Weld SE support was introduced in version 2.15 of Jersey and this certainly not without any reason. But I would like to give it a try:
- The shown solution works fine for non-complex project structures but declaring every single binding might not be the best solution
- You don't need to use
beans.xml
. Annotations and auto-binding works fine with some additional effort (see below) - I'm not sure about this, but would say Weld seems to be more advanced. And of course you could mix CDI with some effort.
- (no answer here)
Here the example, which I think could be interesting:
Dependencies (Maven):
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-metadata-generator</artifactId>
<version>2.5.0-b05</version> <!-- HK2 version int. used by Jersey 2.23.2 -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
An application event listener:
import org.glassfish.hk2.api.*;
import org.glassfish.jersey.server.*;
@Provider
public class ApplicationListener implements ApplicationEventListener {
@Inject ServiceLocator serviceLocator;
@Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
onInitFinished();
break;
case DESTROY_FINISHED:
case INITIALIZATION_APP_FINISHED:
case INITIALIZATION_START:
case RELOAD_FINISHED:
default:
break;
}
}
@Override
public RequestEventListener onRequest(RequestEvent requestEvent) { return null; }
public void onInitFinished() {
populate(serviceLocator);
}
private void populate(ServiceLocator serviceLocator) {
DynamicConfigurationService dcs = serviceLocator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
populator.populate();
} catch (IOException | MultiException e) {
throw new MultiException(e);
}
}
}
A contract:
import org.jvnet.hk2.annotations.Contract;
@Contract
public interface ExampleService {
void executeSomething();
}
One or more services:
import javax.inject.Named;
import org.jvnet.hk2.annotations.Service;
@Service
@Named("bar")
public class BarService implements ExampleService {
@Override
public void executeSomething() { /* doBar */ }
}
Usage:
@Path("/")
public class TestResource {
// either ...
@Inject
@Named("bar")
private ExampleService bar;
// or ...
@Inject
private IterableProvider<ExampleService> services;
}
Just an option to get rid of beans.xml
(which I've never used or have seen) or declaration within ResourceConfig
, but it might find interested parties :)
Additionally, it seems like Jersey 3.0 is comming ^^
Have a nice day!
来源:https://stackoverflow.com/questions/39003933/dependency-injection-using-cdi-with-jersey-with-without-abstract-binding