Governator is a library of extensions and utilities that enhance Google Guice with lifecycle management. The concept of lifecycle management has two aspects here.
- Injector lifecycle management via LifecycleListener
- Object lifecycle managmenet via @PostConstruct and @PreDestroy.
Governator also provides hooks through which additional features may be added to lifecycle management at the appropriate places. (see LifecycleFeature)
Governator provides a simple builder DSL on top of Guice's built in SPI to,
- provide a more readable fluent code
- Make injector creation policy driven
- constructing the list of modules provided to Guice.
LifecycleInjector injector = InjectorBuilder.fromModules(new MyApplicationModule());Once created the container can interact with the LifecycleInjector's lifecycle methods directly or asynchronously by registering a LifecycleListener in a Guice module. The injector's lifecycle may be terminated either by calling LifecycleInjector.shutdown() or by injecting LifecycleShutdownSignal and calling LifecycleShutdownSignal.shutdown().
For example, to block until the injector's lifecycle completes,
injector.awaitTermination();Or to get asynchronous notification of termination
injector.addListener(new DefaultLifecycleListener() {
public void onShutdown() {
// Do your shutdown handling here
}
});To shutdown the injector from outside of Guice call,
injector.shutdown();Or to trigger shutdown from an Injector managed class,
@Singleton
public class SomeServiceThatGetsAShutdownSignal {
private final LifecycleShutdownSignal signal;
@Inject
public SomeServiceThatGetsAShutdownSignal(LifecycleShutdownSignal signal) {
this.signal = signal;
}
private void someShutdownInvokingCode() {
this.signal.shutdown();
}
}You can also enable a JVM shutdown hook by adding ShutdownHookModule to Guice's list of modules
Governator.createInjector(new ShutdownHookModule(), new MyApplicationModule());When using DI all operations should be performed within the context DI such that initialization is done via dependency injection and eager singleton behavior. As long as eager singletons have been properly registered the entire application should be functional once the injector has been created. Sometimes, however, it may be necessary to perform post injector creation operations, such as registering that the application is ready to serve traffic. This can be done by implementing the LifecycleInterface from any eager singleton.
@Singleton
public class MyApplication extends AbstractLifecycleListener {
@Override
public void onStarted() {
applicationStatus.markAsUp();
}
}Governator includes several utilities to help debug problems and get insight into injector creation.
Sometimes Guice fails to create the injector and provides little information about which class or object creation path resulted in failure. Enabling the TracingProvisionListener will result in class names being emitted to standard output (can be customized to different outputs) and indented to give a clear path to the path through which objects were provisioned.
The ProvisionDebugModule tracks metrics about object instantiation and retains this information after the injector has been created. The information is later accessible via ProvisionMetrics. This can be used to provide a UI that gives a visual representation of the application bootstrapping processes, helping identify slow initialization paths.
public class MyApplication {
public static void main(String[] args) throws Exception {
InjectorBuilder
.fromModules(new ShutdownHookModule(), new MyApplicationModule())
.awaitTermination();
}
}public class StartServer extends GovernatorServletContextListener
{
@Override
protected Injector createInjector() {
return InjectorBuilder.fromModules(
new ShutdownHookModule(),
new JerseyServletModule() {
@Override
protected void configureServlets() {
serve("/REST/*").with(GuiceContainer.class);
bind(GuiceContainer.class).asEagerSingleton();
bind(MyResource.class).asEagerSingleton();
}
}
).createInjector();
}
}<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>StartServer</listener-class>
</listener>
</web-app>public class MyApplication {
public static void main(String[] args) throws Exception {
Governator.createInjector(
new JettyModule(),
new ShutdownHookModule(),
new JerseyServletModule() {
@Override
protected void configureServlets() {
serve("/REST/*").with(GuiceContainer.class);
bind(GuiceContainer.class).asEagerSingleton();
bind(MyResource.class).asEagerSingleton();
}
}
).awaitTermination();
}
}TBD
Governator is built via Gradle (http://www.gradle.org). To build from the command line: ./gradlew build
Governator binaries are published to Maven Central. Please see the docs for details.
Eran Landau (mailto:elandau@netflix.com)
Copyright 2015 Netflix, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.