Guice: Lifecycle support

Created on 7 Jul 2014  路  117Comments  路  Source: google/guice

_From [email protected] on March 14, 2007 09:22:31_

Support for JSR-250 (javax.annotation) would also be very useful for all those people using init()
methods and the list.

The mapping I think is:

@PostConstruct -> Called right after construction
@Resource -> Analogous to @Inject
@PreDestroy -> No concept of destruction, is there?
@Generated -> Doesn't apply

_Original issue: http://code.google.com/p/google-guice/issues/detail?id=62_

Component-NewExtension Priority-Medium enhancement imported

Most helpful comment

We have no plans of implementing lifecycle support.

You can use Guava's Service + ServiceManager(https://github.com/google/guava/wiki/ServiceExplained) to have services with a lifecycle. The simplest way is to bind a multiset of Set<Service> and construct a ServiceManager with that set.

For things where you want to do something after creation/injection (otherwise known as provisioning), you can use a ProvisionListener (http://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/spi/ProvisionListener.html, bound with Binder.bindListener).

Guice has no concept of "finishing" a scope or object, so anything where you want to do something on-destroy must be done through a separate framework that's better suited to lifecycle management.

All 117 comments

_From dhanji on March 14, 2007 16:36:02_

Couldnt @Inject be made available on zero-arg methods (and invoked after all other
@Injects)? That would solve @PostConstruct

That being said, I feel that lifecycle methods are a legacy of setter-injection and
are superfluous in guice, especially as constructor injection is now on par with
spring-style setter injection (auto-wire with annotations).

It's also significant (different from guice) that @Resource (with no name=..)
connotes field names being used as ids. Should that be considered an implicit @Named?

_From peter.[email protected] on March 14, 2007 16:43:44_

lifecycle (which is what this is) will certainly be needed. +1 to hani's JSR-250 suggestion.

(and its bogus to say that cxtor injection is now "on par" with setting injection. picocontainer has been doing
cxtor injection just as long as spring has been doing setter (trivial to tweak pico to use annotations). guice just
does it in a super-elegant and java5-friendly way)

_From [email protected] on March 14, 2007 17:39:38_

Nooo!

@Inject on no-arg methods is a hack. Nothing is being injected, it'd be an abuse of the annotation.

I do think that @Resource should work the way it's supposed to too (via field name). Guice should be flexible
enough to be able to plug in different resolution mechanisms, and this is just one of them.

_From dhanji on March 14, 2007 18:27:15_

proper lifecycle is much more of an app-server/container issue. IMO I think lifecycle
is overkill (you can currently do it just fine with ctors and @Inject-ed methods).
just imho of course. =)

yes I am well aware pico did ctor injection long before anyone else, that's not what
I was referring to.

_From dhanji on March 14, 2007 18:29:00_

yea come to think @Inject on no arg was a terrible idea

_From kevinb9n on March 15, 2007 07:55:42_

I am also deeply suspicious of the entire idea of "initialization" as separate from
object construction. I think I'm lacking that great example that shows me why
construction is sometimes not enough.

That said, I can imagine some real value in an object being notified when its Scope
has let it go.  (Or, sometime after its Scope has let it go; and perhaps individual
Scopes themselves need the flexibility to govern how strong their guarantee is in
this regard.)  Some objects, while 'alive', consume resources. You might for example
need to close yourself some closeables.

I wonder if this could be accomplished by having Guice or the Scope detect that your
object implements Closeable.

Status: Accepted

_From [email protected] on March 15, 2007 07:58:59_

Here's a very simple example.

You have field injection, and would like to do some init work.

You can't do it in the ctor since the fields can't be injected until after the ctor has run.

If you want concrete 'init' work, imagine I want to cache some data from an injected DataSource, if it's a field,
how would I do this caching?

_From kevinb9n on March 15, 2007 11:04:51_

Stock answer: then don't use field injection?  Now I need more meat to the example to
tell me why it has to be field injection. :)

_From crazyboblee on March 15, 2007 14:03:26_

I'm inclined to lean on garbage collection for finalization logic. Or to delegate
responsibility to something like OSGi.

We really need an external post-injection/pre-scoping hook. Then you could do
whatever you want in a generic fashion:

1) Call an init() method or some annotated method.
2) Create a phantom reference to an object so you can close its resources before
garbage collection when the scope goes away.
3) Peform ad hoc injections. For example, Struts calls setters on interceptors with
parameters from the config file.

Maybe something like this:

interface ProviderInterceptor<T> {
  T intercept(Key<T> key, Provider<T> next);  
}

Then you could apply them like this:

void bindInterceptor(Matcher<Key<...>> keyMatcher, ProviderInterceptor<...> interceptor);

_From dhanji on March 15, 2007 17:45:01_

Im with kevin--use ctor injection its safer (final publication), better (obvious to
non-guice factories) and has a tight contract (cannot partially inject a ctor like u
can with fields).

the only reason I use field inj is convenience/laziness.

gc is probably a different stage of the lifecycle than closing/shutting down--we have
no control over gc, but my canonical example is: a servlet container may conceivably
want to signal a close hook to its beans (perhaps to cleanup the session), i.e.
injector.close(), which would be totally different to when those beans actually get
finalize()-d.

That having been said I still think proper lifecycle should be managed by an
appserver. Pico does both but clearly states them as disparate features in the doc.

_From crazyboblee on March 15, 2007 17:54:09_

I think we need more use cases. I've never actually needed to run code when the
session ends. If I really need to do this, I can always use the servlet API directly.
Sometimes I wonder if other frameworks support lifecycle methods just because it's so
easy to do.

_From dhanji on March 15, 2007 18:00:38_

I suppose ctor injection would be out if you were "reinjecting" an object (with
injectMembers) and wanted to rerun the init--in that case you could still fall back
on a setter/psuedo-ctor without needing an independent "init" method.

_From dhanji on March 15, 2007 18:05:21_

You may want to release resources on hotdeploys (like datasources)--which REALLY
shouldnt count on the gc but yea I cant think of many use-cases outside of
appserver-style ones.

I dont really like the idea of lifecycle in DI anyway.

_From james.strachan on March 16, 2007 00:04:08_

Here's a use case.

Being able to DI any POJO developed for use in Spring or EJB3. There's a ton of code
out there which relies on the Spring IoC model (injecting optional properties then
having a validation step after injection to double check things are OK). Most
libraries I'm aware of (Jetty, ActiveMQ et al) all tend to have their own
initialisation hooks. Indeed I'm not aware of any IoC container apart from Guice
which does not support at the very least an initialisation callback mechanism.

If you're writing really simple POJOs which only have a set of mandatory
dependencies, then sure constructor injection avoids the need for an init step (as
the Pico folks promoted years ago).

However as soon as you have complex objects with multiple optional properties which
may or may not be set, some of which may be mutually exclusive and need some kind of
on-start validation, its much much cleaner to have a single well defined init method
called (where you can check all the various optional parameters are fine and do any
on-start-up caching & calculation etc).

The great thing about the init method is its called by the IoC container in context
immediately after injection; so if there are any configuration issues (mostly the
init callback is used to double check configuration when optional injections are used
after-all) then the IoC container is capable of giving a better error message as its
aware of the module/binder/injector being used. This avoids a runtime barf later on
when the injection context & information is lost.

_From crazyboblee on March 16, 2007 08:23:24_

Sorry, I meant use cases for the "tear down"/"stop" side of things.

The general ProviderInterceptor mechanism I suggested above should be able to support
any type of "init" design--calling a method on an interface, calling an annotated
method, running external logic, etc.

_From james.strachan on March 17, 2007 00:29:22_

OK the common use case in EJB3 or Spring POJOs is to close down expensive resources
like JDBC connections and the like when a scope is closed; e.g. using a request-scope
for processing web requests or more commonly, singleton POJOs created within an
application scope.

e.g. its fairly common in web applications to have some singleton POJOs which need
closing down in the correct order (as there is often a dependency order so you wanna
close things down in the reverse order to which they were started). For things like
JDBC connections, background threads, sockets and the like you typically don't wanna
just pray and hope on GC kicking in and finalizers sorting it out for you. e.g. folks
usually want their web applications to close down nice and promptly.

This could be implemented using a provider interceptor; calling a stop method is just
a reverse of calling a start method etc. Its just the stop interceptor needs to
register the stop method call with a listener to Scopes closing down.

So to nicely support Spring POJOs we'd just look for DisposableBean interface; for
EJB3 we look for @PreDestroy then call 'em when the scope closes down (FWIW I'm not
sure what Spring does for non-singletons :)

_From kevinb9n on March 19, 2007 11:31:12_

The only action we plan to take on this is to resolve issue 78 .  After we do that we
should be able to close this one.

Owner: crazyboblee
Labels: -Type-Defect Type-Enhancement

_From ekuleshov on April 20, 2007 14:22:04_

Tear down/close hooks can be very useful for session-scoped beans that may hold
resources or need to notify someone else about their destruction.

_From stolsvik on June 05, 2007 09:47:12_

I have this "Spring-based" swing application that I'd like to convert to Guice, as
I'm fed up by the refactor-unfriendlyness of the string identifiers. I've just
started looking into Guice for real, so I might easily be missing lots..

However, right after ditching Spring from the classpath to start my convertion, I
quickly ran into the problem of destroy-methods. I'd like to be able to "reboot" the
entire application, and that obviously (at least to me, please enlighten me if I'm
missing something) requires a rather extensive use of destroying.

Is there a way to get hold of all objects that Guice have instantiated? Is it
possible to inject some kind of listener that lets me know which objects are created,
so that I could destroy them myself?

Basically, I'd like a Inject.destroy()/stop() method - but I'd be happy to make it
myself it is possible.. Hooks into the "internals" would be great.

_From crazyboblee on June 05, 2007 09:55:29_

Don't you have some root object you could just throw away and re-create? Is there
some reason that garbage collection won't work?

If not, construction listeners (coming in the next release) will do what you need.

_From stolsvik on June 05, 2007 12:06:43_

.. okay, listeners sounds good!

When it comes to garbage collection, I really don't like to rely on that for
"external resources" - I thought that was "basic java": you might, for example, use
up all your database connections if there suddenly are two or more db pools hanging
around, and System.gc() is just a _hint_ to the runtime that you'd like GC to happen.
Threads won't die either w/o some explicit "we're going down" message.

Googling "finalization java" gives several articles pointing out this fact, e.g.
"Don't rely on finalizers to release non-memory resources. ...But the same program
may fail on a different JVM whose garbage collector doesn't finalize often enough to
keep the program from running out of file handles."

(Really a mailinglist question, but..) Is there a timeframe for next version? Is
there a place where I can find such info myself?

_From crazyboblee on June 05, 2007 13:07:41_

You should release a critical resource in a finally block in close proximity to where
you acquired the resource. Waiting for a framework to call you back means you're
holding onto the resource longer than necessary and taking the risk that it won't get
cleaned up.

We don't have a concrete date for the next release yet, but it won't be long.

_From kevinb9n on June 05, 2007 13:59:00_

In other words, no object should ever hold a resource "occupied" between method
invocations?  Only within the confines of a single method call?

_From crazyboblee on June 05, 2007 14:25:51_

I wouldn't say that. More detailed use cases would help.

_From peter.kitt.reilly on June 05, 2007 15:17:06_

If objects are created in a scope, it only
makes sense that they can be informed that the scope
is gone.

The "classic" example is an object grabbing an expensive
non-gcable native in a scope and being informed that the
scope is gone - so it can release the resource in a timely
fashion. It may not be possible to release the resource
in the body of a function - i.t may for example be a handle
to a window.

_From stolsvik on June 06, 2007 17:40:48_

crazyboblee: so I should make my database _pool_ where I need a database connection,
and then kill it when I don't need the connection anymore in a finally? Great idea.

It is of course possible to handle _all_ external resources ("heavy Closables")
outside of Guice, and take care of destruction myself. That will however lessen the
value of Guice slightly, I believe.

(.. but so far I like it real good! XML-hell be gone!)

_From crazyboblee on June 06, 2007 18:09:05_

Ha ha. I was talking about releasing connections for example, but why does Guice need
to tear down my connection pool? When should this happen?

We're trying to find a solution to a problem we haven't really defined.

_From stolsvik on June 08, 2007 06:27:11_

bob: i think the thing here is "in and out of scopes", like kevin refers to comment 6.

If I'm instantiated within some scope, I'd possibly like to know when that scope is
no more, so that I can release any non-memory resources.

However, there is a difference between singleton and instance "beans" (objects) here.
Spring solves this by explicitly stating that the destroy methods won't be run on
"prototype" beans (which are "instance"), while singleton beans (which are default in
Spring), and the other scopes (request and (global) session) will have their destroy
run. http://www.springframework.org/docs/reference/beans.html#beans-factory-scopes-prototype This is pretty much OK, I think, since those "expensive" objects most likely will be
of a "singleton" character (a db pool, or some other ERP connection used throughout
some scoped call), while instance objects are of a "use and ditch"-character,
probably just holding onto memory, and should be able to cope with only their
finalizer being run, OR the method they're injected into should handle the closing.

This goes hand in hand with the logic that states that "don't clean anything other
than RAM in finalizers".

Thus basically, if only Guice somehow would let me known which objects it's currently
"caching" (since I guess it'll have to do just that to handle the "singleton scope"),
I could really manage destroy myself.

_From stolsvik on July 11, 2007 06:00:47_

As a further point towards init() methods.

I just got myself Brian Goetz's "Java Concurrency in Practice". In chapter 3.2.1
"Sharing Objects -> Publication and escape -> Safe construction practices" (p.41),
one may read "Do not allow the this reference to escape during construction". This
was actually something I hadn't thought about: if you in a constructor do some
EventListener registration, you let the not yet fully constructed object "escape",
and the eventlistener registration may invoke methods further down the line, or back
on the object. Another interesting issue is to start Threads in the constructor,
again exposing the not-yet initialized object to a new running stack context. This
obviously also goes for staring timers and threadpools. Both of these errors may lead
to a whole bunch of interesting fuck-ups.

Brian suggest as a solution "expose a start() or initialize() method...", or make the
constructor private, and expose a static factory method instead (that does the
"init()"). I guess this could be realized by using Providers, but wouldn't it be
easier with a @Initialize annotation possible on no-args methods?

_From stolsvik on July 11, 2007 12:47:54_

PS: I just realized that this bug concerns two entirely different concepts: the JSR
250 annotations, and object lifecycle handling.

I HIGHLY vote for the JSR 250 annotations being honored, natively, by Guice. One
should even consider to just drop (at least deprecate) the corresponding Guice
annotations.

(I also vote for the lifecycle methods (obviously, given my comments).)

_From stolsvik on August 08, 2007 06:40:24_

I just got this message: "This is a proxy used to support circular references
involving constructors. The object we're proxying is not constructed yet. Please wait
until after injection has completed to use this object."

a) Why doesn't it say which object we're talking about - the class?

.. but my point is b) This is what happens when I need to do initialization stuff in
the constructor (here obviously trying to use the injected stuff), not having a
dedicated init-method that could be invoked afterwards. How can i wait "until after
injection has completed", when I need to do initialization stuff, and Guice refuses
to have init-methods?!

.. but also c) Isn't silent proxying like this un-good (performance wise)? Spring
handles circular dependencies only if one of the classes in the circle have a setter
instead of constructor injection, which breaks the circle (it "eagerly caches the
instance for resolving circular dependencies"). (And spring have support for
init-method, did I mention that?! :))

_From [email protected] on February 13, 2008 10:14:14_

Following up on point 27, in a web application context, if you want to
redeploy the application many times without running out of memory, you
need to ensure that any resources that reference the web application's
class loader are properly freed or that any objects in the parent
class loader do not have references to objects inside the web
application.  The gc on its own cannot clean this up.

If you don't programmatically close the resources, then references
from them to the web application class loader will prevent the class
loader, any classes loaded by it and all static variables from being
gc'ed.  After a number of redeployments, the JVM runs out of permanent
generation space, throws a OutOfMemoryError and you have to bounce the
process.

One common resource that needs to be shutdown are any threads started
in the web application since they contain a reference to the class
loader.

So you need an explicit shutdown method.

See this page for a discussion of the different libraries that can
keep a class loader from being gc'ed. http://opensource.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669 In our case, we start an Ice server with 30 threads and a Java
memcached client which has its own pool management thread, both are
singletons.  As stolsvik stated, it looks like I would need to ask the
Injector for the singleton's that it constructed and then run a
shutdown method on them.

The one problem with this is that then I manually have to make sure I
shut them down in the correct order, when Guice already knows the
correct order from the dependencies when it constructed them.

_From limpbizkit on May 30, 2008 01:21:52_

I believe this could be implemented as a custom scope that remembers everything it's scoped. The scope
would know whenever it provides a given object, and it could track which object need to be disposed when
the scope ends.

Usually we have a hook when a scope is exited, and we could dispose the appropriate objects at that time.

The tricks:
 - finding dispose() methods. This could be a marker interface on the returned instance, on the Key's type, or 
even just an annotated method somewhere.
 - not leaking memory

The nice thing about implementing this as a custom scope is that it doesn't make Guice's internals more
complex than they already are. The bad thing about implementing it as a custom scope is that it competes
with Guice's built-in scopes for request, session, etc.. It would be reasonable for a first-pass at this to fork
Guice's servlet extension. And we might even fold-in the implementation if it seems to work okay.

Status: New

_From james.strachan on September 30, 2008 03:45:13_

I'm with limpbizkit; handling the @PreDestroy or close type of lifecycles is a responsibility of the Scope instances; as they are the objects capable of
knowing when the scope is closed - so it can register objects in the scope and then close them when it is being shut down.

Already the servlet REQUEST and SESSION scopes already maintain a registry of objects within that scope - and they are easily capable of knowing when
those objects go out of scope. So there really should be an easy way to register some kind of hook to process all objects about to be closed via a Scope
closing; we can then let folks register SPI hooks to invoke different shut down mechanisms (e.g. auto-detecting Spring's DisposableBean interface - or
using @PreDestroy or some other user annotation driven mechanism etc).

i.e. rather than the end user having to replace the standard guice scopes for REQUEST/SESSION to get the @PreDestroy / DisposableBean behaviour this
should be a standard feature IMHO. It may be that Guice out of the box comes with no registered destroy handlers, but we should allow folks to use
additional Guice libraries to support @PreDestroy / DisposableBean without having to move away from standard Guice scopes.

I'd also like to see a standard guice ApplicationScope that was easy to use; so folks could create one or more application scopes, let Guice do the
injection; then at some point later on, close the application scope and have all the singletons in that scope shut down cleanly (like folks do in Spring /
Pico / HiveMind / Plexus).

For the initialisation hooks, the guice framework knows when an object has been created; so the Scopes don't really need to be involved; but some
kinda post-construction handler mechanism would be cool - so folks could use the SPI to invoke methods annotated with @PostConstruct or invoke
objects with some kind of custom lifecycle interface like Spring's InitialisingBean.

So in summary, I'd love Guice to have some kinda lifecycle hook in the SPI which the default APPLICATION/REQUEST/SESSION scopes invoked on the
close of a scope and invoked on the post-construction of an object. Hopefully folks can register multiple implementations of this handler; so folks can
add an implementation for JSR 250, one for Spring, one for registering objects into the OSGi registry if annotated with something and for other
frameworks and custom lifecycle interfaces etc.

_From james.strachan on October 06, 2008 06:39:07_

I've taken a stab at adding support for @PreDestroy and Spring's DisposableBean lifecycles; building above my
patch for issue 78 : https://code.google.com/p/google-guice/issues/detail?id=78 .

So far they only work with Singleton scoped objects; but I've also added the functionality into the REQUEST and
SESSION scoped Scopes too - though I've not yet added any code to the Servlet package to invoke the close()
methods yet.

I've introduced a Closeable interface which a Scope or Provider can implement; so if a Scope implements
Closeable you can then close it down cleanly; ensuring that all objects are closed and each exception thrown
is collected (rather like we do with the Errors class when binding objects).

Also I've added a close() method to Injector so you can close down any singleton objects.

e.g.

  Injector injector = Guice.createInjector(...);

  // do stuff

  // now lets cleanly close down the singletons in this injector
  injector.close();

There are many possible strategies we can use to actually close down an object held within a
Singleton/REQUEST/SESSION scope . e.g. respecting java.io.Closeable; or using @PreDestroy on a method or
Spring's DisposableBean or some developer-defined lifecycle API/annotation mechanism etc.

So I've introduced a strategy interface, Closer which is a strategy to close objects down. So you can bind as
many Closer implementations into your binder and this patch will invoke them all on each object in the scope
being closed. e.g. so you could install the JavaIO, JSR250 and Spring closers to respect those lifecycles. If you
look at some of the Closer implementations in this patch it will become a bit more clear.

Note this patch has no effect to objects created outside of a singleton (and is currently not invoked for
REQUEST/SESSION scopes).

The code InjectorImpl.close() and REQUEST/SESSION scopes is fairly straightforward. The more complex
change was dealing with the Singleton scope; as the singleton SINGLETON object creates Providers for each
key which internally stores the singleton object. So to be able to close all the singletons on an injector you
need to iterate through all the Providers in the bindings looking for providers which are Closeable. Since
there's a lot of wrapping of Providers along with InternalFactory; I made a number of internal wrappers and
adapters also implement Closeable. This should have no runtime effect when folks don't invoke the
Injector.close() method.

Attachment: gist
   _complete_with_predestroy.patch_

_From sven.linstaedt on October 07, 2008 08:51:21_

Is there any chance to get these functionality as an _extension_ of guice? These
solution seems to add two (?) more dependencies (javax.annotation.* is part of JRE6)
to the framework. The majority of developers will use at most one of the lifecycle
mechanisms.

Solving this like limpbizkit had it in mind (using custom scopes) would allow us to
use different lifecycle demarcation mechanisms (javax.annotation, DisposableBean,
etc.) depending on the actual needs.

Additionally I would like to see a solution that does not based on a servlet
container. There are lots of people using guice in standalone applications and these
people might have a need for lifecycle support too ;) Lifecycle support should also
cope with other environments.

_From james.strachan on October 07, 2008 08:57:23_

BTW my patch is modular. The jsr250 module is optional (and is the module that depends on JSR250) ditto the
Spring code is in the spring module.

However the support for ConstructorInterceptor has to kinda go into the core guice package as its code is like
that of MethodInterceptor which is already in the core. The core guice module still just depends on the
aopalliance.jar so no new dependency has been introduced in the core module; the spring module is still
dependent on spring and the new optional jsr250 module is just dependent on the JSR 250 API

_From heinz.in.ulm on December 05, 2008 02:06:25_

Hi, i write this because of some frustation reading the block here. For me it seems
that some are thinking of guice as a tool for osgi and j2ee ONLY. if guice should be
just that - ok - but then guice should be renamed to just another tool to make the
j2ee world bigger. Guice is advertized as "next-generation dependency injection
container for Java 5 and later".
Back to the issue - guice outside of a managed container has no livecycle management
at all if field or method injections are used. Except for "constructor only
injections" there is no single point of "being initialized". But field and method
injection are part of guice - aren't they?
Isn't that missing livecycle a serious issue by itself? I think that's what Sun has
forseen with it's javax.annotation package in java6 - smart,because this is an
architecture issue not just a usage case.
Someone asked here for usage cases - beside I think that's the wrong question for a
fundamental package like guice - nevertheless here is one for a Swing based application:

I wanted to use guice in a swing based environment to bootstrap a Swing application.
Having hundreds of JPanel's needing access to hierachical application wide services.
In a single panel there may be 2 to 50 other JComponent's and other classes
constructed. So to use juice I found three choices:
1.) use guice and constructor only injectors for the panels- then I endup with
constructors with up to 50 parameters and initialize the panel inside of this huge
constructor - very very ugly
2.) pass (or inject) a Injector instance into all panels and use
injector.getInstance(...) - then I don't need guice - any singleton pattern could do
that same thing better.
3.) don't use guice
I think we end up to go with the option 3.)
Note: the application wide services in our case are hierachical  and would fit very
well into guice Scope and Stage concept - many of these services are not just
singletons. Guice would have helped a lot if there would be a point where the panels
could be "initialized" after being fully constructed (and injected). In this
environment there is no way around an init() or createComponent() or
postConstructed() pattern. Or you end up with "constructor-only" classes.
Just to strengthen my point for those knowing the Eclipse architecture: Eclipse
implementation solved this by using inheritance - ending up with a almost endless -
in my opinion - very ugly class hierachy of 10th of levels of inheritance. Any simple
eclipse panel (pane) knows by inheritance any service providers of eclipse!!! A
Service oriented architecture for an ui would have been much cleaner.

_From james.strachan on April 03, 2009 03:04:36_

Just to keep this thread up to date; using trunk of Guice its now easy to implement @Resource injection (this
works perfectly now in GuiceyFruit using the trunk of Guice) and @PostContruct is pretty much there - though
there's a potential ordering issue of post inject hooks being invoked before custom injections have all taken
place - see https://code.google.com/p/google-guice/issues/detail?id=351 The only missing piece now is being able to close resources which are bound to some scope (e.g. singleton,
request, session etc). There's no current way to implement @PreDestroy from JSR 250 or DisposableBean from
Spring using trunk of Guice.

I'll try refactor my old patches into a simpler patch just for this issue and spin up a new issue to track its
progress

_From dhanji on April 03, 2009 03:12:05_

"he only missing piece now is being able to close resources which are bound to some scope (e.g. singleton,
request, session etc). There's no current way to implement @PreDestroy from JSR 250 or DisposableBean from
Spring using trunk of Guice."

Why not? you can register the objects before firing post-construct and provide an api or jvm shutdown hook to
call pre-destroy...

_From james.strachan on April 03, 2009 03:36:13_

@dhanji: actually thats a neat idea :)

I'm gonna take a stab at trying to implement that.

My only reservation is that all the scopes (application, request, session) already store the objects (they have
to so that they can be reused within the scope).

So all we need really need is a way of iterating through all the objects in a scope so they can be closed. (e.g.
iterating through the request/session scopes in the servlet or through the injector's bindings for application
scope). It does feel a bit dirty and inefficient having another Map for each application/request/session scope
and copying all objects into them just because Guice can't expose a hook to process all objects within a
scope.

But in the meantime you're idea is a great workaround :)

_From james.strachan on April 03, 2009 03:47:53_

@dhanji: it also saves me the dread of trying to merge an old massive & complex patch against trunk of Guice
which has changed alot - many thanks :)

_From dhanji on April 03, 2009 04:20:58_

@james.strachan

=)

You can hook into most of the scopes, by rebinding the annotations to your own scoping wrapper and fire the
destroy event appropriately. Note that Guice Servlet already fires destroy() properly on the servlet lifecycle event
and can be hooked into in webapps...

_From elijah.epifanov on April 13, 2009 16:27:00_

Why didn't anyone mention a hibernate Session, which MUST be closed after use?

_From elijah.epifanov on April 13, 2009 16:40:06_

And more provocative question:

  • How can you call a Scope scope when it can't terminate?

This is just to highlight that a tool that provides means of creating objects must
also provide means to properly destroy them. Or else how could I create an expensive
object except of in Scopes.SINGLETON?

_From [email protected] on April 13, 2009 17:09:11_

@45

"Why didn't anyone mention a hibernate Session, which MUST be closed after use?"

If you use warp-persist this is done for you on transactions or Http requests (or any granularity of session,
really). You can even set up a scope around the session or transaction, which is consistent with our philosophy to
keeps scopes simple (by making scoping orthogonal to domain use cases).

_From james.strachan on April 15, 2009 08:49:27_

BTW the patch on this issue: https://code.google.com/p/google-guice/issues/detail?id=354 provides a
solution to the last remaining issue with lifecycle support - being able to iterate through objects within a
scope so that you can close them (other than using a scope specific work around such as the servlet
request/session scopes that @dhanji mentions). We're using this mechanism right now in GuiceyFruit to
support @PreDestroy and Spring's DisposableBean interface.

I'm not sure which way this will go though; there's more discussion on various possible implementations here: http://groups.google.com/group/google-guice/browse_thread/thread/da6af0961cf4a5d6 I certainly hope that some mechanism can be added though :)

_From ericaro on January 05, 2010 08:48:02_

for the one expecting the feature, here is a "snipper" of mine:
//annotatedMethods is a simple method that return a list of any methods (and super ones, that has the given annotation)
public static <T extends Annotation> List<Method> annotatedMethods(Class<?> target, Class<T> annotationClass) {
                List<Method> methods = new ArrayList<Method>();
                while (target != null) {
                        for (Method m : target.getDeclaredMethods()) {
                                T annotated = m.getAnnotation(annotationClass);
                                if (annotated != null) {
                                        methods.add(m);
                                }
                        }
                        target = target.getSuperclass();
                }
                return methods;
        }

// the type listener itself
public class JFormDesignerTypeListener implements TypeListener {

public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
                Class<? super T> raw = typeLiteral.getRawType();
                List<Method> methods = annotatedMethods(raw, PostConstruct.class);
                typeEncounter.register(new JFormDesignerInjector<T>(methods));
}
}

//and the JFormDesignerInjector :

class JFormDesignerInjector<T> implements MembersInjector<T> {
        private List<Method> methods;
        public JFormDesignerInjector(List<Method> methods) {
                        super();
                        this.methods = methods;
                }

                /*
                 
@param t
                 */
                public void injectMembers(final T t) {

                        SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                        for (Method m : methods) {
                                                try {
                                                        m.setAccessible(true);
                                                        m.invoke(t, null);
                                                } catch (InvocationTargetException ite) {
                                                assert false : "Static Exception Occurred. @PostConstructor Method raises an exception:" + t.getClass() + ":" + m.getName() + " raises :" +
ite.getTargetException() + " : " + ite.getTargetException().getMessage();
                                  &n...

_From ericaro on January 05, 2010 08:48:02_

...bsp;             } catch (Throwable e) {
                                                assert false : "Static Exception Occurred. @See logs for more details in: " + JFormDesignerInjector.this.getClass().getName() + " " +
e.getMessage();
                                                }
                                        }
                                }
                        });
                }

I've tried to simplified my actual code ( in fact I've mixed bean  injections from JFormDesigner and @PostConstructor ).

The main idea here is to use the swing invokelater to handle the PostConstructor. this is quite nice for "swing" requirements ( as I had ).

_From limpbizkit on July 22, 2010 23:32:12_

Dhanji and I discussed this at length this evening. We're thinking about taking a Service interface, inspired by the one in Guava, with these methods. Note that start() is renamed to startAsync() and likewise for stop:
  interface Service {
    boolean isRunning();
    State state();
    Future<State> startAsync();
    void startAndWait();
    Future<State> stopAsync();
    void stopAndWait();
  } https://code.google.com/p/guava-libraries/source/browse/trunk/src/com/google/common/base/Service.java?r=49 In addition, we'd like to support listeners on services, so objects could register to be notified when a service changes state. The granularity of registration may be by service instance or perhaps by Guice Key.

We were also discussing the interplay between services and scopes. It might be useful to create a scope that's keyed off of a Provider<Service> for a particular service, and whose objects are in scope only while a service is running. This idea isn't fully baked.

_From james.strachan on July 23, 2010 00:59:24_

Hooray!

Whatever Service interface you decide to go with, please make sure there's some kind of ServiceStrategy so we can plug in adapters to it - as there's a zillion different mechanisms out there for basically calling a 'start' and a 'stop' on a bean (JSR 250, Spring's IniitializingBean / DisposableBean then most frameworks add their own API with some kind of start/stop method - the JDK has Closable etc).

Being able to stop a scope would rock too.

_From sberlin on July 23, 2010 05:36:59_

Some thoughts, based on previous lifecycle stuff I've written to cooperate with Guice...

  both startAndWait & startAsync (similarly both stopAsync & stopAndWait) is unnecessary.  xAndWait can be done by calling get() on the returned future of the async method.
 
 I've found an 'initialize' state to be useful -- that is, a state between & State.RUNNING.  (likely two states: State.INITIALIZING & State.INITIALIZED), with a method Future<State> initialize().  This lets a lot of services that are interdependent make sure that they each have a proper setup before starting.  (The service manager would call initialize on everything before starting anything.)
  While there should be a granularity on services per service (or key), there should also be a way for a single listener to be notified of all service state changes.
 
 There should be an easy way to schedule periodic Runnables/Callables (similarly to ScheduledExecutorService), to ensure that they start when the service starts & stop when the service stops.  Something easier than delegating to a SecheduledExecutorService, capturing the returned ScheduledFuture in start & stopping it in stop.. because that usually either goes wrong (forgetting null checking), or is ignored (no stopping).
 * There should be some concept of service order.  Doesn't need to be exact, but I've found buckets (early, middle, late) to be very helpful.

_From christianedwardgruber on July 23, 2010 11:33:41_

There's no need for the manager to call everything before anything is returned - we have a dependency graph, we can just call startup along the dependency chains.

Anyway, Jesse Wilson and I had a similar conversation about five weeks ago (I think) and came to a similar conclusion about an interface.  I was working up a proposal, but hadn't seen this bug.  I DO think it's important that we not go with the "start everything" approach.  Too much up-front hit, I think.  Wiring should happen up-front, but one point of separating out wiring from config from startup is to keep the costs of these pieces of work separate (and maintainable).

The other thing that needs to happen with any lifecycle system is a strong set of recommendations on where to do what kinds of work, so people have a clue.  So much work is done in providers and constructors to-date, that having good instructions could ease migration to using the lifecycle in a maintainable and sane way.

_From christianedwardgruber on July 23, 2010 11:34:03_

And yes, I'm volunteering. :)

_From sberlin on July 23, 2010 11:48:47_

We have a dependency graph for use/construction dependencies, but not for service requirements.  It's fairly often that a service (Foo) needs other services (Bar, Baz) setup (either initialized or up & running) before Foo can start, despite Foo not having a Guice-visible dependency on Bar/Baz.

_From christianedwardgruber on July 23, 2010 11:55:00_

Why would Foo not have guice visible dependency on Bar/Baz, if Guice is actually creating the wiring graph... I don't mean it has to have a direct visible dep on Bar or Baz, but it should have a sort of transitive dependency on those that Guice, having wired up the graph first, knows about.

Picocontainer does it this way and it works nicely.  Components which need lifecycle implement the start() semantics, and the container starts them in dependency order as-needed.  What am I missing about how Guice handles things?  Or is the lifecycle proposal external to the Injector entirely?

_From dhanji on July 23, 2010 12:38:07_

We discussed this at length, and were pretty convinced that best solution is for the user to manage the dependency order with the help of a CompositeService:

Service.start() // called from main()

CompositeService -> calls Service1.start(); Service2.start(); etc.

_From sberlin on July 23, 2010 13:10:58_

@dhanji -- So long as multiple .start() calls are ignored (the service isn't started twice), and the returned Future from latter calls still works for blocking.. that seems like a good plan.  I'm a little scared about having an insanely large CompositeService -- kind of like an additional Module, except for service ordering instead of object wiring.

@cwg -- It's often the case that a service has no need for a real "wiring" dependency on something else, but it still has a service dependency on it.  It would be ashame, I think, to force an object dependency on it.  This has been what's nice about Guice not including lifecycle as part of a base feature -- it separates lifecycle dependencies from object dependencies.

_From undeconstructed on July 23, 2010 13:20:33_

I have an interest in the Service approach being talked about here, but to me that seems to be a separate issue to how this started out.  Recently I was trying to implement a service architecture on Guice, but ran into various issues that made a quick solution impractical. A major one being the difficulty in finding which bindings are really services, when the interfaces they are bound to do not indicate this. That is, finding implementations that are singletons with the required "Service" interface, even when the bean itself might be bound to a provider method, returning only a public interface for the service it offers.

The easiest way around this was (unfortunately) to switch to Spring, which has two separate lifecycle concepts, 1) injection lifecycle (init, destroy, etc,) 2) context lifecycle (start, stop). These two are well defined, but also pretty simplistic, in that you get only one context lifecycle, that will always start every bean with the right interface, as long is it is defined at the top level in the config.

What I think would be more interesting to experiment with for this use case is a general purpose service framework, built on top of Guice. This layer would be able to offer features such as promotion of some interfaces from an injector as services, while hiding all implemention; more complicated state management (initialized, starting, started, going offline...); or even automatic proxying/remoting.  It might be possible to do something like:

configure() {
  bind(Someimpl.class)
  bind(InternalThing.class).to(another.class)
  bindAsService(MyService.class).to(myserviceimpl.class)
}

And then have MyService available to inject into other modules, while the InternalThing binding would only be visible to those locally defined bindings.

However, I don't really see this as a responsibility of Guice - Guice just proviides some mechanisms that could really simplify the work.

_From christianedwardgruber on July 23, 2010 13:24:54_

<sigh>

I was afraid this was where Guice was going to go...

I wholeheartedly disagree that composite-service wtih a separate listing of dependency is the way to go.  For me, a collaborator dependency graph IS the order in which B needs A, and usage-order/start-order implies construction order (as in, if B needs A to be started before it needs to be started, it surely needs A to exist before it needs to exist.  Even if it doesnt' know about A, because it's transitive.

So I don't see it as an artificial dependency, but an absolutely natural one, implicit in the creation graph.

But even if it was artificial, with a CompositeService (which isn't really a "feature" of guice, as I can do this with a Multibinder today), you're basically specifying a separate, duplicate wiring which (as I said) overloads (to an extent) the creation graph.  That's maintaining metadata twice, which (again, to me) is really hard to maintain.

I've long considered the lack of lifecycle a bug, not a feature, and a radically bad design choice, and what I've seen in terms of people adding work to constructors/providers as a "workaround" the missing feature (to me) justifies this view.

I'll dig back through the bug and conversations and see if I can't convince myself otherwise, but I"m afraid I wasn't convinced when I first read the arguments about "we're an injector not a container" and I suspect I won't find much new to convince me.

And I'm sorry if I'm a little snippy in this bug thread, but I had built up hopes and I'm actually really disappointed in this decision, because I really really really want to like Guice, and it's clean in so many other ways.

_From [email protected] on July 23, 2010 14:14:41_

My problem with the Service approach is just the same as it is with every other proposed solution. The attitude is 'we'll come up with something complex to address every single case, then it's up to the community to do the simplification that 95% of apps need'.

Sure, the Service interface would do the job. Except I now have to implement an interface, and I suddenly have to know about concurrency and futures and states.

If I'm the kind of person who knows al that, chances are I'm also clever enough to do all that in my @PostConstruct method.

I accept the religious argument against any external dependencies (or rather, am resigned to it). So how about guice specific versions of the standard annotations? Hell, give them the exact same name and just put them in a guice package. That way the totally awesome google code wouldn't have to be polluted with javax filth.

Also sorry for the snippy tone, probably cos I'm angry at myself for forgetting to celebrate the 3 year anniversary of this issue!

_From dhanji on July 23, 2010 14:53:55_

@60 What do you mean by a implies b ordering, in practical terms? Are you saying you want any class in the injector that impl's Startable to have start() called on it? Trying to understand... certainly don't want you to stop liking Guice!

@hani We can support the javax.* annotations as an optional module using Service. The Service scheme is mainly meant to nail down the conceptual programming model. There's no problem with supporting different annotations.

_From christianedwardgruber on July 23, 2010 15:51:27_

Ok, I have a possible proposal alternative, whipped up by some fellow googlers and I this afternoon, incorporating some of this discussion's pros and cons, and some thoughts from my convo with Jesse.  I'm going to try to put it together into something coherent, with at least sample usage code over the next few days.

Side notes:
@62 - Yes, before it's supplied as a dependency, if it implements lifecycle (either the service interface (or annotation or however it's indicated)

@61 - 3 years... heh.  Too funny.

_From limpbizkit on July 24, 2010 00:51:19_

@61: the goal of Guava's service interface is to do the concurrency for you. Clients who want to start services just call start/startAndWait(). Those methods are idempotent and allow you to shutdown a service asynchronously. People defining their own service implement AbstractExecutionThreadService, where they implement startup, run loop, and shutdown methods. http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/util/concurrent/AbstractExecutionThreadService.html

_From mcculls on July 27, 2010 01:59:15_

@61 FWIW you can use @PostConstruct with Guice if you add the https://code.google.com/p/guiceyfruit/ extension. This uses the same SPI that I used to re-implement Plexus as an extension on top of Guice.

On a side-note, to support Plexus lifecycles I took the simple approach and used an InjectionListener to track instances that implemented the various Plexus lifecycle interfaces - for each instance I ran through the appropriate startup sequence. This worked because for all cases (so far) the startup sequence matched the injection sequence. When the container stopped I just did the calls in reverse.

So basic lifecycle support is already possible using the SPI in trunk - I also think it's better for this to be an extension rather than baked into core, as there will always be someone who wants a different model.

_From james.strachan on July 27, 2010 02:26:04_

@mcculls yes - the problem isn't the 'start' part of lifecycle, its easy to do with the existing hooks. The big problem is trying to do a 'stop/close' or @PreDestroy in a clean way without hacks like forking guice (which guiceyfruit had to do) or writing your own custom Scope objects etc. (FWIW your idea only works if the stop hooks map exactly to the start hooks, which isn't the case in JSR 250).

We should be able to create an Injector, look up some objects then close down all the singletons for example without jumping through too many hoops. (Ditto Request / Session scope in guice-servlet).

Guice knows which objects have been created in a particular scope - they are stored in that scope (thats what a scope is afterall), so its kinda trivial to be able to iterate through a scope so you can close the objects - it just requires a fairly trivial change to guice to be able to do such a thing... https://code.google.com/p/google-guice/issues/detail?id=354 Right now there are only a small subset of real 'stop' lifecycles you can do without hacking your own replacement Scopes, forking guice or solving a small subset through hacks (basically creating your own mirror scope keeping track of all the objects you post process in a start interceptor).

_From cowwoc%bbs.darktech.[email protected] on January 25, 2011 21:55:36_

How about implementing this feature incrementally? Does anyone disagree with the fact that the built-in scopes (I'm thinking REQUEST/SESSION scopes here) should clean up all Closeables at the end of each request/session? That seems pretty non-controversial to me. The beautiful part is that invoking close() multiple times is guaranteed to have no-effect so this feature won't conflict with @PreDestroy.

_From james.strachan on January 26, 2011 00:51:12_

I don't see why any particular Scope should be special and be able to do proper lifecycle starting & stopping of resources while others are not. Whether a Scope is application/singleton or page/request/session or some other kind of scope (conversation or whatnot) - its a pretty basic requirement to be able to cleanly start and stop resources without developers having to patch/hack/fork a DI container or jump through silly hoops.

Pico & Spring have supported this for like 5 years; they make it easy for a developer. Its pretty sad there's still a discussion on this 4 year old issue which has been fixed in pretty much all DI engines ever - apart from Guice :(. I still can't fathom the push back. Maybe Guice committers just really get off on saying no? :)

_From kvaster on November 05, 2011 05:48:34_

Telling the truth, I don't understand why guice have no good lifecycle support yet...
Mycilla guice is good, but it is not so good as it should be.
Errors on container start are not properly handled. i.e. some instances are already started when error occurs. in that case all services should be stopped which were already started...

_From kvaster on November 27, 2011 15:02:26_

And what about injector creation errors ? Some services may be already started in case of partially created injector and we defenitely need to stop them...

_From kvaster on December 24, 2011 11:59:17_

Just in case somone interested.
mycilla-guice works ok for @PostConstruct and @PreDestroy for me, but I had one problem: guice+mycilla does not work ok when guice fails to create injector (in case some of services failed to start). Theese patches add:

  • do not allow to recreate singleton objects after error
  • perform destroy upon injector create error

Attachment: gist
   _mycilla-destroy-on-error.patch_
   _guice-singleton-recreation.patch_

_From crazyboblee on March 13, 2012 22:06:27_

This issue is still open? :-)

I'd recommend against adding a sophisticated service lifecycle management framework to Guice. This could be a framework in and of itself. Of course, such a framework could integrate with Guice.

5 years ago, I didn't want Guice to depend on @PostConstruct and @PreDestroy because this would have created a dependency from Guice on Java EE. This would have been unacceptable because core Guice needs to run on platforms like Android.

Today, these annotations are part of core Java (since Java 6). Functionality that depends on these annotations could fail fast when the annotations aren't present (Java 5, Android, etc.). For example, Injector.shutDown() would throw a runtime exception.

Simple support for @PostConstruct and @PreDestory might make since.

It wouldn't make sense to support @PostConstruct alone. It exists because @Resource supports only fields and methods. Guice supports constructors and does not need something like @PostConstruct. However, if we support @PreDestroy, we should almost certainly support @PostConstruct, too, to avoid confusion.

Do we need @PreDestroy support? If so, how exactly should it behave? What level of flexibility do we need with regard to concurrency (asynchronous, parallel), exception handling, invocation ordering, etc.? Does it apply to only objects instantiated by Guice or all objects? What's the compatibility story?

To answer these questions, we need concrete, real world use cases (examples) for @PreDestroy. We need lots of examples, and in each case, @PreDestroy should be the best way of addressing that use case.

Finally, when it comes to the implementation, we need to take care not to introduce performance regressions, even if that means making this an "opt-in" feature. Performance is already bad enough on Android.

_From [email protected] on March 13, 2012 22:26:58_

Hey Bob,

Glad to see that you're still alive :)

I think that this feature needs to be split into two:

  1. A built-in @PreDestroy behavior that invokes close() on all instances of Closeable.
  2. Support for @PostConstruct, @PreDestroy and other annotations.

Everyone seems to be on-board for #1. There seems to be some controversy surrounding #2. Couldn't we resolve them separately?

_From crazyboblee on March 14, 2012 10:42:44_

I wouldn't use Closeable (#1) here. It would be surprising to me if Guice called close() on my objects just because they happen to implement Closeable. Also, "close" doesn't fit all of the use cases.

If anything, we'd support @PreDestroy, but again, what are the use cases? A looked through the first 20 or so pages of results on koders.com and didn't see one interesting usage. I can try to imagine some:

  1. Closing I/O resources
  2. Shutting down threads and executors
  3. Proactively freeing native memory
  4. Removing external references (listeners, etc.)
  ...

@PreDestroy doesn't seem like a good solution to any of these. Use try-finally, try-with-resources, references, explicit shut down logic, etc., instead, and your code will be less error prone and more maintainable. No offense intended to Hani and others than were on JSR-250, but my sense is that @PreDestroy is an annotation in search of a problem.

_From [email protected] on March 14, 2012 10:45:35_

The usecase I have is mostly in getting rid of Providers.

Basically, once everything is wired up (config) I want to then 'start stuff up', this includes making external connections based on bindings, and so on. It's a very good match for @PostConstruct.

@PreDestroy I haven't used. I tend to prefer explicit demarcation lines to denote scope ends, rather than have it done for me.

_From kvaster on March 14, 2012 11:28:43_

Basic use case:

* I want my beans to start once all is configured. Some beans needs to creat thread to process data e.t.c. This can be done in constructors...

  • Also I want my beans to shutdown properly. It means I want services to flush caches, to stop threads e.t.c. Usually it is not easy to stop properly...

_From sberlin on March 14, 2012 11:45:52_

I very much believe that lifecycles like "starting" should be handled explicitly.  Classes should implement 'Service' and can use multibinder to bind into a Set<Service>, and then the Services can be started.  This doesn't feel like dependency injection to me.

_From eric.jain on March 14, 2012 11:53:09_

I can live without @PostConstruct, but without @PreDestroy I have to remember which instances to close, which is error prone. If there is a better way, Id love to hear about it...

public class Application {

  private Injector injector;

  public void onStart() {
    injector = Guice.createInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(Foo.class).in(Singleton.class);
        ...
      }
    });
  }

  public void onStop() {
    injector.getInstance(Foo.class).close();
    ...
  }
}

_From kvaster on March 14, 2012 11:56:01_

Services should start in the proper order - all dependencies should start before. Same for stop. So it's really close to dependency injection.

_From kvaster on March 14, 2012 14:28:33_

Telling the truth, I am really satisfied with mycilla guice. BUT guice defenitely should include bug fixes from #676.
1) Guice does not throw errors on null values in injected fields, but it should.
2) Singletons are recreated many many times even if error occurs.

_From [email protected] on March 14, 2012 14:32:08_

Yes, I never use guice 'base', always go with mycilla instead.

_From christianedwardgruber on March 14, 2012 14:45:50_

Apparently I failed to post this to the group when I replied to this thread on the dev list. :(  Anyway,

I agree that in all cases I've encountered in my own industry experience, the dependency-construction wiring order was also the correct order for service start-up, and there are efficiencies that can be pulled out in terms of starting up services in parallel where they're independent, etc.  However, in many cases it wasn't "necessary" it was "one correct ordering" of service startup.

Besides,  in this case, what Guice needs to provide is additional API to walk the graph of objects along the dependency wiring, so an extension can do the work.  Service support doesn't need to be baked in to the core, and probably shouldn't, so those who aren't using such don't pay the performance penalty.

Put simply - Guice manages the metadata of the dependency graph related to construction/injection order.  And it also provides the activities of actually constructing the objects and injecting them.  And it provides the intermediate steps of registering bindings, building a wiring order, and keeping that dependency graph straight.  I think we can solve this with extensions, for those around whom the startup order is important.

I'm going to repeat Bob's call for use-cases.  Can we have a comprehensive set of use-cases for service startup that needs more than Sam B.'s Set<Service> or Map<StartOrdinal, Service> (inet.d style startup)?  My historical examples are all from code I can't admit to existing, and in the end we opted for alternatives that did have service startup built-in.  But if we're going to put engineering resources into it, either showing how you would have written a piece of real code that actually needs wiring order, and how you worked around, and why that workaround sucks - that would be helpful.  Also helpful would be for forks/extensions to Guice that have service facilities, to help us understand what they needed from within Guice to implement, and we can talk about how to create an API to support that.

_From francisdb on March 14, 2012 14:49:54_

Ain't this more about proper shutdown than startup?

_From kvaster on March 14, 2012 15:02:55_

Startup can be handled via constructors.
This is really more about shutdown.

_From christianedwardgruber on March 14, 2012 15:16:57_

Ok - sorry - shutdown was the key part of this, but startup handled by constructors?  That's really not ideal.  I don't think I'm comfortable with THAT being the recommendation on how to do initialization of services with Guice.

_From mcculls on March 14, 2012 15:35:33_

FYI, it's been really easy to make a lifecycle extension now the ProvisionListener API has been added: https://code.google.com/p/google-guice/source/browse/core/src/com/google/inject/spi/ProvisionListener.java We use this to add Plexus lifecycle support (the classic Initializable/Startable/Disposable interfaces) https://github.com/sonatype/sisu/blob/master/sisu-inject/containers/guice-plexus/guice-plexus-lifecycles/src/main/java/org/sonatype/guice/plexus/lifecycles/PlexusLifecycleManager.java#L129 The great thing about ProvisionListener is that you can use it to track dependency chains, which helps you decide the starting order of components. Note: with Plexus you can't simply just start a component on the constructor call because of cycles (which exist in legacy code) and because components use a lot of field injection.

_From kvaster on March 14, 2012 15:39:34_

Please, take a look on: https://code.google.com/p/google-guice/issues/detail?id=676 This bug is stop point when working with ProvisionListener for startup/shutdown.

_From sberlin on March 14, 2012 15:40:33_

(FYI, ProvisionListener is new in Guice head & not in a released version.  But +1 to using it.  It's extremely useful for stuff like this. We also use it to trace loading times of objects, etc..)

_From mcculls on March 14, 2012 15:50:06_

Re #676 our lifecycle support fails-fast so that hasn't been an issue for us, but I can see how it could affect others - can you perhaps add a testcase to demonstrate each scenario and verify the proposed fix?

_From [email protected] on March 14, 2012 16:05:39_

Bob,

I'm not suggesting that Closeable replace @PreDestroy. I'm saying: don't make us implement @PreDestroy for Closeable. Guice should provide this reasonable default behavior.

What's the harm in auto-closing Closeable instances once their enclosing scope is destroyed? There is no harm in doing so because the specification explicitly states "If the stream is already closed then invoking this method has no effect."

Common use-case: Closing database connections (if necessary) to prevent leaks.

_From crazyboblee on March 14, 2012 16:11:28_

> What's the harm in auto-closing Closeable instances once their enclosing scope is destroyed?

Maybe I don't want the object to be closed.

_From [email protected] on March 14, 2012 16:33:34_

Bob,

Hehe. Okay then :) Please provide a reasonable use-case where an out-of-scope Closeable object shouldn't be closed.

_From crazyboblee on March 14, 2012 16:42:38_

Sorry, cowwoc. Guice is explicit and not surprising. Someone maintaining your code and trying to figure out if/how a resource gets closed would no doubt be surprised to find out that Guice automagically does it for them.

_From crazyboblee on March 14, 2012 17:11:10_

I think closing/destroying objects when they go out of scope is a red herring.

It sounds like people really want the ability to start and stop per injector services in the right order. While the lifecycle of the service is the same as the injector's, the object isn't necessarily in singleton scope鈥搈aybe the service isn't eligible for injection into other objects (see Binder.requestInjection()).

@PostConstruct and @PreDestroy seem like a bad fit here. First, they don't speak to starting and stopping services. Second, and less important than the naming and semantics, using annotations will be slower and more error prone than using a marker interface.

How do we decide which objects are eligible to be started? Strawman: any object that's created or injected during injector creation. This includes eager singletons, objects passed to requestInjection(), and any transitive dependencies. Note: This could get a little weird if you use DEVELOPMENT vs. PRODUCTION stages.

One could use an InjectionListener named ServiceManager to collect any object that implements Guava's Service interface. After injector creation, you call ServiceManager.start(). ServiceManager stops collecting objects (by ignoring any further callbacks), and then it iterates over the objects in the order in which they were created鈥搒o you can use dependencies to control the order services are started in鈥揳nd it starts each service.

When you're ready to stop, call ServiceManager.stop(). It'll stop the services in the reverse order.

Once Guice supports concurrent singleton injection (by inspecting the dependency graphs), ServiceManager could keep track of which threads the callbacks come in on. Then it could make sure that objects instantiated in the same thread are also started in the same thread.

_From [email protected] on March 14, 2012 17:38:09_

So checking for a @PostConstruct is a performance hit when you're already going through all methods and fields checking for @Inject? Why is it any slower?

The flow as I see it is, if guice creates an object, it is responsible, once the full object graphs has been constructed, for calling @PostConstruct. I don't see it getting weird with things like .injectMembers() and .requestInjection(), in those cases @PostConstruct would not apply because guice did not construct the object. Admittedly with stages it might get weird, but nothing that well specified behaviour cannot address. For a novice/beginner dev, there are plenty of non-intuitive and cryptic behaviours and features in Guice, but they're pretty well specified so it's not terrible.

Keep in mind also that all this is possible. I have all the extra behaviour I'd like in Mycilla Guice. There's just some fundamental issue I must be misunderstanding as to why it's so unthinkable for Guice to get those features.

The 'prove we need it argument' is not very compelling anymore, 100 comments and 5 years on from the initial request. I'd like to reverse the challenge, and ask for a non-core Guice developer to argue we absolutely should not have it!

Clearly all arguments in favor of this feature are not ones that have resonated with any Guice developers, so just close it and say it'll never happen.

_From crazyboblee on March 14, 2012 17:56:52_

Iterating over methods and checking for an annotation is an order of complexity slower than "instanceof Service," especially if you didn't already need to reflect on those methods. This is just to say that it would be nice to not force this overhead on Android apps.

Why would we only start instances that Guice instantiated? Seems like an arbitrary limitation.

To be fair, I think you're asking for something different from what everyone else is asking for. Other people want to start/stop services, orthogonally to injector creation. That makes some sense to me, but needs further specification. For example, which objects exactly are eligible to be started?

You've said that you don't care about stopping things and you just want @PostConstruct. This does not make sense to me because @PostConstruct is barely different from a constructor. Also, if you just want @PostConstruct support, it's trivial to hook in with an InjectionListener already.

_From endre.stolsvik on March 14, 2012 19:46:47_

Quick question: Have Guice gotten intelligent about the order in which it instantiates objects?

Earlier, it just did one or the other random order, not caring about each instance dependencies, creating those annoying proxies when it got to any dependency it didn't already have available.

Then one got the option of specifying that proxies should not be used.

However, the order hadn't gotten any smarter, so one still could arbitrarily crash into the ordering-problem, only now it stops with exception, not creating the proxy.

This even though a simple reordering of the flow would have fixed it.

First create the leafs; the ones without dependencies. Then work your way up: Create instances whose dependencies at this point be fulfilled. If you at some point iterate through the entire list of "to be instantiated" w/o instantiating any, then you have a dependency-loop.

Loops are only evaluated by constructors. Fields and methods can always be injected afterwards.

.. which leads to my point #1 about stuff like @PostConstruct..

_From endre.stolsvik on March 14, 2012 19:52:41_

You need @PostConstruct because that would only be invoked after ALL dependencies have been injected - both the constructor and field/methods.

This because you might need some service of some injected instance to start up. And that instance was injected by means of field injection. No good with constructor startup then.

Also, according to JCIP IIRC, one shall not leak unfinished objects. In a constructor, you could e.g. register yourself with the OnIncomingUserEventService, and then your object instantiation crashes with a NPE for some other reason. Therefore, thou shall not ever do "startup stuff" in a constructor. Only construct yourself, do not e.g. attach yourself to other object graphs.

_From endre.stolsvik on March 14, 2012 20:12:46_

When you folks create features out of this request, please enable me to do custom initialization.

I have always ended up in needing several initialization phases, not only a single @PostConstruct.

What I've needed, is at least a "now you've got all your dependencies and configuration, do your init code", and then a "now you can do listener registration with each other".

So my ideal solution to this is to get a list (preferably in instantiation order) so that I can invoke my different init methods on the relevant objects. This could be fetched by user code when the injector was finished setting up the entire graph (and have invoked @PostConstruct?) - and then the user could would do what life cycling it needs to do.

What I currently do, is to have a LifeCycle service which instances can depend on. There is also the LifeCycled interface. The objects register with the LifeCycle service, either in constructor (which is bad according to JCIP), or in the method injecting the LifeCycle service (better). After injector is finished, I run through all the instances that have registered with the LifeCycle service, all of which shall implement the LifeCycled interface. I then invoke method "phase1" on all objects, then method "phase2" on all objects, etc. (On application shutdown, I have corresponding phase-destroy methods on the LifeCycled interface, which are invoked in the opposite order).

_From noctariushtc on March 14, 2012 22:17:02_

It would be nice to see some help in Guice to build a service framework but it isn't needed, since startup order of services could be possibly different from injection dependecy order.

In my framework I made it something like Bob meantioned. I used an the InjectionListenr / ProvisionListener to collect services implementing the frameworks service interface and after injection finished the frameworks ServiceManager collects and orders the services startup dependencies, searches for postConstruct() handlers and finally calls the startup() method of every service.
When the framework is shutting down first all services preDestroy() method is called and finally the destroy() method.
Right after that point the ServiceManager and the Injector are destroyed.

It was a bit tricky at some small points but that is more a problem of the framework, which can be sticked together from plugins (all have their own AbstractModule) and a plugin descriptor, not a Guice problem.

_From limpbizkit on March 14, 2012 22:17:18_

PROPOSAL 102.

Add an extension that uses Guava's Service interface, and that makes it easy to bind services and start them.

Perhaps a basic service registration DSL:
  class MyAppServiceModule extends ServiceModule {
    public void configureServices() {
      bindService(JettyService.class);
      service(JettyService.class).dependsOn(ConnectionPoolService.class);
    }
  }

Plus a mechanism to start and stop services. This could track user-specified service dependencies.

public static void main(String... args) {
  Stopwatch stopwatch = new Stopwatch();
  Injector injector = ...
  logger.info("Injector creation took " + stopwatch.elapsed());
  stopwatch.reset();

  ServiceManager serviceManager = injector.getInstance(ServiceManager.class);
  serviceManager.registerServiceFailureHandler(new ServiceFailureHandler() {
    public void serviceFailed(Service service, Throwable failure) {
      logger.log(WARNING, "Service " + service + " failed; shutting down", failure);
      serviceManager.shutdown();
    }
  });
  serviceManager.registerShutdownOnExitHook(); // gracefully shut down on CTRL-C
  serviceManager.startAllAndWait();
  logger.info("Service startup took " + stopwatch.elapsed());
  logger.info("Ready");
}

Ideally ServiceManager has a rich API that lets you do all the natural things you want to do with services. Stuff like starting them up, shutting them down, listening for state changes, printing statistics like startup time, and interrogating the dependency graph. It could even do its own logging (in a verbose mode?) to keep the common case concise.

_From noctariushtc on March 15, 2012 00:43:17_

A nice concept but isn't this the first step to make Guice a second Spring? Guice wasn't designed as an application framework, I'm not sure if it would be good to go that way.

_From marchign on March 15, 2012 14:16:48_

Using a marker interface or annotations makes no great difference to me.

I think that the reason why people (including me) request this feature is because it provides a simple machinery to forward the "scope begin" / "scope end" events to objects in that scope without requiring any dependency among who starts/stops the scopes and the object living there.

Following this view, I think that it would make sense to generalize the eagerness attribute to each scope: instead of bind(X).to(Y).asEagerSingleton(), one could use something like bind(X).toY().eager().in(Singleton.class). In this way one could perform some initialization phase at (session / request / whatever ) start time.

I think that this extension would also make less arbitrary the choice of which objects Guice should starts and stop. The user could force an object to be initialized (and destroyed) by Guice at scope beginning (end) simply by binding it eagerly in that scope.

_From [email protected] on March 15, 2012 14:44:18_

Regarding annotations vs marker interfaces, why would you need to iterate over the methods? Wouldn't you only scan the class itself for an annotation (same as a marker interface)?

_From [email protected] on July 16, 2012 11:03:09_

Unclear whether this needs to be in core, or can be fully expressed in an extension, but if it is to be, we need to expand the SPI to support it, as I think it would incur a cost on those who didn't need it if it were in core.  For now, I'm putting this into a "New" component in the issues, as we figure out how best to do this.

Status: Acknowledged
Labels: Component-NewExtension

_From antony.stubbs on November 07, 2012 06:40:24_

You guys might want to look at GuiceBox's @Stop annotation...

_From davide.cavestro on May 10, 2013 13:21:30_

Please note this is blocking even GWT/GIN @PostConstruct annotation implementation.
For GIN there's not 3rd party plugins available providing this kind of features, and GIN guys are waiting for this guice feature in order to introduce some useful features.
GIN issue tracker ref: https://code.google.com/p/google-gin/issues/detail?id=176

_From [email protected] on May 10, 2013 16:23:59_

Clarification: I said "I don't see this [@PostConstruct] being added without Guice chooses to do so".

We might end up having extensions points some time in the future and then one can write extension similar to that - but that is a different story...

_From mcculls on May 12, 2013 15:06:28_

Support for @PostConstruct and @PreDestroy is already available in the lifegycle extension: http://onami.incubator.apache.org/lifecycle/org.apache.onami.lifecycle.standard/index.html There is also a new listener hook implemented in trunk called ProvisionListener: https://code.google.com/p/google-guice/source/browse/core/src/com/google/inject/spi/ProvisionListener.java Which will enable more fine-grained and flexible lifecycle support. I currently use this to re-implement Plexus lifecycle support (involving legacy components with tricky dependency cycles and multiple lifecycle phases) on top of Guice.

_From davide.cavestro on May 12, 2013 23:20:57_

so, is lifegycle (and generally speaking guice extensions) directly compatible with GIN?

_From mcculls on May 14, 2013 03:16:51_

GIN only uses Guice at compile time, so additional work is required to support extensions - for example, assistedinject and multibinder have both been adapted in GIN (but the API/design is based on the original extension). See the various submodules under https://code.google.com/p/google-gin/source/browse/#svn%2Ftrunk%2Fsrc%2Fcom%2Fgoogle%2Fgwt%2Finject%2Fclient So while the API and code to support lifecycles is available, it will need to be adapted for GIN. Whether this is done by porting and re-implementing the underlying TypeListener/ProvisionListener API on top of GIN's GWT runtime, or by looking at lifegycle's higher-level design and porting that, is a question for the GIN folks.

(PS. the original home for lifegycle was http://99soft.github.io/lifegycle/ before it moved to Apache/Onami)

_From [email protected] on December 29, 2013 11:49:16_

Bob,

In comment #93 you said "Maybe I don't want the object to be closed." When I asked you for a concrete use-case you responded with some general statement about avoiding unexpected behavior.

  1. Do you have a concrete use-case where you wouldn't want to close() at the end of a scope? You asked me for a concrete use-case where you would want to do so, and I have provided one.
  2. In my view, we're not doing anything unexpected... certainly no more than closing resources at the end of a try-with-resources block. This behavior should be baked into the specification of what it means to be a Scope. Just to clarify: I am implying that request-scoped resources get disposed at the end of the request, but singleton-scoped resources do not. Meaning, we do not close() inherited bindings.

_From b.k.oxley on January 04, 2014 22:13:28_

This would be great & simple functionality to fold into Guice.  Lifegycle uses a simple type listener & module to implement, so the is optional, a good candidate for guice extensions.

Simply supporting "@PostConstruct" and "@PreDestroy" is 90+% of what I need in some of my projects.  Presently we depend on Spring; I would love to migrate to Guice for these.

+1, any plan to support this feature?
It's a very common functionality.

At the least, it would be great to have an official "We don't have this implemeted yet, but if you want to shutdown cleanly, do this."

We have no plans of implementing lifecycle support.

You can use Guava's Service + ServiceManager(https://github.com/google/guava/wiki/ServiceExplained) to have services with a lifecycle. The simplest way is to bind a multiset of Set<Service> and construct a ServiceManager with that set.

For things where you want to do something after creation/injection (otherwise known as provisioning), you can use a ProvisionListener (http://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/spi/ProvisionListener.html, bound with Binder.bindListener).

Guice has no concept of "finishing" a scope or object, so anything where you want to do something on-destroy must be done through a separate framework that's better suited to lifecycle management.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dxiao picture dxiao  路  4Comments

laurentmartelli picture laurentmartelli  路  11Comments

prasanthgithub picture prasanthgithub  路  14Comments

nathanmerrill picture nathanmerrill  路  5Comments

cobexer picture cobexer  路  6Comments