tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Tapestry Inversion of Control FAQ
Date Mon, 29 Apr 2013 16:04:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Tapestry+Inversion+of+Control+FAQ">Tapestry
Inversion of Control FAQ</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~hlship">Howard
M. Lewis Ship</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        eager loading<br />
    </div>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{note} <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
How do I make my service startup with the rest of the application, rather than lazily? <br>
<br>Tapestry services are designed to be _lazy_; they are only fully realized when needed:
when the first method on the service interface is invoked. <br> <br>Sometimes
a service does extra work that is desirable at application startup: examples may be registering
message handlers with a JMS implementation, or setting up indexing.  Since the service&#39;s
constructor (or [@PostInjection|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PostInjection.html]
methods) are not invoked until the service is realized. <br> <br>The solution
is the [@EagerLoad|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html]
annotation; service implementation classes marked with this annotation are loaded when the
Registry is first startup, rather than lazily. <br> <br></td></tr>
            <tr><td class="diff-unchanged" >{scrollbar} <br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Injection+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Injection+FAQ">Injection
FAQ</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions">Frequently Asked Questions</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/Security+FAQ">Security
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Security+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>

<h2><a name="TapestryInversionofControlFAQ-TapestryInversionofControlContainer"></a>Tapestry
Inversion of Control Container</h2>

<p>Main article: <a href="/confluence/display/TAPESTRY/IoC" title="IoC">Tapestry
IoC</a></p>

<div class='navmenu' style='float:right; background:#eee; margin:3px; padding:3px'><table
class="tableview" width="100%">
            <tr><th style="padding: 3px 3px 3px 0px">Related Articles</th></tr>
                        <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Tapestry+Inversion+of+Control+FAQ">Tapestry
Inversion of Control FAQ</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/IoC">IoC</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/IoC+cookbook">IoC cookbook</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Tapestry+IoC+Overview">Tapestry
IoC Overview</a>
        
                                            </td>
        </tr>
            </table>
</div>

<h3><a name="TapestryInversionofControlFAQ-WhydoIneedtodefineaninterfaceformyservices%3FWhycan%27tIjustusetheclassitself%3F"></a>Why
do I need to define an interface for my services?  Why can't I just use the class itself?</h3>

<p>First of all: you can do exactly this, but you lose some of the functionality that
Tapestry's IoC container provides.</p>

<p>The reason for the split is so that Tapestry can provide functionality for your service
around the core service implementation.  It does this by creating <em>proxies</em>:
Java classes that implement the service interface.  The methods of the proxy will ultimately
invoke the methods of your service implementation.</p>

<p>One of the primary purposes for proxies is to encapsulate the service's life cycle:
most services are singletons that are created <em>just in time</em>.  Just in
time means only as soon as you invoke a method.  What's going on is that the life cycle proxy
(the object that gets injected into pages, components or other service implementations) checks
on each method invocation to see if the actual service exists yet.  If not, it instantiates
and configures it (using proper locking to ensure thread safety), then delegates the method
invocation to the service.</p>

<p>If you bind a service class (not a service interface and class), then the service
is fully instantiated the first time it is injected, rather than at that first method invocation.
Further, you can't use decorations or method advice on such a service.</p>

<p>The final reason for the service interface / implementation split is to nudge you
towards always coding to an interface, which has manifest benefits for code structure, robustness,
and testability.</p>

<h3><a name="TapestryInversionofControlFAQ-Myservicestartsathread%3BhowdoIknowwhentheapplicationisshuttingdown%2Ctostopthatthread%3F"></a>My
service starts a thread; how do I know when the application is shutting down, to stop that
thread?</h3>

<p>This same concern applies to any long-lived resource (a thread, a database connection,
a JMS queue connection) that a service may hold onto.  Your code needs to know when the application
has been undeployed and shutdown.  This is actually quite easy, by adding some post-injection
logic to your implementation class.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class MyServiceImpl <span class="code-keyword">implements</span>
MyService, RegistryShutdownListener
{
  <span class="code-keyword">private</span> <span class="code-object">boolean</span>
shuttingDown;

  <span class="code-keyword">private</span> <span class="code-keyword">final</span>
<span class="code-object">Thread</span> workerThread;

  <span class="code-keyword">public</span> MyServiceImpl()
  {
    workerThread = <span class="code-keyword">new</span> <span class="code-object">Thread</span>(.
. .);
  }

  . . .

  @PostInjection
  <span class="code-keyword">public</span> void startupService(RegistryShutdownHub
shutdownHub)
  {
    shutdownHub.addRegistryShutdownListener(<span class="code-keyword">this</span>);
  }

  <span class="code-keyword">public</span> void registryDidShutdown()
  {
    shuttingDown = <span class="code-keyword">true</span>;

    workerThread.interrupt();
  } 
}
</pre>
</div></div>

<p>After Tapestry invokes the constructor of the service implementation, and after it
performs any field injections, it invokes post injection methods. The methods must be public
and return void.  Parameters to a post injection method represent further injections ... in
the above example, the RegistryShutdownHub is injected into the PostInjection method, since
it is only used inside that one method.</p>

<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/forbidden.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td>It is <b>not</b>
recommended that MyServiceImpl take RegistryShutdownHub as a constructor parameter and register
itself as a listener inside the constructor. Doing so is an example of <a href="http://www.ibm.com/developerworks/java/library/j-jtp0618.html"
class="external-link" rel="nofollow">unsafe publishing</a>, a remote but potential
thread safety issue.</td></tr></table></div>

<p>This same technique will work for any kind of resource that must be cleaned up or
destroyed when the registry shuts down.</p>

<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>Be careful not to invoke methods
on any service proxy objects as they will also be shutting down with the Registry. A RegistryShutdownListener
should not be reliant on anything outside of itself.</td></tr></table></div>

<h3><a name="TapestryInversionofControlFAQ-HowdoImakemyservicestartupwiththerestoftheapplication%2Cratherthanlazily%3F"></a>How
do I make my service startup with the rest of the application, rather than lazily?</h3>

<p>Tapestry services are designed to be <em>lazy</em>; they are only fully
realized when needed: when the first method on the service interface is invoked.</p>

<p>Sometimes a service does extra work that is desirable at application startup: examples
may be registering message handlers with a JMS implementation, or setting up indexing.  Since
the service's constructor (or <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PostInjection.html"
class="external-link" rel="nofollow">@PostInjection</a> methods) are not invoked
until the service is realized.</p>

<p>The solution is the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html"
class="external-link" rel="nofollow">@EagerLoad</a> annotation; service implementation
classes marked with this annotation are loaded when the Registry is first startup, rather
than lazily.</p>

<style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Injection+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Injection+FAQ">Injection
FAQ</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions">Frequently Asked Questions</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/Security+FAQ">Security
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Security+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Tapestry+Inversion+of+Control+FAQ">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23335247&revisedVersion=13&originalVersion=12">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message