Skip to content

Lifecycle annotations

Allows using lifecycle annotations for initialization/destruction methods in guice beans. Main motivation is to replace Managed usage in places where it's simpler to just annotate method, rather than register extension.

  • @PostCostruct - same as Managed.start()
  • @PostStartup - called after server startup (application completely started)
  • @PreDestroy - same as Managed.stop()

Setup

Maven:

<dependency>
  <groupId>ru.vyarus.guicey</groupId>
  <artifactId>guicey-lifecycle-annotations</artifactId>
  <version>7.1.4</version>
</dependency>

Gradle:

implementation 'ru.vyarus.guicey:lifecycle-annotations:7.1.4'

Omit version if guicey BOM used

Usage

By default, no setup required: bundle will be loaded automatically with the bundles lookup mechanism (enabled by default). So just add jar into classpath and annotations will work.

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import ru.vyarus.guicey.annotations.lifecycle.PostStartup;

public class SampleBean {    

    @PostConstruct
    private void start() {
        // same time as Managed.start()
    }

    @PostStartup
    private void afterStartup() {
        // application completely started
    }

    @PreDestroy
    private void stop() {
        // same time as Managed.stop()
    }
}
  • Annotated methods must not contain parameters. Method could have any visibility.
  • @PostConstruct or @PostStartup methods fail fails entire application startup (fail fast)
  • @PreDestroy method fails are just logged to guarantee that all destroy methods will be processed
  • If both current class and super class have annotated methods - both methods will be executed (the only obvious exception is overridden methods)

Important

If bean is created on demand (lazy creation by guice JIT), annotated methods will still be called, even if actual lifecycle event was already passed. Warning log message will be printed to indicate this "not quite correct" execution, but you can be sure that your methods will always be processed.

Reducing scope

Annotations are applied using guice TypeListener api which means that all guice beans are introspected for annotated methods.

If you want to limit the scope of processed beans then register bundle manually (in this case lookup will be ignored):

GuiceBundle.builder()
           .bundles(new LifecycleAnnotationsBundle("package.to.apply"))
           .build()

In this example only beans lying in specified package will be checked.

Also, direct Matcher implementation could be specified for more sophisticated cases. For example, if I want to exclude only one class:

new LifecycleAnnotationsBundle(new AbstractMatcher<TypeLiteral<?>>() {                               
           @Override
           public boolean matches(TypeLiteral<?> o) {
               return o.getRawType() != SomeExcludedBean.class;
           }
       })