Wednesday, October 21, 2009

Hibernate + Spring in Standalone application

Just a quick reminder howto use Hibernate + Spring in standalone application.
First comes hibernate session factory. I prefer to use separate file for hibernate, Instead of configuring it Spring's applicationContext.xml:

<bean name="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml"/>
<!-- Those package will be scanned for classes with persistence annotations -->
<property name="packagesToScan" value="net.test.domain"/>
<!-- Annotated package. Contains package-level configuration. -->
<property name="annotatedPackages" value="net.test.domain"/>
</bean>

Transaction manager:

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernate.session.factory"/>
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>

Next is hibernate session. Hibernate guys suggest to use HibernateDaoSupport class as base for your DAOs, but to be completely honest, I'm not really comfortable with it, because it adds really weird dependency on Spring in DAO classes. Instead, it looks more natural to use dependency injection, which is really Spring's approach. To archive that all you need to do is mark session definition as being scoped proxy, set scope to 'prototype' and define SessionFactoryUtils#getSession as factory method. In result, each call to "any_method" in hibernate session bean instance is converted to SessionFactoryUtils.getSession().any_method():

<bean name="hibernateSession" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession"
scope="prototype">
<constructor-arg index="0" ref="hibernateSessionFactory"/>
<constructor-arg index="1" value="false"/>
<aop:scoped-proxy/>
</bean>

And all together:

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean name="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml"/>
<!-- Those package will be scanned for classes with persistence annotations ->
<property name="packagesToScan" value="net.test.domain"/>
<!-- Annotated package. Contains package-level configuration. -->
<property name="annotatedPackages" value="net.test.domain"/>
</bean>

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<bean name="hibernateSession" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession"
scope="prototype">
<constructor-arg index="0" ref="hibernateSessionFactory"/>
<constructor-arg index="1" value="false"/>
<aop:scoped-proxy/>
</bean>

<bean name="someDao" scope="singleton" class="net.test.TestDAO">
<property name="session" ref="hibernateSession"/>
</bean>
</beans>

In DAO class there is no need to worry about session management, "tx:annotation-driven" will do all work for you. The only thing, which developer has to think about is appropriate usage of transaction annotations.

5 comments:

Александр said...

I always have been and still am sure that what they call "enterprise" programming on Java is programming in XML. ;-)

Stas said...

Well, that's just configuration, what did you expect? But, yeah, anyway, lots of XML, more than in C(++) :)

phil pirj said...

Well, fck XML

If you could spend more time onself-education with Ruby (at least, there are even more exiting platforms out there), you would forget this awful undebuggable xml stuff

Dir.new('models').each do |file| require "models/#{file}" if file=~/\.rb$/ end

DataMapper.setup(:default, ENV['DATABASE_URL'] || ENV['DATABASE_URI'] || "sqlite3://#{Dir.pwd}/db.sqlite3")
DataMapper.auto_upgrade!

that's instead of annoying H mappings with g/setters

get '/admin/users' do
check_admin_authorization

users = User.all
haml :'admin/users', :layout => !request.xhr?, :locals => {:users => users}
end

instead of annoying spring bean confs

how much is that?
hmmm, people say almost 50% faster than hibernate+spring
how could that be? ruby is 10 times slower than java?
i wonder, too.
but who finally cares how fast java is? dev's time is much more expensive, even during this prolonged recession period

Stas said...

Looks like you are comparing wrong things. Have no idea how Ruby works, but looks like you are using lots of "default" stuff there.

If you do not need declarative transaction management, there is much less configuration to do with H and no Spring part. All you need is just a hibernate config with driver reference and connection string and here you go.

Also, if you have a look, there is no stuff related to mapping there. You can use even "automatic configuration" if you want to it doesn't require any explicit mapping. Or you can use annotations. You can even avoid get/set methods, if you don't like them.

Also, hibernate is not such an easy thing, that's very sophisticated framework, therefore configuration is not the simplest as well. Want something simpler - go for iBatis.

I think, is not so bad, as you are trying to show :)

lauren said...

As you mentioned that using separate files for hibernate is a good approach as this makes the code more easy to change and maintain .As well as easy to read.Now a days i am working on a project that need Hibernate + Spring so was reading some blogs for best conventions to be used
digital signature sharepoint