This post originated from an RSS feed registered with Java Buzz
by Brian McCallister.
Original Post: Lightweight Spring
Feed Title: Waste of Time
Feed URL: http://kasparov.skife.org/blog/index.rss
Feed Description: A simple waste of time and weblog experiment
Now that CrazyBob started the Spring
backlash it seems like a good idea to talk about how useful
Spring is... even when you don't use it as a container =) Maybe I
should leave out the even in that considering how many people
are piling on Bob's bandwagon. Ah well, I still like Spring, even if
I quite dislike it's XML. So, Lightweight Spring -- getting
the goodness without the thirty second startup time and pages of
XML.
People get all excited about transactions and the hibernate (or OJB
or JDO or JDBI, I just use hibernate as an example here as people
get all gushy-eyed about the Spring hibernate integration)
integration, well, you can do all that without the XML pretty
easily:
public void testSomething() throws Exception
{
SessionFactory sessionFactory = getSessionFactory();
final String name = "Brian";
PlatformTransactionManager transactionManager =
new HibernateTransactionManager(sessionFactory);
final HibernateTemplate hibernate = new HibernateTemplate(sessionFactory);
TransactionTemplate transactions = new TransactionTemplate(transactionManager);
Something s = (Something) transactions.execute(new TransactionCallback()
{
public Object doInTransaction(TransactionStatus transactionStatus)
{
return hibernate.execute(new HibernateCallback()
{
public Object doInHibernate(Session session) throws HibernateException
{
return session.createQuery("select s from Something s where s.name = :name")
.setString("name", name)
.uniqueResult();
}
});
}
});
}
Basiclaly here we use its nice transaction management stuff
completely programmatically. Not bad. You can do the same thing with
the JdbcTemplate:
PlatformTransactionManager ptm = new DataSourceTransactionManager(getDataSource());
TransactionTemplate transactions = new TransactionTemplate(ptm);
final JdbcTemplate jdbc = new JdbcTemplate(getDataSource());
Long count = (Long) transactions.execute(new TransactionCallback()
{
public Object doInTransaction(TransactionStatus transactionStatus)
{
return jdbc.queryForLong("select count(id) from something");
}
});
Now, why would you do this? It gives you resource cleanup,
transaction rollback on exceptions, flexibility in terms of what
kind of transaction you use (the hibernate platform works for a data
source as long as the session factory uses the same data source, the
JTA one can be plugge din pretty transparently, etc), you can nest
transactions inside these callbacks and the expected behavior
(joining transactions, sub-transactions, etc). It is pretty nice to
work with.
Now, a couple catches. First, you need to make sur ethe transaction
callback is the outermost as Spring binds resources to the
transaction, not the thread. This is kind of subtle as the
transaction is bound to the thread, but if you had the jdbc callback
around the transaction callback, the connection wouldn't be bound to
the transaction, despite visually looking like it would be. You also
lose control over which connection you have inside a given
transaction, which usually doesn;t matter, but it might if you want
to do a lot of prepared statement reuse for one connection across a
lot of transactions. So it isn't a solution to everything,
but few things are.
The other very useful thing I have found myself doing frequently
with Spring-As-LIbrary instead of Spring-As-Container is using is
using the ServletRequestDataBinder to bind request
params to beans in other servlet contexts:
Something s = new Somthing();
ServletRequestDataBinder binder = new ServletRequestDataBinder(s, "");
binder.bind(servletRequest);
Such a simple thing, but so very common if the framework you are
using at the moment doesn;t quite line up with what you need to
do. The empty string, by the way, is a prefix, so name would
map to Something#setName(String) in the above example,
but if we has used new ServletRequestDataBinder(s, "s")
then s.name would be bound to
Something#setName(String). Commons-BeanUtils comes
close to doing this, but I couldn'f find anything in there that
played as nicely with the servlet request. It must be there, but
it was hidden, or didn't work as I needed it, cannot recall now =(