Modified:
websites/production/tapestry/content/defining-tapestry-ioc-services.html
==============================================================================
--- websites/production/tapestry/content/defining-tapestry-ioc-services.html
(original)
+++ websites/production/tapestry/content/defining-tapestry-ioc-services.html
Wed Sep 20 12:29:16 2017
@@ -27,6 +27,14 @@
</title>
<link type="text/css" rel="stylesheet" href="/resources/space.css" />
+ <link href='/resources/highlighter/styles/shCoreCXF.css'
rel='stylesheet' type='text/css' />
+ <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet'
type='text/css' />
+ <script src='/resources/highlighter/scripts/shCore.js'
type='text/javascript'></script>
+ <script src='/resources/highlighter/scripts/shBrushJava.js'
type='text/javascript'></script>
+ <script>
+ SyntaxHighlighter.defaults['toolbar'] = false;
+ SyntaxHighlighter.all();
+ </script>
<link href="/styles/style.css" rel="stylesheet" type="text/css"/>
@@ -36,26 +44,13 @@
<div class="wrapper bs">
- <div id="navigation"><div class="nav"><ul class="alternate"><li><a
href="index.html">Home</a></li><li><a href="getting-started.html">Getting
Started</a></li><li><a href="documentation.html">Documentation</a></li><li><a
href="download.html">Download</a></li><li><a
href="about.html">About</a></li><li><a class="external-link"
href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a
href="community.html">Community</a></li><li><a class="external-link"
href="http://www.apache.org/security/">Security</a></li><li><a
class="external-link" href="http://www.apache.org/">Apache</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
-
-</div>
+ <div id="navigation"><div class="nav"><ul class="alternate"><li><a
href="index.html">Home</a></li><li><a href="getting-started.html">Getting
Started</a></li><li><a href="documentation.html">Documentation</a></li><li><a
href="download.html">Download</a></li><li><a
href="about.html">About</a></li><li><a class="external-link"
href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a
href="community.html">Community</a></li><li><a class="external-link"
href="http://www.apache.org/security/">Security</a></li><li><a
class="external-link" href="http://www.apache.org/">Apache</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
<div id="top">
- <div id="smallbanner"><div class="searchbox"
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999;
font-size: 90%">Tapestry docs, issues, wikis & blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get"
action="http://tapestry.apache.org/search.html">
- <input type="text" name="q">
- <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a href="index.html"><span
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image
confluence-external-resource"
src="http://tapestry.apache.org/images/tapestry_small.png"
data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1
id="SmallBanner-PageTitle">Defining Tapestry IOC Services</h1></div>
-
-</div>
+ <div id="smallbanner"><div class="searchbox"
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999;
font-size: 90%">Tapestry docs, issues, wikis & blogs:</span><form
enctype="application/x-www-form-urlencoded" method="get"
action="http://tapestry.apache.org/search.html">
+ <input type="text" name="q">
+ <input type="submit" value="Search">
+</form></div><div class="emblem" style="float:left"><p><a
href="index.html"><span class="confluence-embedded-file-wrapper"><img
class="confluence-embedded-image confluence-external-resource"
src="http://tapestry.apache.org/images/tapestry_small.png"
data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div
class="title" style="float:left; margin: 0 0 0 3em"><h1
id="SmallBanner-PageTitle">Defining Tapestry IOC Services</h1></div></div>
<div class="clearer"></div>
</div>
@@ -67,7 +62,8 @@
</div>
<div id="content">
- <div id="ConfluenceContent"><p>Services consist of two main
parts: a service interface and a service implementation.</p><p>The service
interface is how the service will be represented throughout the rest of the
registry. Since what gets passed around is normally a proxy, you can't expect
to cast a service object down to the implementation class (you'll see a
ClassCastException instead). In other words, you should be careful to ensure
that your service interface is complete, since Tapestry IoC effectively walls
you off from back doors such as casts.</p><h1
id="DefiningTapestryIOCServices-ServiceLifeCycle">Service Life
Cycle</h1><p>Every service has a very specific life cycle.</p><ul><li>Defined:
The service has a definition (from some module) but has not yet been
referenced.</li><li>Virtual: The service has been referenced, so a proxy for
the class has been created.</li><li>Realized: A method on the proxy has been
invoked, so the service implementation has been instan
tiated, and any decorators applied.</li><li>Shutdown: The entire Registry has
been shut down and with it, all the proxies have been
disabled.</li></ul><p>When the Registry is first created, all modules are
scanned and the definitions for all services are created.</p><p>Services will
be referenced by either accessing them using the Registry, or as dependencies
of other realized services.</p><p>Tapestry IoC waits until the last possible
moment to <em>realize</em> the service: that's defined as when a method of the
service is invoked. Tapestry is <em>thread-safe</em>, so even in a heavily
contested, highly threaded environment (such as a servlet container or
application server) things <em>Just Work</em>.</p><p><parameter
ac:name="">serviceBuilderMethod</parameter></p><h1
id="DefiningTapestryIOCServices-ServiceBuilderMethods">Service Builder
Methods</h1><p>Tapestry doesn't know how to instantiate and configure your
service; instead it relies on you to provide the code to do so, in a ser
vice builder method, a method whose name is (or starts with)
"build":</p><parameter ac:name="">java</parameter><plain-text-body>package
org.example.myapp.services;
+ <div id="ConfluenceContent"><p>Services consist of two main
parts: a service interface and a service implementation.</p><p>The service
interface is how the service will be represented throughout the rest of the
registry. Since what gets passed around is normally a proxy, you can't expect
to cast a service object down to the implementation class (you'll see a
ClassCastException instead). In other words, you should be careful to ensure
that your service interface is complete, since Tapestry IoC effectively walls
you off from back doors such as casts.</p><h1
id="DefiningTapestryIOCServices-ServiceLifeCycle">Service Life
Cycle</h1><p>Every service has a very specific life cycle.</p><ul><li>Defined:
The service has a definition (from some module) but has not yet been
referenced.</li><li>Virtual: The service has been referenced, so a proxy for
the class has been created.</li><li>Realized: A method on the proxy has been
invoked, so the service implementation has been instan
tiated, and any decorators applied.</li><li>Shutdown: The entire Registry has
been shut down and with it, all the proxies have been
disabled.</li></ul><p>When the Registry is first created, all modules are
scanned and the definitions for all services are created.</p><p>Services will
be referenced by either accessing them using the Registry, or as dependencies
of other realized services.</p><p>Tapestry IoC waits until the last possible
moment to <em>realize</em> the service: that's defined as when a method of the
service is invoked. Tapestry is <em>thread-safe</em>, so even in a heavily
contested, highly threaded environment (such as a servlet container or
application server) things <em>Just Work</em>.</p><p><span
class="confluence-anchor-link"
id="DefiningTapestryIOCServices-serviceBuilderMethod"></span></p><h1
id="DefiningTapestryIOCServices-ServiceBuilderMethods">Service Builder
Methods</h1><p>Tapestry doesn't know how to instantiate and configure your
service; instead it relies o
n you to provide the code to do so, in a service builder method, a method
whose name is (or starts with) "build":</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
public class MyAppModule
{
@@ -75,7 +71,9 @@ public class MyAppModule
{
return new IndexerImpl();
}
-}</plain-text-body><p>Here the service interface is Indexer (presumably inside
the org.example.myapp.services package, since there isn't an import). Tapestry
IoC doesn't know about the IndexerImpl class (the service implementation of the
Indexer service), but it does know about the build() method.</p><p>That's one
of the great innovations of Tapestry IoC: we don't try to encapsulate in XML or
annotations all the different ways possible to create a service; those things
are best expressed in Java code. For a simple case (as here), it would be hard
for external configuration (again, in XML or Java annotations) to be shorter
than "new IndexerImpl()".</p><p><em>The above paragraph was written before
Binding and Autobuilding were introduced.</em></p><p>For more complex and
realistic scenarios, such as injecting dependencies via the constructor, or
doing more interest work (such as registering the newly created service for
events published by some other service), the Java code is simply t
he most direct, flexible, extensible and readable approach.</p><h1
id="DefiningTapestryIOCServices-BindingandAutobuilding">Binding and
Autobuilding</h1><p>Tapestry IoC can also <em>autobuild</em> your service.
Autobuilding is the <em>preferred</em> way to instantiate your
services.</p><p>Every module may have an optional, static bind() method which
is passed a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBinder.html">ServiceBinder</a>.
Services may be registered with the container by "binding" a service interface
to a service implementation:</p><parameter
ac:name="">java</parameter><plain-text-body>package org.example.myapp.services;
+}</pre>
+</div></div><p>Here the service interface is Indexer (presumably inside the
org.example.myapp.services package, since there isn't an import). Tapestry IoC
doesn't know about the IndexerImpl class (the service implementation of the
Indexer service), but it does know about the build() method.</p><p>That's one
of the great innovations of Tapestry IoC: we don't try to encapsulate in XML or
annotations all the different ways possible to create a service; those things
are best expressed in Java code. For a simple case (as here), it would be hard
for external configuration (again, in XML or Java annotations) to be shorter
than "new IndexerImpl()".</p><p><em>The above paragraph was written before
Binding and Autobuilding were introduced.</em></p><p>For more complex and
realistic scenarios, such as injecting dependencies via the constructor, or
doing more interest work (such as registering the newly created service for
events published by some other service), the Java code is simply the most
direct, flexible, extensible and readable approach.</p><h1
id="DefiningTapestryIOCServices-BindingandAutobuilding">Binding and
Autobuilding</h1><p>Tapestry IoC can also <em>autobuild</em> your service.
Autobuilding is the <em>preferred</em> way to instantiate your
services.</p><p>Every module may have an optional, static bind() method which
is passed a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBinder.html">ServiceBinder</a>.
Services may be registered with the container by "binding" a service interface
to a service implementation:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.ServiceBinder;
@@ -85,7 +83,9 @@ public class MyAppModule
{
binder.bind(Indexer.class, IndexerImpl.class);
}
-}</plain-text-body><p>You can make repeated calls to ServiceBinder.bind(), to
bind additional services.</p><p>You might ask, "which is better, a builder
method for each service, or a bind() method for the module?" For simple
services, those that are just an instantiated instance with simple
dependencies, binding is better than building. That covers at least 90% of all
services, so bind away!</p><p>There are many cases, however, where constructing
a service is more than just instantiating a class. Often the new service will
(for example) be registered as a listener with some other service. In other
cases, the implementation of the service is generated at runtime. These are
where the service builder methods are most useful.</p><p>In terms of the
evolution of the framework, service builder methods came first, and
autobuilding was a later addition, inspired by the terseness of the <a
class="external-link" href="http://code.google.com/p/google-guice/"
rel="nofollow">Guice</a> IoC contai
ner.</p><p>Following the convention over configuration principle, the
autobuilding of services can be even less verbose. If a service interface is
passed as a single argument to the bind() method, Tapestry will try to find an
implementation in the same package whose name matches the name of the service
interface followed by the suffix <em>Impl</em>.</p><parameter
ac:name="">java</parameter><plain-text-body>package org.example.myapp.services;
+}</pre>
+</div></div><p>You can make repeated calls to ServiceBinder.bind(), to bind
additional services.</p><p>You might ask, "which is better, a builder method
for each service, or a bind() method for the module?" For simple services,
those that are just an instantiated instance with simple dependencies, binding
is better than building. That covers at least 90% of all services, so bind
away!</p><p>There are many cases, however, where constructing a service is more
than just instantiating a class. Often the new service will (for example) be
registered as a listener with some other service. In other cases, the
implementation of the service is generated at runtime. These are where the
service builder methods are most useful.</p><p>In terms of the evolution of the
framework, service builder methods came first, and autobuilding was a later
addition, inspired by the terseness of the <a class="external-link"
href="http://code.google.com/p/google-guice/" rel="nofollow">Guice</a> IoC
container.</p
><p>Following the convention over configuration principle, the autobuilding of
>services can be even less verbose. If a service interface is passed as a
>single argument to the bind() method, Tapestry will try to find an
>implementation in the same package whose name matches the name of the service
>interface followed by the suffix <em>Impl</em>.</p><div class="code panel
>pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.ServiceBinder;
@@ -95,25 +95,39 @@ public class MyAppModule
{
binder.bind(Indexer.class);
}
-}</plain-text-body><h1 id="DefiningTapestryIOCServices-ServiceIds">Service
Ids</h1><p>Every service will have a unique service id.</p><p>When using a
service builder method, the service id is the <em>simple name</em> of the
service interface.</p><p>This can be overridden by adding the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html">ServiceId</a>
annotation to the service builder method:</p><parameter
ac:name="">java</parameter><plain-text-body> @ServiceId("FileSystemIndexer")
+}</pre>
+</div></div><h1 id="DefiningTapestryIOCServices-ServiceIds">Service
Ids</h1><p>Every service will have a unique service id.</p><p>When using a
service builder method, the service id is the <em>simple name</em> of the
service interface.</p><p>This can be overridden by adding the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html">ServiceId</a>
annotation to the service builder method:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @ServiceId("FileSystemIndexer")
public static Indexer buildIndexer(@InjectService("FileSystem") FileSystem
fileSystem)
{
. . .
- }</plain-text-body><p>Another option is to add the service id to the method
name, after "build", for example:</p><parameter
ac:name="">java</parameter><plain-text-body> public static Indexer
buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem)
+ }</pre>
+</div></div><p>Another option is to add the service id to the method name,
after "build", for example:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer
buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem)
{
. . .
- }</plain-text-body><p>Here, the service id is "FileSystemIndexer" not
"Indexer".</p><p>For autobuilt services, the service id can be specified by
placing the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html">ServiceId</a>
annotation directly on a service implementation class.</p><parameter
ac:name="">java</parameter><plain-text-body> @ServiceId("FileSystemIndexer")
+ }</pre>
+</div></div><p>Here, the service id is "FileSystemIndexer" not
"Indexer".</p><p>For autobuilt services, the service id can be specified by
placing the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/ServiceId.html">ServiceId</a>
annotation directly on a service implementation class.</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @ServiceId("FileSystemIndexer")
public class IndexerImpl implements Indexer
{
...
- }</plain-text-body><p>When the service is bound, the value of the annotation
is used as id:</p><parameter ac:name="">java</parameter><plain-text-body>
binder.bind(Indexer.class, IndexerImpl.class);</plain-text-body><p>This id can
be overriden again by calling the method <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBindingOptions.html#withIdjava.lang.String">withId</a></p><parameter
ac:name="">java</parameter><plain-text-body> binder.bind(Indexer.class,
IndexerImpl.class).withId("FileSystemIndexer");</plain-text-body><h1
id="DefiningTapestryIOCServices-Injecting_DependenciesInjectingDependencies"><parameter
ac:name="">Injecting_Dependencies</parameter>Injecting
Dependencies</h1><p>It's pretty unlikely that your service will be able to
operate in a total vacuum. It will have other dependencies.</p><p>Dependencies
are provided to a service in one of several ways:</p><ul><li>As parameters to
the service builder method</li
><li>As parameters to the service implementation class' constructor (for
>autobuilt services)</li><li>As parameters passed to the constructor of the
>service's module class (to be cached inside instance
>variables)</li><li>Directly into fields of the service
>implementation</li></ul><p>For example, let's say the Indexer needs a
>JobScheduler to control when it executes, and a FileSystem to access files
>and store indexes.</p><parameter ac:name="">java</parameter><plain-text-body>
> public static Indexer build(JobScheduler scheduler, FileSystem fileSystem)
+ }</pre>
+</div></div><p>When the service is bound, the value of the annotation is used
as id:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> binder.bind(Indexer.class, IndexerImpl.class);</pre>
+</div></div><p>This id can be overriden again by calling the method <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBindingOptions.html#withIdjava.lang.String">withId</a></p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> binder.bind(Indexer.class,
IndexerImpl.class).withId("FileSystemIndexer");</pre>
+</div></div><h1
id="DefiningTapestryIOCServices-Injecting_DependenciesInjectingDependencies"><span
class="confluence-anchor-link"
id="DefiningTapestryIOCServices-Injecting_Dependencies"></span>Injecting
Dependencies</h1><p>It's pretty unlikely that your service will be able to
operate in a total vacuum. It will have other dependencies.</p><p>Dependencies
are provided to a service in one of several ways:</p><ul><li>As parameters to
the service builder method</li><li>As parameters to the service implementation
class' constructor (for autobuilt services)</li><li>As parameters passed to the
constructor of the service's module class (to be cached inside instance
variables)</li><li>Directly into fields of the service
implementation</li></ul><p>For example, let's say the Indexer needs a
JobScheduler to control when it executes, and a FileSystem to access files and
store indexes.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer build(JobScheduler scheduler,
FileSystem fileSystem)
{
IndexerImpl indexer = new IndexerImpl(fileSystem);
scheduler.scheduleDailyJob(indexer);
return indexer;
- }</plain-text-body><p>Tapestry assumes that parameters to builder methods
are dependencies; in this example it is able to figure out what services to
pass in based just on the type (later we'll see how we can fine tune this with
annotations, when the service type is not sufficient to identify a single
service).</p><p>This is an example of when you would want to use the service
builder method, rather than just binding the service interface to the
implementation class: because we want to do something extra, in this case,
register the new indexer service with the scheduler.</p><p>Note that we don't
invoke those service builder methods ... we just "advertise" (via naming
convention or annotation) that we need the named services. Tapestry IoC will
provide the necessary proxies and, when we start to invoke methods on those
proxies, will ensure that the full service, including its interceptors and its
dependencies, are ready to go. Again, this is done in a thread-safe
manner.</p><p>What
happens if there is more than one service that implements the JobScheduler
interface, or the FileSystem interface? You'll see a runtime exception, because
Tapestry is unable to resolve it down to a <em>single</em> service. At this
point, it is necessary to <em>disambiguate</em> the link between the service
interface and <em>one</em> service. One approach is to use the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a>
annotation:</p><parameter ac:name="">java</parameter><plain-text-body> public
static Indexer build(@InjectService("JobScheduler")
+ }</pre>
+</div></div><p>Tapestry assumes that parameters to builder methods are
dependencies; in this example it is able to figure out what services to pass in
based just on the type (later we'll see how we can fine tune this with
annotations, when the service type is not sufficient to identify a single
service).</p><p>This is an example of when you would want to use the service
builder method, rather than just binding the service interface to the
implementation class: because we want to do something extra, in this case,
register the new indexer service with the scheduler.</p><p>Note that we don't
invoke those service builder methods ... we just "advertise" (via naming
convention or annotation) that we need the named services. Tapestry IoC will
provide the necessary proxies and, when we start to invoke methods on those
proxies, will ensure that the full service, including its interceptors and its
dependencies, are ready to go. Again, this is done in a thread-safe
manner.</p><p>What happens i
f there is more than one service that implements the JobScheduler interface,
or the FileSystem interface? You'll see a runtime exception, because Tapestry
is unable to resolve it down to a <em>single</em> service. At this point, it is
necessary to <em>disambiguate</em> the link between the service interface and
<em>one</em> service. One approach is to use the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a>
annotation:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer
build(@InjectService("JobScheduler")
JobScheduler scheduler,
@InjectService("FileSystem")
@@ -124,7 +138,9 @@ public class MyAppModule
scheduler.scheduleDailyJob(indexer);
return indexer;
- }</plain-text-body><p>If you find yourself injecting the same dependencies
into multiple service builder (or service decorator) methods, you can <a
href="tapestry-ioc-modules.html">cache dependency injections</a> in your
module, by defining a constructor. This reduces duplication in your
module.</p><h1
id="DefiningTapestryIOCServices-DisambiguationwithMarkerAnnotations">Disambiguation
with Marker Annotations</h1><p>In the previous example we were faced with a
problem: multiple versions of the JobScheduler service. They had the same
service interface but unique service ids. If you try to inject based on type,
the service to inject will be ambiguous. Tapestry will throw an exception
(identifying the parameter type and the matching services that implement that
type).</p><p>The problem is that when injecting a JobScheduler into some other
service we need to know which <em>one</em> to inject. Rather than using the
service id, another approach is to use a <em>marker annotation</em>.</p
><p>You may optionally link a service implementation with a marker
>annotation.</p><p>For example, maybe you have one JobScheduler implementation
>where the jobs are spread across a number of nodes in a cluster, and you have
>another JobScheduler where the jobs are all executed exclusively in the
>current process.</p><p>We can associate those two JobSchedulers with two
>annotations.</p><parameter
>ac:name="">java</parameter><plain-text-body>@Target(
+ }</pre>
+</div></div><p>If you find yourself injecting the same dependencies into
multiple service builder (or service decorator) methods, you can <a
href="tapestry-ioc-modules.html">cache dependency injections</a> in your
module, by defining a constructor. This reduces duplication in your
module.</p><h1
id="DefiningTapestryIOCServices-DisambiguationwithMarkerAnnotations">Disambiguation
with Marker Annotations</h1><p>In the previous example we were faced with a
problem: multiple versions of the JobScheduler service. They had the same
service interface but unique service ids. If you try to inject based on type,
the service to inject will be ambiguous. Tapestry will throw an exception
(identifying the parameter type and the matching services that implement that
type).</p><p>The problem is that when injecting a JobScheduler into some other
service we need to know which <em>one</em> to inject. Rather than using the
service id, another approach is to use a <em>marker annotation</em>.</p><p>You m
ay optionally link a service implementation with a marker
annotation.</p><p>For example, maybe you have one JobScheduler implementation
where the jobs are spread across a number of nodes in a cluster, and you have
another JobScheduler where the jobs are all executed exclusively in the current
process.</p><p>We can associate those two JobSchedulers with two
annotations.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">@Target(
{ PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@@ -150,7 +166,9 @@ public class MyModule
binder.bind(JobScheduler.class,
ClusteredJobSchedulerImpl.class).withId("ClusteredJobScheduler").withMarker(Clustered.class);
binder.bind(JobScheduler.class,
SimpleJobSchedulerImpl.class).withId("InProcessJobScheduler").withMarker(InProcess.class);
}
-}</plain-text-body><p>Notice that the marker annotations have no attributes.
Further, we support markers on fields (for use in Tapestry components) as well
as parameters.</p><p>To get the right version of the service, you use one of
the annotations:</p><parameter
ac:name="">java</parameter><plain-text-body>public class MyServiceImpl
implements MyService
+}</pre>
+</div></div><p>Notice that the marker annotations have no attributes. Further,
we support markers on fields (for use in Tapestry components) as well as
parameters.</p><p>To get the right version of the service, you use one of the
annotations:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class MyServiceImpl implements MyService
{
private final JobScheduler jobScheduler;
@@ -160,11 +178,15 @@ public class MyModule
}
. . .
-} </plain-text-body><p>The @Clustered annotation on the parameter is combined
with the parameter type (JobScheduler) to find the exact service
implementation.</p><p>Why is this better than using the service id? It's more
refactoring-safe. Service ids can change, which can break your services.
However, using an IDE to rename or move an annotation class or service
interface will be able to update all the uses of the annotation or
interface.</p><p>With a service builder method, you use the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Marker.html">Marker</a>
annotation:</p><parameter ac:name="">java</parameter><plain-text-body>
@Marker(Clustered.class)
+} </pre>
+</div></div><p>The @Clustered annotation on the parameter is combined with the
parameter type (JobScheduler) to find the exact service
implementation.</p><p>Why is this better than using the service id? It's more
refactoring-safe. Service ids can change, which can break your services.
However, using an IDE to rename or move an annotation class or service
interface will be able to update all the uses of the annotation or
interface.</p><p>With a service builder method, you use the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Marker.html">Marker</a>
annotation:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @Marker(Clustered.class)
public JobScheduler buildClusteredJobScheduler()
{
return . . .;
- }</plain-text-body><p>The @Marker annotation may also be placed on an
implementation class, which means that you may omit the call to withMarker()
inside the bind() method.</p><p>Finally, the point of injection may have
multiple marker annotations; only services that are marked with <em>all</em>
those markers will be considered for injection. Each marker annotation creates
an increasingly narrow subset from the set of all possible services (compatible
with the indicated dependency type).</p><h1
id="DefiningTapestryIOCServices-LocalDependencies">Local Dependencies</h1><p>A
special marker interface, @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Local.html">Local</a>,
indicates a dependency that should only be resolved using services from within
<em>the same module</em>.</p><p>@Local can also be combined with other marker
annotations.</p><h1
id="DefiningTapestryIOCServices-InjectingDependenciesforAutobuiltServices">In
jecting Dependencies for Autobuilt Services</h1><p>With autobuilt services,
there's no service builder method in which to specify
injections.</p><p>Instead, the injections occur on <em>constructor</em> for the
implementation class:</p><parameter
ac:name="">java</parameter><plain-text-body>package org.example.myapp.services;
+ }</pre>
+</div></div><p>The @Marker annotation may also be placed on an implementation
class, which means that you may omit the call to withMarker() inside the bind()
method.</p><p>Finally, the point of injection may have multiple marker
annotations; only services that are marked with <em>all</em> those markers will
be considered for injection. Each marker annotation creates an increasingly
narrow subset from the set of all possible services (compatible with the
indicated dependency type).</p><h1
id="DefiningTapestryIOCServices-LocalDependencies">Local Dependencies</h1><p>A
special marker interface, @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Local.html">Local</a>,
indicates a dependency that should only be resolved using services from within
<em>the same module</em>.</p><p>@Local can also be combined with other marker
annotations.</p><h1
id="DefiningTapestryIOCServices-InjectingDependenciesforAutobuiltServices">Injecting
D
ependencies for Autobuilt Services</h1><p>With autobuilt services, there's no
service builder method in which to specify injections.</p><p>Instead, the
injections occur on <em>constructor</em> for the implementation class:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.annotations.InjectService;
@@ -178,7 +200,9 @@ public class IndexerImpl implements Inde
}
. . .
-}</plain-text-body><p>If the class has multiple constructors, the constructor
with the <em>most</em> parameters will be invoked. Alternately, you may mark a
single constructor with the Inject annotation, and Tapestry will use
<em>that</em> constructor specifically, ignoring all other
constructors.</p><p>Note how we are using final fields for our dependencies;
this is generally a Good Idea. These services will often execute inside a
multi-threaded environment, such as a web application, and the use of final
fields inside a constructor ensures that the fields will be properly published
(meaning, "visible to other threads") in accordance with the Java Memory
Model.</p><p>Once thing that is not a good idea is to pass in another service,
such as JobScheduler in the previous example, and pass <code>this</code> from a
constructor:</p><parameter ac:name="">java</parameter><plain-text-body>package
org.example.myapp.services;
+}</pre>
+</div></div><p>If the class has multiple constructors, the constructor with
the <em>most</em> parameters will be invoked. Alternately, you may mark a
single constructor with the Inject annotation, and Tapestry will use
<em>that</em> constructor specifically, ignoring all other
constructors.</p><p>Note how we are using final fields for our dependencies;
this is generally a Good Idea. These services will often execute inside a
multi-threaded environment, such as a web application, and the use of final
fields inside a constructor ensures that the fields will be properly published
(meaning, "visible to other threads") in accordance with the Java Memory
Model.</p><p>Once thing that is not a good idea is to pass in another service,
such as JobScheduler in the previous example, and pass <code>this</code> from a
constructor:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.annotations.InjectService;
@@ -196,7 +220,9 @@ public class IndexerImpl implements Inde
}
. . .
-}</plain-text-body><p>Understanding why this is a bad idea involves a long
detour into inner details of the Java Memory Model. The short form is that
other threads may end up invoking methods on the IndexerImpl instance, and its
fields (even though they are final, even though they appear to already have
been set) may be uninitialized.</p><h1
id="DefiningTapestryIOCServices-FieldInjection">Field Injection</h1><p>The @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a>
and @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a>
annotations may be used on instance fields of a service implementation class,
as an alternative to passing dependencies of the service implementation in via
the constructor.</p><p>Note that only dependencies are settable this way; if
you want resources, including the service's <a href
="tapestry-ioc-configuration.html">configuration</a>, you must pass those
through the constructor. You <em>are</em> free to mix and match, injecting
partially with field injection and partially with constructor
injection.</p><p>Caution: injection via fields uses reflection to make the
fields accessible. In addition, it may not be as thread-safe as using the
constructor to assign to final fields.</p><parameter
ac:name="">java</parameter><plain-text-body>package org.example.myapp.services;
+}</pre>
+</div></div><p>Understanding why this is a bad idea involves a long detour
into inner details of the Java Memory Model. The short form is that other
threads may end up invoking methods on the IndexerImpl instance, and its fields
(even though they are final, even though they appear to already have been set)
may be uninitialized.</p><h1
id="DefiningTapestryIOCServices-FieldInjection">Field Injection</h1><p>The @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a>
and @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a>
annotations may be used on instance fields of a service implementation class,
as an alternative to passing dependencies of the service implementation in via
the constructor.</p><p>Note that only dependencies are settable this way; if
you want resources, including the service's <a href="tapes
try-ioc-configuration.html">configuration</a>, you must pass those through the
constructor. You <em>are</em> free to mix and match, injecting partially with
field injection and partially with constructor injection.</p><p>Caution:
injection via fields uses reflection to make the fields accessible. In
addition, it may not be as thread-safe as using the constructor to assign to
final fields.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.annotations.InjectService;
@@ -206,7 +232,13 @@ public class IndexerImpl implements Inde
private FileSystem fileSystem;
. . .
-}</plain-text-body><h1
id="DefiningTapestryIOCServices-ServiceScopeDefiningServiceScope"><parameter
ac:name="">ServiceScope</parameter>Defining Service Scope</h1><p>Each service
has a <em>scope</em> that controls when the service implementation is
instantiated. There are two built in scopes: "singleton" and "perthread", but
more can be added.</p><p>Service scope is specified using the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html">Scope</a>
annotation, which is attached to a builder method, or to the service
implementation class. When this annotation is not present, the default scope,
"singleton" is used.</p><h3
id="DefiningTapestryIOCServices-singleton">singleton</h3><p>Most services use
the default scope, "singleton". With this scope a <em>proxy</em> is created
when the service is first referenced. By reference, we mean any situation in
which the service is requested by name, such as using the @InjectSer
vice annotation on a service builder method, or by using the <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Registry.html">Registry</a>
API from outside the container.</p><p>In any case, the service proxy will only
create the service implementation when a method on the service interface is
invoked. Until then, the service can be thought of as "virtual". As the first
method is invoked, the service builder method is invoked, then any service
decorations occur. This construction process, called "realization", occurs only
once.</p><p>You should be aware when writing services that your code must be
thread safe; any service you define could be invoked simultaneously by multiple
threads. This is rarely an issue in practice, since most services take input,
use local variables, and invoke methods on other services, without making use
of non-final instance variables. The few instance variables in a service
implementation are usually referen
ces to other Tapestry IoC services.</p><h3
id="DefiningTapestryIOCServices-perthread">perthread</h3><p>The perthread
service scope exists primarily to help multi-threaded servlet applications,
though it has other applications.</p><p>With perthread, the service proxy will
delegate to a local service instance that is associated with the current
thread. Two different threads, invoking methods on the same proxy, will
ultimately be invoking methods on two different service instances, each
reserved to their own thread.</p><p>This is useful when a service needs to keep
request specific state, such as information extracted from the
HttpServletRequest (in a web application). The default singleton model would
not work in such a multithreaded environment. Using perthread on select
services allows state to be isolated to those services. Because the dispatch
occurs <em>inside</em> the proxy, you can treat the service as a global, like
any other.</p><p>You will see that your service builder metho
d is invoked more than once. It is invoked in each thread where the perthread
service is used.</p><p>At the end of the request, the Registry's
cleanupThread() method is invoked; it will discard any perthread service
implementations for the current thread.</p><p><strong>Caution:</strong> A
common technique in Tapestry IoC is to have a service builder method register a
core service implementation as an event listener with some event hub service.
With non-singleton objects, this can cause a number of problems; the event hub
will hold a reference to the per-thread instance, even after that per-thread
instance has been cleaned up (discarded by the inner proxy). Simply put, this
is a pattern to avoid. For the most part, perthread services should be simple
holders of data specific to a thread or a request, and should not have overly
complex relationships with the other services in the registry.</p><h1
id="DefiningTapestryIOCServices-DefiningthescopeofAutobuiltServices">Defining
the scope o
f Autobuilt Services</h1><p>There are two options for defining the scope for
an autobuilt service.</p><p>The service implementation class may include the
@<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html">Scope</a>
annotation. This is generally the preferred way to specify scope.</p><p>In
addition, it is possible to specify the scope when binding the
service:</p><parameter ac:name="">java</parameter><plain-text-body>
bind(MyServiceInterface.class,
MyServiceImpl.class).scope(ScopeConstants.PERTHREAD);</plain-text-body><h1
id="DefiningTapestryIOCServices-EagerLoadingServices">Eager Loading
Services</h1><p>Services are normally created only as needed (per the scope
discussion above).</p><p>This can be tweaked slightly; by adding the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html">EagerLoad</a>
annotation to the service builder metho
d, Tapestry will instantiate the service when the Registry is first
created.</p><p>This will cause the service builder method to be invoked, as
well as any service decorator methods.</p><p>This feature is used when a
service manages a resource, such as a thread, that needs to be created as soon
as the application starts up. Another common example is a service that listens
for events produced by a second service; the first service may need to be
created, and start listening, before any of its service methods are invoked
(which would normally trigger the instantiation of the service).</p><p>Many
services may be annotated with @EagerLoad; the order in which services are
created is not defined.</p><p>With the perthread scope, the service builder
method will not be invoked (this won't happen until a service method is
invoked), but the decorators for the service will be created.</p><h1
id="DefiningTapestryIOCServices-EagerLoadingAutobuiltServices">Eager Loading
Autobuilt Services</h1><p>A
s with service scope, there are two options for indicating that an autobuilt
service should be eagerly loaded.</p><p>The service implementation class may
include the @EagerLoad annotation.</p><p>You may also specify eager loading
explicitly when binding the service:</p><parameter
ac:name="">java</parameter><plain-text-body> bind(MyServiceInterface.class,
MyServiceImpl.class).eagerLoad();</plain-text-body><h1
id="DefiningTapestryIOCServices-InjectingResources">Injecting
Resources</h1><p>In addition to injecting services, Tapestry will key off of
the parameter type to allow other things to be
injected.</p><ul><li>java.lang.String: unique id for the service</li><li><a
class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html"
rel="nofollow">org.slf4j.Logger</a>: logger for the
service</li><li>java.lang.Class: service interface implemented by the service
to be constructed</li><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tap
estry5/ioc/ServiceResources.html">ServiceResources</a>: access to other
services</li></ul><p>No annotation is needed for these cases.</p><p>See also <a
href="tapestry-ioc-configuration.html">service configuration</a> for
additional special cases of resources that can be injected.</p><p>Note:
resources may not be injected into fields, they are injectable only via method
or constructor parameters.</p><p>Example:</p><parameter
ac:name="">java</parameter><plain-text-body> public static Indexer
build(String serviceId, Log serviceLog,
+}</pre>
+</div></div><h1
id="DefiningTapestryIOCServices-ServiceScopeDefiningServiceScope"><span
class="confluence-anchor-link"
id="DefiningTapestryIOCServices-ServiceScope"></span>Defining Service
Scope</h1><p>Each service has a <em>scope</em> that controls when the service
implementation is instantiated. There are two built in scopes: "singleton" and
"perthread", but more can be added.</p><p>Service scope is specified using the
@<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html">Scope</a>
annotation, which is attached to a builder method, or to the service
implementation class. When this annotation is not present, the default scope,
"singleton" is used.</p><h3
id="DefiningTapestryIOCServices-singleton">singleton</h3><p>Most services use
the default scope, "singleton". With this scope a <em>proxy</em> is created
when the service is first referenced. By reference, we mean any situation in
which the service is requested
by name, such as using the @InjectService annotation on a service builder
method, or by using the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Registry.html">Registry</a>
API from outside the container.</p><p>In any case, the service proxy will only
create the service implementation when a method on the service interface is
invoked. Until then, the service can be thought of as "virtual". As the first
method is invoked, the service builder method is invoked, then any service
decorations occur. This construction process, called "realization", occurs only
once.</p><p>You should be aware when writing services that your code must be
thread safe; any service you define could be invoked simultaneously by multiple
threads. This is rarely an issue in practice, since most services take input,
use local variables, and invoke methods on other services, without making use
of non-final instance variables. The few instance variables in a servi
ce implementation are usually references to other Tapestry IoC
services.</p><h3
id="DefiningTapestryIOCServices-perthread">perthread</h3><p>The perthread
service scope exists primarily to help multi-threaded servlet applications,
though it has other applications.</p><p>With perthread, the service proxy will
delegate to a local service instance that is associated with the current
thread. Two different threads, invoking methods on the same proxy, will
ultimately be invoking methods on two different service instances, each
reserved to their own thread.</p><p>This is useful when a service needs to keep
request specific state, such as information extracted from the
HttpServletRequest (in a web application). The default singleton model would
not work in such a multithreaded environment. Using perthread on select
services allows state to be isolated to those services. Because the dispatch
occurs <em>inside</em> the proxy, you can treat the service as a global, like
any other.</p><p>You wil
l see that your service builder method is invoked more than once. It is
invoked in each thread where the perthread service is used.</p><p>At the end of
the request, the Registry's cleanupThread() method is invoked; it will discard
any perthread service implementations for the current
thread.</p><p><strong>Caution:</strong> A common technique in Tapestry IoC is
to have a service builder method register a core service implementation as an
event listener with some event hub service. With non-singleton objects, this
can cause a number of problems; the event hub will hold a reference to the
per-thread instance, even after that per-thread instance has been cleaned up
(discarded by the inner proxy). Simply put, this is a pattern to avoid. For the
most part, perthread services should be simple holders of data specific to a
thread or a request, and should not have overly complex relationships with the
other services in the registry.</p><h1
id="DefiningTapestryIOCServices-DefiningthescopeofAu
tobuiltServices">Defining the scope of Autobuilt Services</h1><p>There are two
options for defining the scope for an autobuilt service.</p><p>The service
implementation class may include the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Scope.html">Scope</a>
annotation. This is generally the preferred way to specify scope.</p><p>In
addition, it is possible to specify the scope when binding the service:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> bind(MyServiceInterface.class,
MyServiceImpl.class).scope(ScopeConstants.PERTHREAD);</pre>
+</div></div><h1 id="DefiningTapestryIOCServices-EagerLoadingServices">Eager
Loading Services</h1><p>Services are normally created only as needed (per the
scope discussion above).</p><p>This can be tweaked slightly; by adding the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html">EagerLoad</a>
annotation to the service builder method, Tapestry will instantiate the
service when the Registry is first created.</p><p>This will cause the service
builder method to be invoked, as well as any service decorator
methods.</p><p>This feature is used when a service manages a resource, such as
a thread, that needs to be created as soon as the application starts up.
Another common example is a service that listens for events produced by a
second service; the first service may need to be created, and start listening,
before any of its service methods are invoked (which would normally trigger the
instantiation of the servic
e).</p><p>Many services may be annotated with @EagerLoad; the order in which
services are created is not defined.</p><p>With the perthread scope, the
service builder method will not be invoked (this won't happen until a service
method is invoked), but the decorators for the service will be created.</p><h1
id="DefiningTapestryIOCServices-EagerLoadingAutobuiltServices">Eager Loading
Autobuilt Services</h1><p>As with service scope, there are two options for
indicating that an autobuilt service should be eagerly loaded.</p><p>The
service implementation class may include the @EagerLoad annotation.</p><p>You
may also specify eager loading explicitly when binding the service:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> bind(MyServiceInterface.class,
MyServiceImpl.class).eagerLoad();</pre>
+</div></div><h1 id="DefiningTapestryIOCServices-InjectingResources">Injecting
Resources</h1><p>In addition to injecting services, Tapestry will key off of
the parameter type to allow other things to be
injected.</p><ul><li>java.lang.String: unique id for the service</li><li><a
class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html"
rel="nofollow">org.slf4j.Logger</a>: logger for the
service</li><li>java.lang.Class: service interface implemented by the service
to be constructed</li><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceResources.html">ServiceResources</a>:
access to other services</li></ul><p>No annotation is needed for these
cases.</p><p>See also <a href="tapestry-ioc-configuration.html">service
configuration</a> for additional special cases of resources that can be
injected.</p><p>Note: resources may not be injected into fields, they are
injectable only via method or constructor parameter
s.</p><p>Example:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer build(String serviceId, Log
serviceLog,
JobScheduler scheduler, FileSystem fileSystem)
{
IndexerImpl indexer = new IndexerImpl(serviceLog, fileSystem);
@@ -214,14 +246,18 @@ public class IndexerImpl implements Inde
scheduler.scheduleDailyJob(serviceId, indexer);
return indexer;
- }</plain-text-body><p>The order of parameters is completely irrelevant. They
can come first or last or be interspersed however you like.</p><p>Injecting in
the ServiceResources can be handy when you want to calculate the name of a
service dependency on the fly. However, in the general case (where the id of
service dependencies is known at build time), it is easier to use the
@InjectService annotation.</p><p>The Log's name (used when configuring logging
settings for the service) consists of the module class name and the service id
seperated by a period, i.e.
"org.example.myapp.MyModule.Indexer".</p><p>Further, ServiceResources includes
an autobuild() method that allows you to easily trigger the construction of a
class, including dependencies. Thus the previos example could be rewritten
as:</p><parameter ac:name="">java</parameter><plain-text-body> public static
Indexer build(ServiceResources resources, JobScheduler jobScheduler)
+ }</pre>
+</div></div><p>The order of parameters is completely irrelevant. They can come
first or last or be interspersed however you like.</p><p>Injecting in the
ServiceResources can be handy when you want to calculate the name of a service
dependency on the fly. However, in the general case (where the id of service
dependencies is known at build time), it is easier to use the @InjectService
annotation.</p><p>The Log's name (used when configuring logging settings for
the service) consists of the module class name and the service id seperated by
a period, i.e. "org.example.myapp.MyModule.Indexer".</p><p>Further,
ServiceResources includes an autobuild() method that allows you to easily
trigger the construction of a class, including dependencies. Thus the previos
example could be rewritten as:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer build(ServiceResources
resources, JobScheduler jobScheduler)
{
IndexerImpl indexer = resources.autobuild(IndexerImpl.class);
scheduler.scheduleDailyJob(resources.getServiceId(), indexer);
return indexer;
- }</plain-text-body><p>This works the exact same way with autobuilt services,
except that the parameters of the service implementation constructor are
considered, rather than the parameters of the service builder method.</p><p>The
@InjectService annotation takes precedence over these resources.</p><p>If the
@InjectService annotation is not present, and the parameter type does not
exactly match a resource type, then <a href="object-providers.html">object
injection</a> occurs. Object injection will find the correct object to inject
based on a number of (extensible) factors, including the parameter type and any
additional annotations on the parameter.</p><p>Every once and a while, you'll
have a conflict between a resource type and an object injection. For example,
the following does not work as expected:</p><parameter
ac:name="">java</parameter><plain-text-body> public static Indexer
build(String serviceId, Log serviceLog,
+ }</pre>
+</div></div><p>This works the exact same way with autobuilt services, except
that the parameters of the service implementation constructor are considered,
rather than the parameters of the service builder method.</p><p>The
@InjectService annotation takes precedence over these resources.</p><p>If the
@InjectService annotation is not present, and the parameter type does not
exactly match a resource type, then <a href="object-providers.html">object
injection</a> occurs. Object injection will find the correct object to inject
based on a number of (extensible) factors, including the parameter type and any
additional annotations on the parameter.</p><p>Every once and a while, you'll
have a conflict between a resource type and an object injection. For example,
the following does not work as expected:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer build(String serviceId, Log
serviceLog,
JobScheduler scheduler, FileSystem fileSystem,
@Value("${index-alerts-email}")
String alertEmail)
@@ -231,7 +267,9 @@ public class IndexerImpl implements Inde
scheduler.scheduleDailyJob(serviceId, indexer);
return indexer;
- }</plain-text-body><p>It doesn't work because type String always gets the
service id, as a resource (as with the serviceId parameter). In order to get
this to work, we need to turn off the resource injection for the alertEmail
parameter. That's what the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a>
annotation does:</p><parameter ac:name="">java</parameter><plain-text-body>
public static Indexer build(String serviceId, Log serviceLog,
+ }</pre>
+</div></div><p>It doesn't work because type String always gets the service id,
as a resource (as with the serviceId parameter). In order to get this to work,
we need to turn off the resource injection for the alertEmail parameter. That's
what the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a>
annotation does:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer build(String serviceId, Log
serviceLog,
JobScheduler scheduler, FileSystem fileSystem,
@Inject @Value("${index-alerts-email}")
String alertEmail)
@@ -241,7 +279,9 @@ public class IndexerImpl implements Inde
scheduler.scheduleDailyJob(serviceId, indexer);
return indexer;
- }</plain-text-body><p>Here, the alertEmail parameter will receive the
configured alerts email (see <a href="symbols.html">the symbols
documentation</a> for more about this syntax) rather than the service
id.</p><h1 id="DefiningTapestryIOCServices-BindingServiceBuilders">Binding
ServiceBuilders</h1><p>Yet another option is available: instead of binding an
interface to a implemention class, you can bind a service to a <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBuilder.html">ServiceBuilder</a>,
a callback used to create the service implementation. This is very useful in
very rare circumstances.</p><h1
id="DefiningTapestryIOCServices-BuiltinServices">Builtin Services</h1><p>A few
services within the Tapestry IOC Module are "builtin"; there is no service
builder method in the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/TapestryIOCModule.html">TapestryIOCModu
le</a> class.</p><div class="table-wrap"><table
class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1"
class="confluenceTd"><p><strong>Service Id</strong></p></td><td colspan="1"
rowspan="1" class="confluenceTd"><p><strong>Service
Interface</strong></p></td></tr><tr><td colspan="1" rowspan="1"
class="confluenceTd"><p>ClassFactory</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/ClassFactory.html">ClassFactory</a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>LoggerSource</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/LoggerSource.html">LoggerSource</a></p></td></tr><tr><td
colspan="1" rowspan="1"
class="confluenceTd"><p>RegistryShutdownHub</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/RegistryShutdownHub.html">RegistryShutdownHub</a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>PerthreadManager</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PerthreadManager.html">PerthreadManager</a></p></td></tr></tbody></table></div><p>Consult
the JavaDoc for each of these services to identify under what circumstances
you'll need to use them.</p><h1
id="DefiningTapestryIOCServices-MutuallyDependentServices">Mutually Dependent
Services</h1><p>One of the benefits of Tapestry IoC's proxy-based approach to
just-in-time instantiation is the automatic support for mutually dependent
services. For example, suppose that the Indexer and the FileSystem needed to
talk directly to each other. Normally, this would cause a "chicken-and-the-egg"
problem: which one to
create first?</p><p>With Tapestry IoC, this is not even considered a special
case:</p><parameter ac:name="">java</parameter><plain-text-body> public static
Indexer buildIndexer(JobScheduler scheduler, FileSystem fileSystem)
+ }</pre>
+</div></div><p>Here, the alertEmail parameter will receive the configured
alerts email (see <a href="symbols.html">the symbols documentation</a> for
more about this syntax) rather than the service id.</p><h1
id="DefiningTapestryIOCServices-BindingServiceBuilders">Binding
ServiceBuilders</h1><p>Yet another option is available: instead of binding an
interface to a implemention class, you can bind a service to a <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBuilder.html">ServiceBuilder</a>,
a callback used to create the service implementation. This is very useful in
very rare circumstances.</p><h1
id="DefiningTapestryIOCServices-BuiltinServices">Builtin Services</h1><p>A few
services within the Tapestry IOC Module are "builtin"; there is no service
builder method in the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/TapestryIOCModule.html">TapestryIOCModule</a>
cl
ass.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service
Id</strong></p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><strong>Service Interface</strong></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>ClassFactory</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/ClassFactory.html">ClassFactory</a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>LoggerSource</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/LoggerSource.html">LoggerSource</a></p></td></tr><tr><td
colspan="1" rowspan="1"
class="confluenceTd"><p>RegistryShutdownHub</p></td><td colspan="1" rowspan="1"
class="confluenceTd"><p><a class="external-link" href="ht
tp://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/RegistryShutdownHub.html">RegistryShutdownHub</a></p></td></tr><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p>PerthreadManager</p></td><td
colspan="1" rowspan="1" class="confluenceTd"><p><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PerthreadManager.html">PerthreadManager</a></p></td></tr></tbody></table></div><p>Consult
the JavaDoc for each of these services to identify under what circumstances
you'll need to use them.</p><h1
id="DefiningTapestryIOCServices-MutuallyDependentServices">Mutually Dependent
Services</h1><p>One of the benefits of Tapestry IoC's proxy-based approach to
just-in-time instantiation is the automatic support for mutually dependent
services. For example, suppose that the Indexer and the FileSystem needed to
talk directly to each other. Normally, this would cause a "chicken-and-the-egg"
problem: which one to create fi
rst?</p><p>With Tapestry IoC, this is not even considered a special
case:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static Indexer buildIndexer(JobScheduler
scheduler, FileSystem fileSystem)
{
IndexerImpl indexer = new IndexerImpl(fileSystem);
@@ -253,7 +293,8 @@ public class IndexerImpl implements Inde
public static FileSystem buildFileSystem(Indexer indexer)
{
return new FileSystemImpl(indexer);
- } </plain-text-body><p>Here, Indexer and FileSystem are mutually dependent.
Eventually, one or the other of them will be created ... let's say its
FileSystem. The buildFileSystem() builder method will be invoked, and a proxy
to Indexer will be passed in. Inside the FileSystemImpl constructor (or at some
later date), a method of the Indexer service will be invoked, at which point,
the builderIndexer() method is invoked. It still receives the proxy to the
FileSystem service.</p><p>If the order is reversed, such that Indexer is built
before FileSystem, everything still works the same.</p><p>This approach can be
very powerful. For example, it can be used to break apart untestable monolithic
code into two mutually dependent halves, each of which can be unit
tested.</p><p>The exception to this rule is a service that depends on itself
<em>during construction</em>. This can occur when (indirectly, through other
services) building the service tries to invoke a method on the service being
built. This can happen when the service implementation's constructor invoke
methods on service dependencies passed into it, or when the service builder
method itself does the same. This is actually a very rare case and difficult to
illustrate.</p><p> </p><p></p></div>
+ } </pre>
+</div></div><p>Here, Indexer and FileSystem are mutually dependent.
Eventually, one or the other of them will be created ... let's say its
FileSystem. The buildFileSystem() builder method will be invoked, and a proxy
to Indexer will be passed in. Inside the FileSystemImpl constructor (or at some
later date), a method of the Indexer service will be invoked, at which point,
the builderIndexer() method is invoked. It still receives the proxy to the
FileSystem service.</p><p>If the order is reversed, such that Indexer is built
before FileSystem, everything still works the same.</p><p>This approach can be
very powerful. For example, it can be used to break apart untestable monolithic
code into two mutually dependent halves, each of which can be unit
tested.</p><p>The exception to this rule is a service that depends on itself
<em>during construction</em>. This can occur when (indirectly, through other
services) building the service tries to invoke a method on the service being
built. This
can happen when the service implementation's constructor invoke methods on
service dependencies passed into it, or when the service builder method itself
does the same. This is actually a very rare case and difficult to
illustrate.</p><p> </p><p></p></div>
</div>
<div class="clearer"></div>
Modified:
websites/production/tapestry/content/dependencies-tools-and-plugins.html
==============================================================================
--- websites/production/tapestry/content/dependencies-tools-and-plugins.html
(original)
+++ websites/production/tapestry/content/dependencies-tools-and-plugins.html
Wed Sep 20 12:29:16 2017
@@ -36,26 +36,13 @@
<div class="wrapper bs">
- <div id="navigation"><div class="nav"><ul class="alternate"><li><a
href="index.html">Home</a></li><li><a href="getting-started.html">Getting
Started</a></li><li><a href="documentation.html">Documentation</a></li><li><a
href="download.html">Download</a></li><li><a
href="about.html">About</a></li><li><a class="external-link"
href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a
href="community.html">Community</a></li><li><a class="external-link"
href="http://www.apache.org/security/">Security</a></li><li><a
class="external-link" href="http://www.apache.org/">Apache</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
-
-</div>
+ <div id="navigation"><div class="nav"><ul class="alternate"><li><a
href="index.html">Home</a></li><li><a href="getting-started.html">Getting
Started</a></li><li><a href="documentation.html">Documentation</a></li><li><a
href="download.html">Download</a></li><li><a
href="about.html">About</a></li><li><a class="external-link"
href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a
href="community.html">Community</a></li><li><a class="external-link"
href="http://www.apache.org/security/">Security</a></li><li><a
class="external-link" href="http://www.apache.org/">Apache</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a
class="external-link"
href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
<div id="top">
- <div id="smallbanner"><div class="searchbox"
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999;
font-size: 90%">Tapestry docs, issues, wikis & blogs:</span>
-<form enctype="application/x-www-form-urlencoded" method="get"
action="http://tapestry.apache.org/search.html">
- <input type="text" name="q">
- <input type="submit" value="Search">
-</form>
-
-</div>
-
-
-<div class="emblem" style="float:left"><p><a href="index.html"><span
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image
confluence-external-resource"
src="http://tapestry.apache.org/images/tapestry_small.png"
data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
-
-
-<div class="title" style="float:left; margin: 0 0 0 3em"><h1
id="SmallBanner-PageTitle">Dependencies, Tools and Plugins</h1></div>
-
-</div>
+ <div id="smallbanner"><div class="searchbox"
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999;
font-size: 90%">Tapestry docs, issues, wikis & blogs:</span><form
enctype="application/x-www-form-urlencoded" method="get"
action="http://tapestry.apache.org/search.html">
+ <input type="text" name="q">
+ <input type="submit" value="Search">
+</form></div><div class="emblem" style="float:left"><p><a
href="index.html"><span class="confluence-embedded-file-wrapper"><img
class="confluence-embedded-image confluence-external-resource"
src="http://tapestry.apache.org/images/tapestry_small.png"
data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div
class="title" style="float:left; margin: 0 0 0 3em"><h1
id="SmallBanner-PageTitle">Dependencies, Tools and Plugins</h1></div></div>
<div class="clearer"></div>
</div>