Modified: websites/production/tapestry/content/tapestry-ioc-decorators.html
==============================================================================
--- websites/production/tapestry/content/tapestry-ioc-decorators.html (original)
+++ websites/production/tapestry/content/tapestry-ioc-decorators.html Sat Aug
8 17:20:04 2015
@@ -31,8 +31,6 @@
<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 src='/resources/highlighter/scripts/shBrushXml.js'
type='text/javascript'></script>
- <script src='/resources/highlighter/scripts/shBrushPlain.js'
type='text/javascript'></script>
<script type="text/javascript">
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
@@ -62,43 +60,13 @@
<div class="clearer"></div>
<div id="breadcrumbs">
- <a href="index.html">Apache Tapestry</a> > <a
href="documentation.html">Documentation</a> > <a
href="user-guide.html">User Guide</a> > <a
href="ioc.html">IoC</a> > <a
href="tapestry-ioc-decorators.html">Tapestry IoC Decorators</a>
+ <a href="index.html">Apache Tapestry</a> > <a
href="documentation.html">Documentation</a> > <a
href="user-guide.html">User Guide</a> > <a
href="ioc.html">IOC</a> > <a
href="tapestry-ioc-decorators.html">Tapestry IoC Decorators</a>
<a class="edit" title="Edit this page (requires approval -- just ask on
the mailing list)"
href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=23338481">edit</a>
</div>
<div id="content">
-<div id="ConfluenceContent">
-
-<h1 id="TapestryIoCDecorators-TapestryIoCDecorators">Tapestry IoC
Decorators</h1>
-
-<div class="confluence-information-macro
confluence-information-macro-information"><span class="aui-icon aui-icon-small
aui-iconfont-info confluence-information-macro-icon"></span><div
class="confluence-information-macro-body">
-<p>Starting with Tapestry 5.1, Service Decoration is augmented with <a
shape="rect" href="service-advisors.html">Service Advice</a>. Advisors are
similar but more general, as they work on any service interface, which doesn't
have to be known at build time. Decoration is used when the type of the service
being decorated <em>is</em> known at build time, and involves supplying a new
implementation of the service interface.</p></div></div>
-
-<p><em>Decoration</em> is the name of a popular design pattern. Using
decoration, an existing object's behavior can be extended without changing the
implementation of the object.</p>
-
-<p>Instead, a new object is placed <em>around</em> the existing object. The
rest of the world sees this new object, termed an <strong>interceptor</strong>.
The interceptor implements the same interface as the underlying object being
decorated.</p>
-
-<p>A common example for this is the Java I/O library. The abstract InputStream
base class has a very simple API for reading bytes from a stream (and a few
other things). Subclasses of InputStream provide a wide array of other options
such as buffering, encryption or decryption, as well as control over the source
of data read by the stream. All of these <em>concerns</em> are encapsulated in
different implementations of InputStream, and all can be connected together in
a kind of pipeline, using the common InputStream API.</p>
-
-<p>Tapestry IoC uses a similar approach, where one or more interceptor
objects, all implementing the service interface, are strung together. The
service's proxy (responsible for just-in-time instantiation of the service
implementation) is at one end of this pipeline, the core service implementation
is at the other.</p>
-
-<p>For each method in the service interface, the interceptor object can
perform some operations before and after re-invoking the same method on the
core service implementation. This is another design pattern:
<em>delegation</em>. An interceptor can even catch exceptions thrown by the
underlying implementation and react to them. A sufficiently clever interceptor
could retry a method if an exception is thrown, or could "soften" a checked
exception by wrapping it in a RuntimeException.</p>
-
-<p>Decorators often are used in the context of <em>cross-cutting
concerns</em>, such as logging or transaction management. This approach is a
kind of <em>aspect oriented design</em>.</p>
-
-<p>One such cross cutting concern is lazy initialization of services. In
Apache HiveMind, services are created only as needed, when a method of a
service interface is first invoked. This concern is supplied by the Tapestry
IoC framework itself, but similar concerns are easily implemented as
decorations.</p>
-
-<p>Whereas the popular AspectJ framework changes the compiled bytecode of your
classes (it calls the process "weaving"), with Tapestry IoC, the approach is to
wrap your existing classes in new objects. These wrapper objects are often
dynamically created at runtime.</p>
-
-<p>It is also common to have <em>multiple</em> decorations on a single
service. In this case, a whole stack of interceptor objects will be created,
each delegating to the next. Tapestry IoC provides control over the order in
which such decorations occur.</p>
-
-<p>Decorations are driven by service decoration methods. Often, a reusable
service exists to do the grunt work of creating and instantiating a new
class.</p>
-
-<h1 id="TapestryIoCDecorators-ServiceDecorationMethods">Service Decoration
Methods</h1>
-
-<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;
+<div id="ConfluenceContent"><div class="confluence-information-macro
confluence-information-macro-information"><span class="aui-icon aui-icon-small
aui-iconfont-info confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Starting with Tapestry 5.1,
Service Decoration is augmented with <a shape="rect"
href="service-advisors.html">Service Advice</a>. Advisors are similar but more
general, as they work on any service interface, which doesn't have to be known
at build time. Decoration is used when the type of the service being decorated
<em>is</em> known at build time, and involves supplying a new implementation of
the service interface.</p></div></div><p><em>Decoration</em> is the name of a
popular design pattern. Using decoration, an existing object's behavior can be
extended without changing the implementation of the object.</p><p>Instead, a
new object is placed <em>around</em> the existing object. The rest of the world
sees this new object, terme
d an <strong>interceptor</strong>. The interceptor implements the same
interface as the underlying object being decorated.</p><p>A common example for
this is the Java I/O library. The abstract InputStream base class has a very
simple API for reading bytes from a stream (and a few other things). Subclasses
of InputStream provide a wide array of other options such as buffering,
encryption or decryption, as well as control over the source of data read by
the stream. All of these <em>concerns</em> are encapsulated in different
implementations of InputStream, and all can be connected together in a kind of
pipeline, using the common InputStream API.</p><p>Tapestry IoC uses a similar
approach, where one or more interceptor objects, all implementing the service
interface, are strung together. The service's proxy (responsible for
just-in-time instantiation of the service implementation) is at one end of this
pipeline, the core service implementation is at the other.</p><p>For each
method in
the service interface, the interceptor object can perform some operations
before and after re-invoking the same method on the core service
implementation. This is another design pattern: <em>delegation</em>. An
interceptor can even catch exceptions thrown by the underlying implementation
and react to them. A sufficiently clever interceptor could retry a method if an
exception is thrown, or could "soften" a checked exception by wrapping it in a
RuntimeException.</p><p>Decorators often are used in the context of
<em>cross-cutting concerns</em>, such as logging or transaction management.
This approach is a kind of <em>aspect oriented design</em>.</p><p>One such
cross cutting concern is lazy initialization of services. In Apache HiveMind,
services are created only as needed, when a method of a service interface is
first invoked. This concern is supplied by the Tapestry IoC framework itself,
but similar concerns are easily implemented as decorations.</p><p>Whereas the
popular AspectJ fra
mework changes the compiled bytecode of your classes (it calls the process
"weaving"), with Tapestry IoC, the approach is to wrap your existing classes in
new objects. These wrapper objects are often dynamically created at
runtime.</p><p>It is also common to have <em>multiple</em> decorations on a
single service. In this case, a whole stack of interceptor objects will be
created, each delegating to the next. Tapestry IoC provides control over the
order in which such decorations occur.</p><p>Decorations are driven by service
decoration methods. Often, a reusable service exists to do the grunt work of
creating and instantiating a new class.</p><h1
id="TapestryIoCDecorators-ServiceDecorationMethods">Service Decoration
Methods</h1><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.services.LoggingDecorator;
import org.slf4j.Logger;
@@ -118,35 +86,13 @@ public class MyAppModule
return decorator.build(serviceInterface, delegate, serviceId, logger);
}
}</pre>
-</div></div>
-
-<p>The method decorateIndexer() is a service decorator method because it
starts with the word "decorate". In this simple case, only the myapp.Indexer
service will be decorated, even if there are other services in this module or
others ... this is because of the name match ("decorateIndexer" and
"buildIndexer"), but we'll shortly see how annotations can be used to target
many services for decoration.</p>
-
-<p>We are using the parameterized types here (the <T>), to reinforce the
fact that the delegate object passed in (which will be the core service
implementation, or some other interceptor) must implement the service
interface, and that the decorator method must return an instance of the service
interface.</p>
-
-<p>The values that may be provided to a decorator method are exactly the same
as for a builder method, with one addition: The underlying service will be
passed in as a parameter of type java.lang.Object (after type erasure, the
<code>T delegate</code> parameter becomes <code>Object delegate</code>).</p>
-
-<p>In the above example, the decorator method receives the core service
implementation, the service interface for the Indexer service, the Log for the
Indexer service, and an interceptor factory that generates logging
interceptors.</p>
-
-<p>The "heavy lifting" is provided by the factory, which will create a new
interceptor that logs method entry before delegating to the core service
implementation. The interceptor will also log method parameters, return values,
and even log exceptions.</p>
-
-<p>The return value of the method is the new interceptor. You may return null
if your decorator method decides not to decorate the supplied service.</p>
-
-<p>Alternately, when targetting services whose type is known at compile time,
you may provide a parameter whose type matches the service interface. For
example, decorateIndexer() will always be applied to the Indexer service, whose
type (Indexer) is known. We could therefore rewrite decorateIndexer() 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 decorateIndexer(Indexer delegate, Logger logger,
LoggingDecorator decorator)
+</div></div><p>The method decorateIndexer() is a service decorator method
because it starts with the word "decorate". In this simple case, only the
myapp.Indexer service will be decorated, even if there are other services in
this module or others ... this is because of the name match ("decorateIndexer"
and "buildIndexer"), but we'll shortly see how annotations can be used to
target many services for decoration.</p><p>We are using the parameterized types
here (the <T>), to reinforce the fact that the delegate object passed in
(which will be the core service implementation, or some other interceptor) must
implement the service interface, and that the decorator method must return an
instance of the service interface.</p><p>The values that may be provided to a
decorator method are exactly the same as for a builder method, with one
addition: The underlying service will be passed in as a parameter of type
java.lang.Object (after type erasure, the <code>T delegate</code> parameter be
comes <code>Object delegate</code>).</p><p>In the above example, the decorator
method receives the core service implementation, the service interface for the
Indexer service, the Log for the Indexer service, and an interceptor factory
that generates logging interceptors.</p><p>The "heavy lifting" is provided by
the factory, which will create a new interceptor that logs method entry before
delegating to the core service implementation. The interceptor will also log
method parameters, return values, and even log exceptions.</p><p>The return
value of the method is the new interceptor. You may return null if your
decorator method decides not to decorate the supplied
service.</p><p>Alternately, when targetting services whose type is known at
compile time, you may provide a parameter whose type matches the service
interface. For example, decorateIndexer() will always be applied to the Indexer
service, whose type (Indexer) is known. We could therefore rewrite
decorateIndexer() 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 decorateIndexer(Indexer
delegate, Logger logger, LoggingDecorator decorator)
{
return decorator.build(Indexer.class, delegate, "Indexer", logger);
}</pre>
-</div></div>
-
-<p>Of course, nothing stops you from combining building with decorating inside
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;">
-package org.example.myapp.services;
+</div></div><p>Of course, nothing stops you from combining building with
decorating inside 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;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.services.LoggingDecorator;
import org.slf4j.Logger;
@@ -158,54 +104,16 @@ public class MyAppModule
return decorator.build(Indexer.class, logger, new IndexerImpl());
}
}</pre>
-</div></div>
-
-<p>But as we'll see next, it's possible to have a single decorator method work
on many different services by using annotations.</p>
-
-<h1 id="TapestryIoCDecorators-TargetingMultipleServices">Targeting Multiple
Services</h1>
-
-<p>By using the @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html">Match</a>
annotation, you may identify which services are to be decorated.</p>
-
-<p>The value specified in the Match annotation is one or more patterns. These
patterns are used to match services. Patterns take two forms: glob patterns and
regular expressions.</p>
-
-<p>In a glob pattern, a "*" at the start or end of a string will match zero or
more characters. Regular expressions provide a lot more matching power, but
require a more involved syntax.</p>
-
-<p>In either case, the matching is case insensitive.</p>
-
-<p>For example, to target all the services in your module:</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;">
- @Match("*")
+</div></div><p>But as we'll see next, it's possible to have a single decorator
method work on many different services by using annotations.</p><h1
id="TapestryIoCDecorators-TargetingMultipleServices">Targeting Multiple
Services</h1><p>By using the @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html">Match</a>
annotation, you may identify which services are to be decorated.</p><p>The
value specified in the Match annotation is one or more patterns. These patterns
are used to match services. Patterns take two forms: glob patterns and regular
expressions.</p><p>In a glob pattern, a "*" at the start or end of a string
will match zero or more characters. Regular expressions provide a lot more
matching power, but require a more involved syntax.</p><p>In either case, the
matching is case insensitive.</p><p>For example, to target all the services in
your module:</p><div class="code panel pdl" style="border-wi
dth: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @Match("*")
public static <T> T decorateLogging(Class<T> serviceInterface, T
delegate,
String serviceId, Logger logger,
LoggingDecorator decorator)
{
return decorator.build(serviceInterface, delegate, serviceId, logger);
} </pre>
-</div></div>
-
-<p>You can use multiple patterns with @Match, in which case, the decorator
will be applied to a service that matches <em>any</em> of the patterns. For
instance, if you only wanted logging for your data access and business logic
services, you might end up with <code>@Match("Data*", "*Logic")</code> (based,
of course, on how you name your services).</p>
-
-<p>As the preceding example showed, a simple "glob" matching is supported,
where a asterisk ('*') may be used at the start or end of the match string to
match any number of characters. As elsewhere, matching is case insensitive.</p>
-
-<p>Thus, <code>@Match("*")</code> is dangerous, because it will match every
service in every module.</p>
-
-<p><em>Note: It is not possible to decorate the services of the
TapestryIOCModule.</em></p>
-
-<p><em>Note: Another idea will be other ways of matching services: base on
inheritance of the service interface and/or based on the presence of particular
class annotations on the service interface. None of this has been implemented
yet, and can readily be accomplished inside the decorator method (which will
return null if it decides the service doesn't need decoration).</em></p>
-
-<h1 id="TapestryIoCDecorators-OrderingofDecorators">Ordering of Decorators</h1>
-
-<p>In cases where multiple decorators will apply to a single service, you can
control the order in which decorators are applied using an additional
annotation: @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Order.html">Order</a>.</p>
-
-<p>This annotation allows any number of <a shape="rect"
href="ordering-by-constraints.html">ordering constraints</a> to be specified
for the decorator, to order it relative to any other decorators.</p>
-
-<p>For example, you almost always want logging decorators to come first,
so:</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;">
- @Match("*")
+</div></div><p>You can use multiple patterns with @Match, in which case, the
decorator will be applied to a service that matches <em>any</em> of the
patterns. For instance, if you only wanted logging for your data access and
business logic services, you might end up with <code>@Match("Data*",
"*Logic")</code> (based, of course, on how you name your services).</p><p>As
the preceding example showed, a simple "glob" matching is supported, where a
asterisk ('*') may be used at the start or end of the match string to match any
number of characters. As elsewhere, matching is case insensitive.</p><p>Thus,
<code>@Match("*")</code> is dangerous, because it will match every service in
every module.</p><p><em>Note: It is not possible to decorate the services of
the TapestryIOCModule.</em></p><p><em>Note: Another idea will be other ways of
matching services: base on inheritance of the service interface and/or based on
the presence of particular class annotations on the service interface. None o
f this has been implemented yet, and can readily be accomplished inside the
decorator method (which will return null if it decides the service doesn't need
decoration).</em></p><h1
id="TapestryIoCDecorators-OrderingofDecorators">Ordering of
Decorators</h1><p>In cases where multiple decorators will apply to a single
service, you can control the order in which decorators are applied using an
additional annotation: @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Order.html">Order</a>.</p><p>This
annotation allows any number of <a shape="rect"
href="ordering-by-constraints.html">ordering constraints</a> to be specified
for the decorator, to order it relative to any other decorators.</p><p>For
example, you almost always want logging decorators to come first, so:</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;"> @Match("*")
@Order("before:*")
public static <T> T decorateLogging(Class<T> serviceInterface, T
delegate,
String serviceId, Logger logger,
@@ -213,28 +121,13 @@ public class MyAppModule
{
return decorator.build(serviceInterface, delegate, serviceId, logger);
} </pre>
-</div></div>
-
-<p>"before:*" indicates that this decorator should come before any decorator
in <em>any</em> module.</p>
-
-<p><strong>Note:</strong> the ordering of decorators is in terms of the
<em>effect</em> desired. Internally, the decorators are invoked last to first
(since each once receives the "next" interceptor as its delegate). So the core
service implementation is created (via a service builder method) and that is
passed to the last decorator method. The interceptor created there is passed to
the the next-to-last decorator method, and so forth.</p>
-
-<p>It should now be evident that the delegate passed into a decorator method
is sometimes the core service implementation, and some times an interceptor
object created by some other decorator method.</p>
+</div></div><p>"before:*" indicates that this decorator should come before any
decorator in <em>any</em> module.</p><p><strong>Note:</strong> the ordering of
decorators is in terms of the <em>effect</em> desired. Internally, the
decorators are invoked last to first (since each once receives the "next"
interceptor as its delegate). So the core service implementation is created
(via a service builder method) and that is passed to the last decorator method.
The interceptor created there is passed to the the next-to-last decorator
method, and so forth.</p><p>It should now be evident that the delegate passed
into a decorator method is sometimes the core service implementation, and some
times an interceptor object created by some other decorator method.</p><h1
id="TapestryIoCDecorators-Annotationdrivendecorators">Annotation driven
decorators</h1><p>
-<h1 id="TapestryIoCDecorators-Annotationdrivendecorators">Annotation driven
decorators</h1>
-
-
-
-<div class="confluence-information-macro
confluence-information-macro-information"><p class="title">Added in
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body">
+</p><div class="confluence-information-macro
confluence-information-macro-information"><p class="title">Added in
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body">
</div></div>
<div style="border-right: 20px solid #D8E4F1;border-left: 20px solid #D8E4F1;">
-</div>
-
-<p>Starting from version 5.2, Tapestry supports annotation-driven decorator
methods. If the <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Decorate.html">@Decorate</a>
annotation is present, the decorator method can be arbitrary named, as shown
in the following 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;">
- @Decorate
+<p> </p></div>Starting from version 5.2, Tapestry supports
annotation-driven decorator methods. If the <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Decorate.html">@Decorate</a>
annotation is present, the decorator method can be arbitrary named, as shown
in the following example.<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;"> @Decorate
@Match("*DAO")
public static <T> T byServiceId(Class<T> serviceInterface, T
delegate,
String serviceId, Logger logger,
@@ -243,15 +136,8 @@ public class MyAppModule
return decorator.build(serviceInterface, delegate, serviceId, logger);
}
</pre>
-</div></div>
-
-<p>The decorator above is applied to any service whose id matches the "*DAO"
pattern.</p>
-
-<p>Alternatively, marker annotations can be placed on the decorate method to
match a specific 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;">
- @Decorate
+</div></div><p>The decorator above is applied to any service whose id matches
the "*DAO" pattern.</p><p>Alternatively, marker annotations can be placed on
the decorate method to match a specific 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;"> @Decorate
@Blue
public static <T> T byMarkerAnnotation(Class<T>
serviceInterface, T delegate,
String serviceId, Logger logger,
@@ -260,15 +146,8 @@ public class MyAppModule
return decorator.build(serviceInterface, delegate, serviceId, logger);
}
</pre>
-</div></div>
-
-<p>The decorator above is applied to any service that is marked by the @Blue
annotation.</p>
-
-<p>By default, <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Decorate.html">@Decorate</a>
annotation applies the decorator to any service matched by the <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html">@Match</a>
or marker annotations. You can limit the matching to a single service
interface, as shown in the following 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;">
- @Decorate(serviceInterface=MyService.class)
+</div></div><p>The decorator above is applied to any service that is marked by
the @Blue annotation.</p><p>By default, <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Decorate.html">@Decorate</a>
annotation applies the decorator to any service matched by the <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Match.html">@Match</a>
or marker annotations. You can limit the matching to a single service
interface, as shown in the following 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;"> @Decorate(serviceInterface=MyService.class)
@Match("*DAO")
public static <T> T byServiceId(Class<T> serviceInterface, T
delegate,
String serviceId, Logger logger,
@@ -276,13 +155,8 @@ public class MyAppModule
{
return decorator.build(serviceInterface, delegate, serviceId, logger);
}</pre>
-</div></div>
-
-<p>In the example above, the decorator is applied to any implementation of
MyService interfaces whose id matches the "*DAO" pattern.</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;">
- @Decorate(serviceInterface=MyService.class)
+</div></div><p>In the example above, the decorator is applied to any
implementation of MyService interfaces whose id matches the "*DAO"
pattern.</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;"> @Decorate(serviceInterface=MyService.class)
@Blue
public static <T> T byMarkerAnnotation(Class<T>
serviceInterface, T delegate,
String serviceId, Logger logger,
@@ -291,35 +165,8 @@ public class MyAppModule
return decorator.build(serviceInterface, delegate, serviceId, logger);
}
</pre>
-</div></div>
-
-<p>The decorator above is applied to any implementation of the MyService
interface that is marked by the @Blue annotation.</p>
-
-<h1 id="TapestryIoCDecorators-CreatingyourownDecorators">Creating your own
Decorators</h1>
-
-<p>Decorators are a limited form of Aspect Oriented Programming, so we have
borrowed some of that terminology here.</p>
-
-<p>A decorator exists to create an <em>interceptor</em>. The interceptor wraps
around the service (because these interceptors can get chained, we talk about
the "delegate" and not the "service").</p>
-
-<p>Each method of the interceptor will take <em>advice</em>. Advice is
provided by a <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdvice.html">MethodAdvice</a>
instance. The sole method, <code>advise()</code>, receives an <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Invocation.html">Invocation</a>.
MethodAdvice gives you a chance to see what the method invocation <em>is</em>;
you can query the name of the method, and the types and values of the
parameters.</p>
-
-<p>The MethodAdvice can override the parameters if necessary, then invoke
<code>proceed()</code>. This call invokes the corresponding method on the
original object, the delegate.</p>
-
-<p>If the method call throws a runtime exception, that exception is not
caught. Your method advice can put a try ... catch block around the call to
proceed() if interested in catching runtime exceptions.</p>
-
-<p>Checked exceptions are not thrown (since they are not part of the proceed()
method's signature). Instead the invocation's <code>isFail()</code> method will
return true. You can then retrieve the exception or override it.</p>
-
-<p>In the normal success case, you can ask for the return value and even
override it before returning from the advise() method.</p>
-
-<p>In other words, you have total control. Your MethodAdvice can query or
change parameters, decide whether it proceed into the original code, it can
intercept exceptions that are thrown and replace them, and can query or even
replace the return value.</p>
-
-<p>The <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/AspectDecorator.html">AspectDecorator</a>
service is how you put your MethodAdvice into action.</p>
-
-<p>By way of an example, we'll show an implementation of the LoggingDecorator
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;">
-public class LoggingDecoratorImpl implements LoggingDecorator
+</div></div><p>The decorator above is applied to any implementation of the
MyService interface that is marked by the @Blue annotation.</p><h1
id="TapestryIoCDecorators-CreatingyourownDecorators">Creating your own
Decorators</h1><p>Decorators are a limited form of Aspect Oriented Programming,
so we have borrowed some of that terminology here.</p><p>A decorator exists to
create an <em>interceptor</em>. The interceptor wraps around the service
(because these interceptors can get chained, we talk about the "delegate" and
not the "service").</p><p>Each method of the interceptor will take
<em>advice</em>. Advice is provided by a <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/MethodAdvice.html">MethodAdvice</a>
instance. The sole method, <code>advise()</code>, receives an <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/Invocation.html">Invocation</a>.
MethodAdvic
e gives you a chance to see what the method invocation <em>is</em>; you can
query the name of the method, and the types and values of the
parameters.</p><p>The MethodAdvice can override the parameters if necessary,
then invoke <code>proceed()</code>. This call invokes the corresponding method
on the original object, the delegate.</p><p>If the method call throws a runtime
exception, that exception is not caught. Your method advice can put a try ...
catch block around the call to proceed() if interested in catching runtime
exceptions.</p><p>Checked exceptions are not thrown (since they are not part of
the proceed() method's signature). Instead the invocation's
<code>isFail()</code> method will return true. You can then retrieve the
exception or override it.</p><p>In the normal success case, you can ask for the
return value and even override it before returning from the advise()
method.</p><p>In other words, you have total control. Your MethodAdvice can
query or change parameters, deci
de whether it proceed into the original code, it can intercept exceptions that
are thrown and replace them, and can query or even replace the return
value.</p><p>The <a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/AspectDecorator.html">AspectDecorator</a>
service is how you put your MethodAdvice into action.</p><p>By way of an
example, we'll show an implementation of the LoggingDecorator 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;">public class LoggingDecoratorImpl implements
LoggingDecorator
{
private final AspectDecorator aspectDecorator;
@@ -374,18 +221,7 @@ public class LoggingDecoratorImpl implem
serviceInterface.getName()));
}
}</pre>
-</div></div>
-
-<p><em>The actual code has been refactored slightly since this documentation
was written.</em></p>
-
-<p>Most of the logging logic occurs inside the ServiceLogger object, the
MethodAdvice exists to call the right methods at the right time. A Logger
doesn't <em>change</em> parameter values (or thrown exceptions, or the result),
it just captures and logs the data.</p>
-
-<p>Notice that for runtime exceptions, we catch the exception, log it, and
rethrow it.</p>
-
-<p>For checked exceptions, we use isFail() and getThrown().</p>
-
-<p>The AspectDecorator service can also be used in more complicated ways: it
is possible to only advise some of the methods and not others, or use different
advice for different methods. Check the JavaDoc for more details.</p>
-</div>
+</div></div><p><em>The actual code has been refactored slightly since this
documentation was written.</em></p><p>Most of the logging logic occurs inside
the ServiceLogger object, the MethodAdvice exists to call the right methods at
the right time. A Logger doesn't <em>change</em> parameter values (or thrown
exceptions, or the result), it just captures and logs the data.</p><p>Notice
that for runtime exceptions, we catch the exception, log it, and rethrow
it.</p><p>For checked exceptions, we use isFail() and getThrown().</p><p>The
AspectDecorator service can also be used in more complicated ways: it is
possible to only advise some of the methods and not others, or use different
advice for different methods. Check the JavaDoc for more
details.</p><p> </p><p></p></div>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/tapestry-ioc-modules.html
==============================================================================
--- websites/production/tapestry/content/tapestry-ioc-modules.html (original)
+++ websites/production/tapestry/content/tapestry-ioc-modules.html Sat Aug 8
17:20:04 2015
@@ -31,8 +31,6 @@
<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 src='/resources/highlighter/scripts/shBrushXml.js'
type='text/javascript'></script>
- <script src='/resources/highlighter/scripts/shBrushPlain.js'
type='text/javascript'></script>
<script type="text/javascript">
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
@@ -62,35 +60,13 @@
<div class="clearer"></div>
<div id="breadcrumbs">
- <a href="index.html">Apache Tapestry</a> > <a
href="documentation.html">Documentation</a> > <a
href="user-guide.html">User Guide</a> > <a
href="ioc.html">IoC</a> > <a
href="tapestry-ioc-modules.html">Tapestry IoC Modules</a>
+ <a href="index.html">Apache Tapestry</a> > <a
href="documentation.html">Documentation</a> > <a
href="user-guide.html">User Guide</a> > <a
href="ioc.html">IOC</a> > <a
href="tapestry-ioc-modules.html">Tapestry IoC Modules</a>
<a class="edit" title="Edit this page (requires approval -- just ask on
the mailing list)"
href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=23338484">edit</a>
</div>
<div id="content">
-<div id="ConfluenceContent">
-
-<h1 id="TapestryIoCModules-TapestryIoCModules">Tapestry IoC Modules</h1>
-
-<p>You inform Tapestry about your services and contributions by providing a
module class.</p>
-
-<p>The module class is a plain Java class. A system of annotations and naming
conventions allow Tapestry to determine what services are provided by the
module.</p>
-
-<p>A module class exists for the following reasons:</p>
-
-<ul><li>To <em>bind</em> service interfaces to service
implementations</li><li>To contribute configuration data <em>into</em>
services</li><li>To <em>decorate</em> services by providing
<em>interceptors</em> around them</li><li>To provide explicit code for building
a service</li><li>To set a default <em>marker</em> for all services defined in
the module</li></ul>
-
-
-<p>All public methods of a module class must be meaningful to Tapestry (be one
of the categories above). Any extra public methods result in startup exceptions
(because the method may contain a typo).</p>
-
-<h1 id="TapestryIoCModules-ServiceBuilderMethods">Service Builder Methods</h1>
-
-<p>Service builder methods were the original way to define a service and
provide the logic to construct it; although this is now more commonly (and
succinctly) accomplished using the bind() method, there are still many cases
where service builder methods are useful.</p>
-
-<p>Service builder methods are public methods. They are often static. Here's a
trivial 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;">
-package org.example.myapp.services;
+<div id="ConfluenceContent"><p>You inform Tapestry about your services and
contributions by providing a <strong>module</strong> class.</p><p>The module
class is a plain Java class that you create to inform Tapestry about your
services and contributions.</p><p>A system of annotations and naming
conventions allow Tapestry to determine what services are provided by the
module.</p><p>A module class exists for the following reasons:</p><ul><li>To
<em>bind</em> service interfaces to service implementations</li><li>To
contribute configuration data <em>into</em> services</li><li>To
<em>decorate</em> services by providing <em>interceptors</em> around
them</li><li>To provide explicit code for building a service</li><li>To set a
default <em>marker</em> for all services defined in the module</li></ul><p>All
public methods of a module class must be meaningful to Tapestry (be one of the
categories above). Any extra public methods result in startup exceptions
(because the method may contain a typo
).</p><h1 id="TapestryIoCModules-ServiceBuilderMethods">Service Builder
Methods</h1><p>Service builder methods were the original way to define a
service and provide the logic to construct it; although this is now more
commonly (and succinctly) accomplished using the bind() method, there are still
many cases where service builder methods are useful.</p><p>Service builder
methods are public methods. They are often static. Here's a trivial
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;">package org.example.myapp.services;
public class MyAppModule
{
@@ -99,31 +75,8 @@ public class MyAppModule
return new IndexerImpl();
}
}</pre>
-</div></div>
-
-<p>Any public method (static or instance) whose name starts with "build" is a
service builder method, implicitly defining a service within the module.</p>
-
-<p>Here we're defining a service around the Indexer service interface
(presumably also in the org.example.myapp.services package).</p>
-
-<p>Every service has a unique id, used to identify it throughout the Registry
of services (the Registry is the combined sum of all services from all
modules). If you don't provide an explicit service id, as in this example, the
service id is drawn from the return type; this service has an id of
"Indexer".</p>
-
-<p>You can give a service an explicit id by adding it to the method name:
buildIndexer(). This is useful when you do not want the service id to match the
service interface name (for example, when you have different services that
implement the same interface), or when you need to avoid name collisions on the
method name (Java allows only a single method with a given name and set of
parameters, even if the return types are different, so if you have two
different service builder methods that take the same parameters, you should
give them explicit service ids in the method name).</p>
-
-<p>Tapestry IoC is <a shape="rect" href="case-insensitivity.html">case
insensitive</a>; later we can refer to this service as "indexer" or "INDEXER"
or any variation thereof, and connect to this service.</p>
-
-<p>Service ids must be unique; if another module contributes a service with
the id "Indexer" (or any case variation thereof) a runtime exception will occur
when the Registry is created.</p>
-
-<p>We could extend this example by adding additional service builder methods,
or by showing how to inject dependencies. See <a shape="rect"
href="defining-tapestry-ioc-services.html">the service documentation</a> for
more details.</p>
-
-<h1 id="TapestryIoCModules-AutobuildingServices">Autobuilding Services</h1>
-
-<p>Main article: <a shape="rect"
href="defining-tapestry-ioc-services.html">Defining Tapestry IOC
Services</a></p>
-
-<p>An alternate, and usually preferred, way to define a service is via a
module's bind() method. The previous example can 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;">
-package org.example.myapp.services;
+</div></div><p>Any public method (static or instance) whose name starts with
"build" is a service builder method, implicitly defining a service within the
module.</p><p>Here we're defining a service around the Indexer service
interface (presumably also in the org.example.myapp.services
package).</p><p>Every service has a unique id, used to identify it throughout
the Registry of services (the Registry is the combined sum of all services from
all modules). If you don't provide an explicit service id, as in this example,
the service id is drawn from the return type; this service has an id of
"Indexer".</p><p>You can give a service an explicit id by adding it to the
method name: buildIndexer(). This is useful when you do not want the service id
to match the service interface name (for example, when you have different
services that implement the same interface), or when you need to avoid name
collisions on the method name (Java allows only a single method with a given
name and set of par
ameters, even if the return types are different, so if you have two different
service builder methods that take the same parameters, you should give them
explicit service ids in the method name).</p><p>Tapestry IoC is <a shape="rect"
href="case-insensitivity.html">case insensitive</a>; later we can refer to this
service as "indexer" or "INDEXER" or any variation thereof, and connect to this
service.</p><p>Service ids must be unique; if another module contributes a
service with the id "Indexer" (or any case variation thereof) a runtime
exception will occur when the Registry is created.</p><p>We could extend this
example by adding additional service builder methods, or by showing how to
inject dependencies. See <a shape="rect"
href="defining-tapestry-ioc-services.html">the service documentation</a> for
more details.</p><h1 id="TapestryIoCModules-AutobuildingServices">Autobuilding
Services</h1><p>Main article: <a shape="rect"
href="defining-tapestry-ioc-services.html">Defining Tapestry
IOC Services</a></p><p>An alternate, and usually preferred, way to define a
service is via a module's bind() method. The previous example can 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;">package org.example.myapp.services;
import org.apache.tapestry5.ioc.ServiceBinder;
@@ -134,27 +87,8 @@ public class MyAppModule
binder.bind(Indexer.class, IndexerImpl.class);
}
}</pre>
-</div></div>
-
-<p>For more details, see see <a shape="rect"
href="defining-tapestry-ioc-services.html">Defining Tapestry IOC Services</a>.
In most cases, autobuilding is the <em>preferred</em> approach.</p>
-
-<p>Generally speaking, you should always bind and autobuild your services. The
only exceptions are when:</p>
-
-<ul><li>You wish to do more than just instantiate a class; for example, to
register the class as an event listener with some other service.</li><li>There
is <em>no implementation class</em>; in some cases, you can create your
implementation on the fly using JDK dynamic proxies or bytecode
generation.</li></ul>
-
-
-<p>The bind() method must be static; an exception is thrown if the bind()
method exists but is an instance method.</p>
-
-<h1 id="TapestryIoCModules-Cacheing_ServicesCachingServices"><span
class="confluence-anchor-link"
id="TapestryIoCModules-Cacheing_Services"></span>Caching Services</h1>
-
-<p>You will occasionally find yourself in the position of injecting the same
services into your service builder or service decorator methods repeatedly
(this occurs much less often since the introduction of service autobuilding).
This can result in quite a bit of redundant typing. Less code is better code,
so as an alternative, you may define a <em>constructor</em> for your module
that accepts annotated parameters (as with <a shape="rect"
href="defining-tapestry-ioc-services.html">service builder injection</a>).</p>
-
-<p>This gives you a chance to store common services in instance variables for
later use inside service builder methods.</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 MyModule
+</div></div><p>For more details, see see <a shape="rect"
href="defining-tapestry-ioc-services.html">Defining Tapestry IOC Services</a>.
In most cases, autobuilding is the <em>preferred</em> approach.</p><p>Generally
speaking, you should always bind and autobuild your services. The only
exceptions are when:</p><ul><li>You wish to do more than just instantiate a
class; for example, to register the class as an event listener with some other
service.</li><li>There is <em>no implementation class</em>; in some cases, you
can create your implementation on the fly using JDK dynamic proxies or bytecode
generation.</li></ul><p>The bind() method must be static; an exception is
thrown if the bind() method exists but is an instance method.</p><h1
id="TapestryIoCModules-Cacheing_ServicesCachingServices"><span
class="confluence-anchor-link"
id="TapestryIoCModules-Cacheing_Services"></span>Caching Services</h1><p>You
will occasionally find yourself in the position of injecting the same services
int
o your service builder or service decorator methods repeatedly (this occurs
much less often since the introduction of service autobuilding). This can
result in quite a bit of redundant typing. Less code is better code, so as an
alternative, you may define a <em>constructor</em> for your module that accepts
annotated parameters (as with <a shape="rect"
href="defining-tapestry-ioc-services.html">service builder
injection</a>).</p><p>This gives you a chance to store common services in
instance variables for later use inside service builder methods.</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 MyModule
{
private final JobScheduler scheduler;
private final FileSystem fileSystem;
@@ -174,55 +108,13 @@ public class MyModule
return indexer;
}
}</pre>
-</div></div>
-
-<p>Notice that we've switched from <em>static</em> methods to
<em>instance</em> methods. Since the builder methods are not static, the
MyModule class will be instantiated so that the methods may be invoked. The
constructor receives two common dependencies, which are stored into instance
fields that may later be used inside service builder methods such as
buildIndexer().</p>
-
-<p>This approach is far from required; all the builder methods of your module
can be static if you wish. It is used when you have many common dependencies
and wish to avoid defining those dependencies as parameters to multiple
methods.</p>
-
-<p>Tapestry IoC automatically resolves the parameter type (JobScheduler and
FileSystem, in the example) to the corresponding services that implement that
type. When there's more than one service that implements the service interface,
you'll get an error (but additional annotations and configuration can be used
to ensure the correct service injected).</p>
-
-<p>For modules, there are two additional parameter types that are used to
refer to <em>resources</em> that can be provided to the module instance (rather
than <em>services</em> which may be injected).</p>
-
-<ul><li><a shape="rect" class="external-link"
href="http://www.slf4j.org/api/org/slf4j/Logger.html" >org.slf4j.Logger</a>:
logger for the module (derived from the module's class name)</li><li><a
shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ObjectLocator.html">ObjectLocator</a>:
access to other services<br clear="none">
-Note that the fields are final: this is important. Tapestry IoC is thread-safe
and you largely never have to think about concurrency issues. But in a busy
application, different services may be built by different threads
simultaneously. Each module class is a singleton, instantiated at most once,
and making these fields final ensures that the values are available across
multiple threads. Refer to Brian Goetz's <a shape="rect" class="external-link"
href="http://www.javaconcurrencyinpractice.com/" >Java Concurrency in
Practice</a> for a more complete explanation of the relationship between final
fields, constructors, and threads ... or just trust us!</li></ul>
-
-
-<p>Care should be taken with this approach: in some circumstances, you may
force a situation in which the module constructor is dependent on itself. For
example, if you invoke a method on any injected services defined within the
same module from the module class' constructor, then the service implementation
will be needed. Creating service implementations requires the module builder
instance ... that's a recursive reference.</p>
-
-<p>Tapestry detects these scenarios and throws a runtime exception to prevent
an endless loop.</p>
-
-<h1 id="TapestryIoCModules-ModuleClassImplementationNotes">Module Class
Implementation Notes</h1>
-
-<p>Module classes are designed to be very, very simple to implement.</p>
-
-<p>Again, keep the methods very simple. Use <a shape="rect"
href="defining-tapestry-ioc-services.html">parameter injection</a> to gain
access to the dependencies you need.</p>
-
-<p>Be careful about inheritance. Tapestry will see all <em>public</em>
methods, even those inherited from base classes. Tapestry <em>only</em> sees
public methods.</p>
-
-<p>By convention, module class names end in Module and are final classes.</p>
-
-<p>You don't <em>have</em> to define your methods as static. The use of static
methods is only absolutely necessary in a few cases, where the constructor for
a module is dependent on contributions from the same module (this creates a
chicken-and-the-egg situation that is resolved through static methods).</p>
-
-<h1 id="TapestryIoCModules-DefaultMarker">Default Marker</h1>
-
-<p>Services are often referenced by a particular marker interface on the
method or constructor parameter. Tapestry will use the intersection of services
with that exact marker and assignable by type to find a unique service to
inject.</p>
-
-<p>Often, all services in a module should share a marker, this can be
specified with a @Marker annotation on the module class. For example, the
TapestryIOCModule:</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(Builtin.class)
+</div></div><p>Notice that we've switched from <em>static</em> methods to
<em>instance</em> methods. Since the builder methods are not static, the
MyModule class will be instantiated so that the methods may be invoked. The
constructor receives two common dependencies, which are stored into instance
fields that may later be used inside service builder methods such as
buildIndexer().</p><p>This approach is far from required; all the builder
methods of your module can be static if you wish. It is used when you have many
common dependencies and wish to avoid defining those dependencies as parameters
to multiple methods.</p><p>Tapestry IoC automatically resolves the parameter
type (JobScheduler and FileSystem, in the example) to the corresponding
services that implement that type. When there's more than one service that
implements the service interface, you'll get an error (but additional
annotations and configuration can be used to ensure the correct service
injected).</p><p>For modules
, there are two additional parameter types that are used to refer to
<em>resources</em> that can be provided to the module instance (rather than
<em>services</em> which may be injected).</p><ul><li><a shape="rect"
class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html"
>org.slf4j.Logger</a>: logger for the module (derived from the module's class
name)</li><li><a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ObjectLocator.html">ObjectLocator</a>:
access to other services<br clear="none"> Note that the fields are final: this
is important. Tapestry IoC is thread-safe and you largely never have to think
about concurrency issues. But in a busy application, different services may be
built by different threads simultaneously. Each module class is a singleton,
instantiated at most once, and making these fields final ensures that the
values are available across multiple threads. Refer to Brian Goetz's <a shape
="rect" class="external-link" href="http://www.javaconcurrencyinpractice.com/"
>Java Concurrency in Practice</a> for a more complete explanation of the
relationship between final fields, constructors, and threads ... or just trust
us!</li></ul><p>Care should be taken with this approach: in some circumstances,
you may force a situation in which the module constructor is dependent on
itself. For example, if you invoke a method on any injected services defined
within the same module from the module class' constructor, then the service
implementation will be needed. Creating service implementations requires the
module builder instance ... that's a recursive reference.</p><p>Tapestry
detects these scenarios and throws a runtime exception to prevent an endless
loop.</p><h1 id="TapestryIoCModules-ModuleClassImplementationNotes">Module
Class Implementation Notes</h1><p>Module classes are designed to be very, very
simple to implement.</p><p>Again, keep the methods very simple. Use <a shape="
rect" href="defining-tapestry-ioc-services.html">parameter injection</a> to
gain access to the dependencies you need.</p><p>Be careful about inheritance.
Tapestry will see all <em>public</em> methods, even those inherited from base
classes. Tapestry <em>only</em> sees public methods.</p><p>By convention,
module class names end in Module and are final classes.</p><p>You don't
<em>have</em> to define your methods as static. The use of static methods is
only absolutely necessary in a few cases, where the constructor for a module is
dependent on contributions from the same module (this creates a
chicken-and-the-egg situation that is resolved through static methods).</p><h1
id="TapestryIoCModules-DefaultMarker">Default Marker</h1><p>Services are often
referenced by a particular marker interface on the method or constructor
parameter. Tapestry will use the intersection of services with that exact
marker and assignable by type to find a unique service to inject.</p><p>Often,
all services i
n a module should share a marker, this can be specified with a @Marker
annotation on the module class. For example, the TapestryIOCModule:</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(Builtin.class)
public final class TapestryIOCModule
{
. . .</pre>
-</div></div>
-
-<p>This references a particular annotation class, Builtin:</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(
+</div></div><p>This references a particular annotation class, Builtin:</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
@@ -230,21 +122,8 @@ public @interface Builtin
{
}</pre>
-</div></div>
-
-<p>The annotation can be applied to method and constructor parameters, for use
within the IoC container. It can also be applied to fields, though this is
specific to the Tapestry web framework.</p>
-
-<h1 id="TapestryIoCModules-FieldInjection">Field Injection</h1>
-
-<p>The @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Inject.html">Inject</a>
and @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectService.html">InjectService</a>
annotations may be used on instance fields of a module class, as an
alternative to passing dependencies of the module in via the constructor.</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>
-
-<p>Using this style, the previous example of a module class may be
rewritten:</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 MyModule
+</div></div><p>The annotation can be applied to method and constructor
parameters, for use within the IoC container. It can also be applied to fields,
though this is specific to the Tapestry web framework.</p><h1
id="TapestryIoCModules-FieldInjection">Field Injection</h1><p>The @<a
shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Inject.html">Inject</a>
and @<a shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectService.html">InjectService</a>
annotations may be used on instance fields of a module class, as an
alternative to passing dependencies of the module in via the
constructor.</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><p>Using this style, the previous
example of a module class may be rewritten:</p><div cl
ass="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 MyModule
{
@Inject
private JobScheduler scheduler;
@@ -261,8 +140,7 @@ public class MyModule
return indexer;
}
}</pre>
-</div></div>
-</div>
+</div></div><p> </p><p></p></div>
</div>
<div class="clearer"></div>