dropwizard 0.8.0-rc2, using jersey's HK2 to inject healthchecks, lifecycle Manageds etc.

1,744 views
Skip to first unread message

Natan Abolafya

unread,
Jan 22, 2015, 8:19:19 AM1/22/15
to dropwiz...@googlegroups.com
As I've been struggling to migrate our micro-services to 0.8.0-rc2, I've decided to (or am sort of forced to) migrate to HK2 from Guice.

Among a few challenges, there is one about dropwizard directly. I've been binding classes using

environment.jersey().register(new AbstractBinder() {
         
@Override
         
protected void configure() {
           
...
            bind
(MyService.class):
           
...
         
}
       
});
environment
.jersey().register(MyResource.class); //MyResource uses MyService

so my resources etc. can get their dependencies via @Inject.

There are some cases where our healthchecks and Lifecycle classes require those singleton service dependencies. Even without those specific dependencies, I'd prefer to stick with using dependency injection throughout the application..
However,
environment.healthchecks().register(HealthCheck) //Healtcheck also uses MyService
and 
environment.lifecycle().register(Managed)
accept instances, not classes; which means they are not injected through the DI framework.

With guice, I had access to the injector, hence I was handling it via
injector.getInstance(...)

But now I don't have access to the ServiceLocator of jersey, hence cannot create an instance of Healthcheck. I couldn't find a way to access jersey's ServiceLocator, probably also because it's not initialized until after Application.run() is run. 

I understand dropwizard is in a different context than jersey, and isn't utilizing hk2 directly itself. But this limits our dependency capabilities entirely. Unless I've misunderstood it all wrong :).


Creating my own ServiceLocator, and handling DI through that is an option but will fail when I start implementing my own AuthFactoryProvider because it requires dependencies from jersey (that's actually why we decided to migrate to HK2 in the end).

Any ideas how I can handle dependency injection on healthchecks etc.?

Vyacheslav Rusakov

unread,
Jan 22, 2015, 8:38:32 AM1/22/15
to dropwiz...@googlegroups.com
I did guice integration for 0.8 and find some hk-jersey tricks ;)

The earliest point to inject is feature:

I suggest you to do the same and register binder (guice module analog) inside your feature. Also store reference to service locator somewhere.

Look source (there are not much code), I suppose you'll find answers there. 
Ask me if you'll need any explanations


четверг, 22 января 2015 г., 19:19:19 UTC+6 пользователь Natan Abolafya написал:

Natan Abolafya

unread,
Jan 22, 2015, 9:41:00 AM1/22/15
to dropwiz...@googlegroups.com
Heh, I had actually read your comment on HK2 and how you spent a couple of weeks(days?) to integrate Guice :). Figured I could spend that time to migrate to HK2 so there would be only one DI framework within the application.

Given the challenges I've been facing, I might give up that idea and bridge Guice as you did though. Thanks.

Vyacheslav Rusakov

unread,
Jan 22, 2015, 10:18:32 AM1/22/15
to dropwiz...@googlegroups.com
I was thinking about staying with HK too. Carefully read all docs, looked code, but (as you read) it didn't convince me. 

In your case, if you ok with hk, you actually can still try to use it: by using feature, you'll get service locator and inside your binder you can 
create instances manually and init them with locator (serviceLocator.install(service)) + register in bootstrap.
Yes these objects will not be managed by hk but everything will be in one place.. after all who cares - DI bindings will be resolved, objects registered in bootstrap.. everyone happy.
In some corner cases with not yet available dependencies you can always use Provider or Factory to delay creation (i think this will work in hk, even if service is not yet registered, hk is much less restrictive than guice) 

You should not have problems with AuthFactoryProvider implementation. If you register it as you shown above (using binder), all dependencies should be resolved correctly.
I suppose all your problems was only because of custom locator.

In fact, custom service locator usage is possible, but in too hacky way (https://github.com/Squarespace/jersey2-guice).

p.s. yep it was two weeks, bit ofc not full time, just evenings. Integration prototypes was too clumsy at first, so have to search and experiment until found all I need

четверг, 22 января 2015 г., 20:41:00 UTC+6 пользователь Natan Abolafya написал:

Natan Abolafya

unread,
Jan 23, 2015, 7:25:44 AM1/23/15
to dropwiz...@googlegroups.com
I don't understand how to link Feature to bootstrap. We're talking about java.ws.rs.core.Feature, right? And I will register that to environment.jersey(), which is in run method already. How can I take the instantiated object I need from the future and put it in environment.healthchecks()? I'm probably missing a point, that'd be great if you could point me to some code.

Natan Abolafya

unread,
Jan 23, 2015, 10:32:53 AM1/23/15
to dropwiz...@googlegroups.com
FYI tried this; it creates the correct objects and assigns to lifecycleEnvironment but it doesn't work because lifecycles objects are started before jersey is initialized. Also, the code is horrible :)

    environment.jersey().register(new AbstractBinder() {
     
@Override
     
protected void configure() {

        bind
(environment.lifecycle()).to(LifecycleEnvironment.class);
        bind
(MyManagedService.class).to(MyManagedService.class);
     
}
   
});
    environment
.jersey().register(LifecycleFeature.class);
 
}


 
public static class LifecycleFeature implements Feature{
   
private final ServiceLocator serviceLocator;
   
private final LifecycleEnvironment lifecycleEnvironment;


   
@Inject
   
private LifecycleFeature(ServiceLocator serviceLocator, LifecycleEnvironment lifecycleEnvironment) {
     
this.serviceLocator = serviceLocator;
     
this.lifecycleEnvironment = lifecycleEnvironment;
   
}


   
@Override
   
public boolean configure(FeatureContext context) {
      lifecycleEnvironment
.manage(serviceLocator.getService(MyManagedService.class));
     
return true;
   
}
 
}

and here is how a Managed service looks like.

@Singleton
public class MyManagedService implements Managed {

 
private MyService myService;

 
@Inject
 
public MyManagedService (MyService myService) {
   
 this.myService = myService;
 
}


 
@Override
 
public void start() throws Exception {
   
myService.doStuff();
    // This is never run.
 
}


 
@Override
 
public void stop() throws Exception {
    myService
.doOtherStuff();
 
}
}

As I've said MyService class is a singleton being used by different classes; and in some cases it also has dependencies to other singleton classes; so I cannot cheat and instantiate MyService class just to make this scenario work. I mean I would if I could but the application would end up half DI managed, half self managed.

Vyacheslav Rusakov

unread,
Jan 24, 2015, 8:16:04 AM1/24/15
to dropwiz...@googlegroups.com
Sorry I was sure feature is resolved before managed processing.
I did small prototype and now I see there is no way to use hk bean as Managed (more correctly, to use hk dependencies in managed object). 

The only thing I can suggest is to use @PostConstruct and @PreDestroy annotations. It's spring way, but at least it works.


пятница, 23 января 2015 г., 21:32:53 UTC+6 пользователь Natan Abolafya написал:

Yun Zhi Lin

unread,
Jan 28, 2015, 5:46:02 AM1/28/15
to dropwiz...@googlegroups.com
There is currently a PR https://github.com/HubSpot/dropwizard-guice/pull/45 in https://github.com/HubSpot/dropwizard-guice project which uses SquareSpace's jersey2-guice library.

I'm no the author of the PR but I've contributed a comprehensive suite of unit/integration tests which covers most functionalities, including the tricky Just-In-Time bindings. My company is also using this implementation in our Microservices and has been working quite well. If you are having issues with HK2 it may be worthwhile to take a look at this PR and give feedback.

Yun Zhi Lin

unread,
Jan 28, 2015, 6:01:28 AM1/28/15
to dropwiz...@googlegroups.com
Back to the original question, the Dropwizard Jersey ServiceLocator can be obtained by calling the following: 

((ServletContainer) environment.getJerseyServletContainer()).getApplicationHandler().getServiceLocator()

You'll find it's the same ServiceLocator that gets injected into various other Dropwizard modules such as AuthFactoryProvider.

Vyacheslav Rusakov

unread,
Jan 28, 2015, 8:57:57 AM1/28/15
to dropwiz...@googlegroups.com
Unfortinately this will not help with managed objects, because dropwizard call managed objects just before jersey start.
So currently it's impossible to use hk beans as managed objects.

Thank you for the link, glad to see dropwizard-guice will support 0.8 soon.

среда, 28 января 2015 г., 17:01:28 UTC+6 пользователь Yun Zhi Lin написал:

Bernd Hoffmann

unread,
May 25, 2015, 2:33:31 PM5/25/15
to dropwiz...@googlegroups.com
Is there meanwhile a way to use hk2 managed objects for with dropwizard healthchecks and / or dropwizard managed objects?
Reply all
Reply to author
Forward
0 new messages