Hi,
I recently made a change to add a new mechanism for injecting dependencies into
tasks. Previously, to inject services into a task instance we were using either:
1. getServices().get(Type) or
2. constructor injection.
One downside with #1 is that the approach not declarative, so we can’t figure
out statically which services a task is going to use, or when. This is
important in order for us to determine things like the possible inputs and
outputs of the task, or to do any early validation, or deal with services that
require some work to make usable, and so on.
Approach #2 addresses this issue (mostly), but has a couple of downsides of its
own. Firstly, for good or bad, we currently make the task types public and
allow them to be subclassed. This means that the implementation services are
exposed to subtypes and we can’t change the set of services without changing
the constructor - thereby breaking backwards compatibility.
Secondly, approach #2 requires that all the services be created when the task
is created, regardless of whether the task or service is ever required. The
services are also retained for the entire life of the task object. This has a
noticeable impact on performance and heap usage in particular. This was the
main motivation for the change.
The ‘proper’ solution here is to separate out the configuration and the
implementation pieces of a task, and defer creation of the implementation
stuff, and the services it needs, until execution time. This will be part of
the solution to allow tasks from a given project to execute in parallel.
In the meantime, and for legacy tasks, there is a new mechanism to inject
services that addresses the downsides of #1 and #2 above. To use this, define a
getter annotated with @Inject:
@Inject
protected MyService getMyService() { … doesn’t matter what goes in here ... }
When decorated, this method is replaced with a service lookup. The lookup is
lazy, so that the service is not created until the getter is called.
This mechanism is considered incubating at this stage. It only works for tasks
for now, but would probably be useful for all decorated types (and plugins,
which aren’t decorated yet).
--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com
Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA:
http://www.gradlesummit.com