There was a recent thread that discussed implementing the equivalent of Spring's "prototype" beans in Tapestry IOC. I was of the opinion that it wasn't possible to implement sensibly: you either run the risk of the service living too long or else Tapestry's proxies would mean that you created a new instance for every method call.
I've been thinking about this some more, and I've realised that the problem is about controlling the scope. Prototype beans in Spring are a bit problematic anyway and the reason is that the scope is started by a request to the container for the bean and then ended by the last reference being removed (GC). Sometimes the "call to the container" is hidden - so it's not very clear exactly what the scope is and that would be particularly true in Tapestry where the proxies and @Inject mechanisms hide the container well away from the client code. So I think that the key to doing a similar thing in Tapestry IOC is to make control of the scope explicit. This would be known as "manual" scope and the pattern would be something like this: ----------------- // This is provided by a hypothetical library and is actually 'perthread' scoped - so your manual scope is nested within a thread public interface ManualScope { // Opens the scope - error if already open void open(); // Closes the scope - error if not open void close(); // Runs 'r' inside the scope - error if scope is already open void run(Runnable r); } ----------------- // This is your module creating your manually-scoped service (somewhat equivalent to a spring prototype bean) public class MyModule { public static void bind(ServiceBinder binder) { binder.bind(MyService.class, MyServiceImpl.class).scope("manual"); } } ----------------- // This is your client code using the service @Inject ManualScope manualScope; @Inject MyService myManualScopedService; public void doSomethingOldSchool() { manualScope.open() try { myManualScopedService.doSomething(); myManualScopedService.doSomeMore(); } finally { manualScope.close(); } } public void doSomethingNewSchool() { manualScope.run(new Runnable() { public void run() { myManualScopedService.doSomething(); myManualScopedService.doSomeMore(); } }); } So the idea is that you can only use myManualScoped bean within the open()/close() pair, or within the run(). If you use it outside, you get a helpful exception. There other options for 'prototype' beans I can think of involve not having a service. Either: 1) Create a factory service; the client code injects the factory and calls a create() method. 2) Inject ObjectLocator and call autobuild() (gives you the benefit of dependency injection for a non-service object) Both of these are much simpler for the client. The manual scope is a bit clunky to use. The main benefit is that the service is a proper IOC service you can decorate it/advise it/override it and all kinds of other good IOC stuff. In addition, you have complete control over the lifetime of your service and potentially there could be a ManualScopeCleanupListener (similar to ThreadCleanupListener) to clean-up services when the scope closes. I'm pretty sure my work project would find it useful as, in Spring, I have one-shot "commands" that are prototype beans and we use Spring's AOP to add-on transactions, logging and auditing. This Manual scope idea would work quite well for that as we could use the IOC's decorating/advising capabilities. However, I'm not convinced that the clunkyness of the client code won't put people off using it and I'm not convinced that there are enough times that you want to use IOC magic (such as advice) on a "prototype bean". So, I'd appreciate some feedback on the idea. Can you think of any simplification I could make that makes it less clunky? Would you use it? Is it useful enough for me to write the implementation as open source? Useful enough to pester the committers to put it in the core IOC? Or just a bad idea that I've had late one evening :-) Thanks, - Paul --- This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and delete this e-mail. Any unauthorized copying, disclosure or distribution of the material in this e-mail is strictly forbidden. Please refer to http://www.db.com/en/content/eu_disclosures.htm for additional EU corporate and regulatory disclosures.