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:
void run(final ProcessContext context) {
try {
this.scope.enter(context.processArgs());
this.factory.create(args.processName());
} finally {
this.scope.exit();
}
}
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).
public class ProcessRunnerModule extends AbstractModule {
private static final String PROCESS_RUN_SCOPE = "ProcessRunScope";
/**
* Objects of type Map<String, Object> parameterized by @ProcessParameters
* are injected in the ProcessRunScope
*/
static final Key<Map<String, Object>> PROCESS_PARAMETERS_KEY;
static {
final TypeLiteral<Map<String, Object>> MAP_TYPE = new TypeLiteral<Map<String, Object>>() {
};
PROCESS_PARAMETERS_KEY = Key.get(MAP_TYPE, ProcessParameters.class);
}
/**
* Wraps Guice scope to ProcessScope. Injects the @ProcessParameters into guice
*/
private static class GuiceScopeAdapter implements ProcessScope {
private final SimpleScope scope;
@Inject @SuppressWarnings("unused")
public GuiceScopeAdapter(@Named(PROCESS_RUN_SCOPE) SimpleScope scope) {
this.scope = scope;
}
@Override
public void enterScope(Map<String, Object> parameters) {
scope.enter();
scope.seed(PROCESS_PARAMETERS_KEY, parameters);
}
@Override
public void exitScope() {
scope.exit();
}
}
/**
* Processes are run and bound in @ProcessRunScope.
*/
protected void configure() {
final SimpleScope processRunScope = new SimpleScope();
bindScope(ProcessRunScope.class, processRunScope);
bind(SimpleScope.class)
.annotatedWith(Names.named(PROCESS_RUN_SCOPE))
.to(processRunScope);
}
/**
* This wraps Processes bound via MapBinder to a ProcessFactory
*/
@Provides @Singleton
ProcessFactory createProcessFactory(final Map<String, Provider<Process>> processFactories) {
log.info("Instantiating process factory", "known-processes", processFactories.keySet());
return new ProcessFactory() {
@Override
public Process create(final String name) {
return processFactories.get(name).get();
}
};
}
/**
* ProcessRunner does not know about Guice
*/
@Provides @Singleton
ProcessRunner createProcessRunner(
final ProcessScope processScope,
final ProcessFactory processFactory) {
return new ProcessRunner(processScope, processFactory);
}
/**
* Convienience: bind a @ProcessName extracted from the @ProcessParameters
*/
@Provides @ProcessName @ProcessRunScope
String bindProcessName(final @ProcessParameters Map<String, Object> params) {
return params.get(ProcessRunner.PROCESS_NAME_KEY).toString();
}
/**
* Convienience: bind a ProcessConfig wrapping the @ProcessParameters
*/
@Provides @ProcessRunScope
ProcessConfig createParamHelper(final @ProcessParameters Map<String, Object> params) {
return new ProcessConfig(params);
}
}
I'm wondering, why this was migrated. But anyway:
You shouldn't put everything in a base mojo. That practically makes reusing that code impossible. Just think of the mojo growing and you need to split that mojo up into separate classes. You can't do that if that code has a dependency on the base class of the mojo.
You should create services that provide the functionality you currently have in your base mojo. They are reusable and therefore accessible from other places.
As a general rule of thumb:
YAGNI - You aint gonna need a member declaration in a class that is only intendend to be used by deriving classes. How do you know that it is really used?
Best Answer
A
ThreadLocal
is what you want. However, in your situation, I think that you should go forSession
scoped variables.