Working with libraries like Seam, Guice and Spring I have become accustomed to dealing with variables within a scope. These libraries give you a handful of scopes and allow you to define your own. This is a very handy pattern for dealing with variable lifecycles and dependency injection.
I have been trying to identify where scoping is the proper solution, or where another solution is more appropriate (context variable, singleton, etc). I have found that if the scope lifecycle is not well defined it is very difficult and often failure prone to manage injections in this way.
I have searched on this topic but have found little discussion on the pattern. Is there some good articles discussing where to use scoping and what are required/suggested prerequisites for scoping?
I interested in both reference discussion or your view on what is required or suggested for a proper scope implementation. Keep in mind that I am referring to scoping as a general idea, this includes things like globally scoped singletons, request or session scoped web variable, conversation scopes, and others.
Edit:
Some simple background on custom scopes: https://stackoverflow.com/questions/9429221/google-guice-custom-scope/9435182#9435182
Some definitions relevant to above:
“scoping” – A set of requirements that define what objects get injected at what time. A simple example of this is Thread scope, based on a ThreadLocal. This scope would inject a variable based on what thread instantiated the class. Here's an example of this:
“context variable” – A repository passed from one object to another holding relevant variables. Much like scoping this is a more brute force way of accessing variables based on the calling code.
Example:
methodOne(Context context){
methodTwo(context);
}
methodTwo(Context context){
...
//same context as method one, if called from method one
}
“globally scoped singleton” – Following the singleton pattern, there is one object per application instance. This applies to scopes because there is a basic lifecycle to this object: there is only one of these objects instantiated.
Here's an example of a JSR330 Singleton scoped object:
@Singleton
public void SingletonExample{
...
}
usage:
public class One {
@Inject
SingeltonExample example1;
}
public class Two {
@Inject
SingeltonExample example2;
}
After instantiation:
one.example1 == two.example2 //true;
Best Answer
Limit the use of scopes or more concretely Use scopes for wiring only.
Used properly, scopes can reduce a lot of factory boiler plate. I use scopes to wire together sub-processes that may need access to its name and arguments. This is similar to the
RequestScope
s provided by Guice and Spring.But scopes are effectively a thread-local map of string to object. This is practically a Global Variable Depot. This is why I limit my scope usage.
This leads to the corollary:
Hide the scopes or more generally Hide your DI Framework
Because scopes (and DI frameworks) are essentially Global Variable Depots, I prefer to encapsulate the DIF such that the only thing that knows there is a DIF is the main method.
To do this, I define my own scope interface and my own ProcessFactory that I define within a Guice module.
Because of this, my process manager is free of references to Guice. In fact, it is little more than this method:
Here's the complete Guice module that binds and hides my use of a Guice. It implements my own ProcessScope and ProcessFactory interfaces. It binds @ProcessParameters so they can be injected and a few convienience objects as well (@ProcessName String and ProcessConfig).