Creating a new injector, with new bindings, but keep all singletons?

67 views
Skip to first unread message

Kevin Burton

unread,
Oct 19, 2014, 12:47:26 AM10/19/14
to google...@googlegroups.com
Long story short, I've painted myself into a corner.

I was creating new modules and a new injector in some code each time a service started.

The problem is I need to keep state by moving over singletons to the new injector.

The problem is, some of these bindings are now changes and possibly replaced.

Is it possible to migrate all existing singletons to a new injector with new bindings?

Nate Bauernfeind

unread,
Oct 19, 2014, 8:49:58 AM10/19/14
to google...@googlegroups.com
It sounds like you might want to use a childInjector pattern here. Structure it something like this:

Global Injector binds everything that is truly a singleton in your project. Then in the service(s) where you want to be able to set some state and create a new object that references the global state create a childInjector.

It's possible I don't completely understand your use case. Though, I think this should help you do what you want.

Nate

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-guice/bcb4d057-1685-409e-ae6b-b66913d6464e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kevin Burton

unread,
Oct 19, 2014, 10:46:21 AM10/19/14
to google...@googlegroups.com
This is my understanding as well...

However, my problem is that if I update the bindings , say by replacing one with a new binding, then when I create the child injector it fails because that binding was "already configured"

I replace bindings because during init various systems changes.  For example, I have a bunch of threads for one task then a bunch of threads for another. I have a 'Caller' that I use and change so that HTTP requests can be logged based on which task performed the request.  

I guess one strategy would be to call getAllBindings on the injector and then find all singletons, then merge the singletons into the new binding by calling bind( Foo.class ).toInstance( ).. 

... I think that would work but there are edge cases I am probably missings.

Nate Bauernfeind

unread,
Oct 19, 2014, 11:13:54 AM10/19/14
to google...@googlegroups.com
I don't really understand how you aren't able to come up with a static set of singletons that you want to be changing at each type of request.

The solution that you're trying to take sounds like a terribly hard one to maintain. I advise you to look, seriously, into picking an alternative dependency injection pattern. I imagine that you're going to have a hard time debugging issues that arise from unexpected leakages between tasks/injectors.

If your application changes state dramatically based on the current task then you may really want to try and structure it that way. You can create a global injector for the infrastructure and all singletons that never, ever, change. Then for each task, create a new Module that binds singletons for that task only. Use that module to create a child injector off of your global injector. Then, when the task is over simply throw away the child injector to clean up the garbage (assuming you clear up any additional references for things you pull out of the injector).

Don't be afraid of duplicating some bindings if the objects depend on an interface being bound that might change per task. If you have a common set of duplications you can put them into a common module and either install that module in the task's module or create the child injector directly from the two modules.

Nate

Kevin Burton

unread,
Oct 19, 2014, 11:54:42 AM10/19/14
to google...@googlegroups.com
I'm aware that it's probably that I might need to refactor some things ... 

However, I'm not sure the ideal way to have certain bindings, without replacing them.

I have one binding, Caller, which is literally just a string explaining what root service called an object.

This way I can trace things like how an HTTP request originated.

By default, it's unknown... because any library should be able to perform an HTTP request if necessary.

However, I need to swap in a new one as I'm starting up certain tasks.

So if I have a Foo and a Bar task each should have its own Caller.  

And yes, you might be right...  I may need to rethink some of my bindings... some of these aren't completely obvious though.

Nate Bauernfeind

unread,
Oct 19, 2014, 12:55:25 PM10/19/14
to google...@googlegroups.com
Do you ever run two tasks simultaneously? If not, perhaps you can create a special provider that you can swap out the Caller where you're currently considering creating a new injector.

import com.google.inject.Provider;
import java.util.concurrent.atomic.AtomicReference;
 
public class CallerProvider implements Provider<Caller> {
private AtomicReference<Caller> caller;
 
public void set(Caller currentCaller) {
caller.set(currentCaller);
}
 
@Override
public Caller get() {
return caller.get();
}
}

Inject Provider<Caller> anywhere you need to know who the caller is (when logging, etc) and call .get() to get the current caller. Consider using a Provider<Optional<Caller>> or at least be careful of null pointer exceptions when Caller is not set.

Does this help you get to a solution? Are there other things you were hoping to replace by creating a new injector that doesn't fit into this pattern?


--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.

Stephan Classen

unread,
Oct 19, 2014, 2:49:50 PM10/19/14
to google...@googlegroups.com
You can also use custom scopes to change the returned instance depending on your logic.
This may be a little cleaner than having too much logic in the providers.
Reply all
Reply to author
Forward
0 new messages