Dropwizard is a really nice, simple framework for developing RESTful web services. Out of the box it comes with all kinds of nice features by leveraging a collection of mature libraries in a straightforward manner. The main libraries it uses are Jetty for web serving, Jersey for REST, Jackson for JSON processing, along with others such as Google Guava, Hibernate Validator, Liquibase for migrations, and more. It also comes with out of the box support for JDBI, a simple "SQL convenience library for Java", as well as Hibernate.
The JDBI and Hibernate support provide the basics needed to get going with either of those frameworks, and the Hibernate support provides the @UnitOfWork
annotation for declarative transaction demarcation which you can apply to Jersey resource methods. Dropwizard then takes care of automatically opening a Hibernate session, starting a transaction, and either committing or rolling back that transaction and finally closing the session when the resource method completes. For many use cases this will be all you need or want.
In certain situations, though, you might want more control over transactions and for this Spring is often a good choice. Specifically, you might want to take an existing Spring backend codebase and integrate it into a RESTful web service using Dropwizard. Or maybe you are using Hibernate in a Dropwizard application but you don't want the transaction scoped around and entire resource method (which is what using the @UnitOfWork
annotation gives you out of the box). Maybe you aren't using Hibernate and are using JDBI, Spring JDBC, or Spring JPA and want to use Spring's native @Transactional
support. Or maybe you are not even using a relational database, and instead are using one of the Spring Data projects that support transactions in Neo4J, MongoDB, Redis, etc.
For situations like those described above, what you want is a simple way to use Spring in your Dropwizard application to manage transactions in DAOs or service classes, but not much else. In other words you don't need or want to use all the other many features provided in Spring, but you do want to take advantage of its automatic connection and transaction management. For Dropwizard projects I've been working on recently, we came up with a very simple abstraction and simple pattern to integrate Spring using a builder-style class to create application contexts. This makes Dropwizard configuration and other objects like ManagedDataSource
s available to the Spring context.
For example, suppose you will be using Hibernate in a Dropwizard application but want to use Spring to manage transactions. Suppose also that you configure a DataSourceFactory
via the normal Dropwizard configuration mechanism and want that to be used by Spring when creating the Hibernate session factory. Also suppose you want the Dropwizard configuration object to be available to the Spring context. Assuming you have a simple "todo" Dropwizard application with a TodoApplication
class and a TodoConfiguration
class, you can write code like the following in the TodoApplication
class:
@Override
public void run(TodoConfiguration configuration, Environment environment) throws Exception {
DataSourceFactory dataSourceFactory = configuration.getDataSourceFactory();
ManagedDataSource dataSource = dataSourceFactory.build(environment.metrics(), "dataSource");
ApplicationContext context = new SpringContextBuilder()
.addParentContextBean("dataSource", dataSource)
.addParentContextBean("configuration", configuration)
.addAnnotationConfiguration(TodoSpringConfiguration.class)
.build();
TodoDao todoDao = context.getBean(TodoDao.class);
TodoResource todoResource = new TodoResource(todoDao);
environment.jersey().register(todoResource);
}
In the above code, SpringContextBuilder
is a very simple builder-style class that lets you create Spring application contexts by specifying parent beans that should be available to other beans (e.g. the "dataSource" and "configuration" beans), and then adding either annotation-based configuration classes or XML configuration file locations. This class is available on GitHub here.
The above code creates a Spring context from which you can then extract the beans, such as TodoDao
, that will be used by Jersey resource classes. Note that we're not using Spring for autowiring dependencies in the TodoResource
class, and are simply passing the DAO to its constructor. The resource class has no idea that the DAO is actually a Spring-managed bean, nor does it need to. This also makes it very easy to inject a mock into the resource class for unit tests.
So the only thing left to do is actually create the Spring application context. In the above code, we're using the TodoSpringConfiguration
class which is a Java Config-based configuration class. The code below shows the basics, with a few details omitted:
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackageClasses = TodoDao.class)
public class TodoSpringConfiguration {
@Autowired
private DataSource _dataSource;
@Autowired
private TodoConfiguration _configuration;
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(_dataSource);
sessionFactory.setPackagesToScan(Todo.class.getPackage().getName()));
sessionFactory.setNamingStrategy(ImprovedNamingStrategy.INSTANCE);
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties hibernateProperties() {
// details elided...
}
}
As you can see, the TodoSpringConfiguration
class is just a plain Spring Java-based configuration class. The only real noteworthy thing is how we used @Autowired
to make the data source and Dropwizard configuration objects available. The sessionFactory()
configuration method then simply uses the data source when constructing the session factory. Other beans could use the Dropwizard configuration object, for example to extract other configuration such as Hibernate-specific configuration properties.
That's really all there is to it. You just use SpringContextBuilder
to create your Spring context, extract the beans you need, and pass them to Jersey resource classes or any other classes such as health checks. The classes using the Spring-managed beans can simply use them without needing to be aware of their Spring-managed nature. All of which helps keep your Dropwizard code clean while still gaining the advantage of powerful Spring features. The "todo" example application code is available on GitHub here along with instructions for building and running it.