-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 
Author Message
 Post subject: Service --> DAO architecture using Hibernate & Spring
PostPosted: Tue Nov 11, 2003 6:22 am 
Expert
Expert

Joined: Fri Nov 07, 2003 4:24 am
Posts: 315
Location: Cape Town, South Africa
Hi

I am a Spring/Hibernate newbie, but would like some advice/opinions on the following architectural questions/suggestions.

IM(H)O services provide use-case-centric operations for the application whereas DAO's provide a finer grained access to the domain model. I would therefore like to control transactions at the service level and take advantage of the SessionFactory utilities provided by the HibernateDaoSupport class at the DAO level. In addition, it is a requirement to be able to throw Application Exceptions, and I therefore steer clear of the templating framework provided by Spring.

I have a simple service class which implements the interface:
Code:
public interface BankService {   
   void transfer(long fromAccount, long toAccount, int amount)
             throws OutOfFundsException;
}


My service class is proxied using the org.springframework.transaction.interceptor.TransactionInterceptor class which handles the transactional side of things, starting and commiting/rolling back the transaction as required. (I get my service classes via a ServiceLocator which gets a handle to the ApplicationContext via a ServletContextListener at startup).

The implementation of this class BankServiceImpl utilises the AccountDAO class to deposit amounts into the respective accounts utilising hibernate specific code. The AccountDAO extends HibernateDaoSupport and thus requires a valid session to exist for the method:

Code:
Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);

to succeed.

The class therefore needs to be proxied by the org.springframework.orm.hibernate.HibernateInterceptor or a session needs to be supplied to every method (from the service layer). I don't like the latter option. The former option however implies that I need to get a proxied version of the DAO class from the Application Context, possibly using the ServiceLocator again.

I know that this is a trivial example and that the architecture seems to be overly-complicated for the requirements, but it is merely a prototype. Am I on the right track here? My main concern revolves around how I get to my DAOs from my service objects - do I pass a Session around (gut feeling - no - as this ties me in to Hibernate code) or do I go via the Application.getBean() methods - to get a proxied version?

Regards from a sunny Cape-Town, SA


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 11, 2003 8:05 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
Your service objects should receive DAOs and other collaborating objects via bean references, instead of looking them up themselves. Have a look at the skeletons and sample apps that come with the Spring distribution for example configurations. Basically, it would look as follows:

Code:
<beans>

  <bean id="mySessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    ...
  </bean>

  <bean id="myDataAccessObject" class="dao.MyDataAccessObject">
    <property name="sessionFactory">
      <ref bean="mySessionFactory"/>
    </property>
  </bean>

  <bean id="myServiceObject" class="service.MyServiceObject">
    <property name="dataAccessObject">
      <ref bean="myDataAccessObject"/>
    </property>
  </bean>

</beans>


MyServiceObject just needs to expose a bean property "dataAccessObject" of type MyDataAccessObject, i.e. a setter method "setDataAccessObject(MyDataAccessObject)", to receive its collaborating DAO instance. It does not need to know about the Spring application context or any custom service locator - IoC applied.

Of course, you can proxy any of these beans: You just need to link the proxied beans as bean references in the application context definition then - your application objects do not have to care. From the outside, you will possibly just access "myServiceObject", as the rest are just collaborating objects that the service object internally needs to handle its responsibilities.

You could use Spring's ApplicationContext itself as service locator, instead of wrapping it with a custom service locator. You can simply fetch a reference to the ApplicationContext from within a Struts action via WebApplicationContextUtils.getWebApplicationContext(ServletContext), for example. With Spring's own web MVC, you don't need to do that in the first place, as you can use bean references again to link your web controllers with your service objects.

Regarding Session handling: You're right - NEVER pass Session instances around as method arguments. With or without HibernateInterceptor, your DAO will participate in transactions, as SessionFactoryUtils.getSession is transaction-aware. If no transaction, the DAO will simply execute non-transactionally with its own Session. Transaction detection works via ThreadLocals internally, but you don't have to worry about that.

Note that HibernateInterceptor is mainly there to avoid the need for SessionFactoryUtils.closeSessionIfNecessary calls in DAO implementations. Additionally, it allows to configure the Session outside of your DAO implementation via bean properties of the interceptor, e.g. the flushing behavior. When using HibernateInterceptor, you should fetch your session with allowCreate=false in any case - the interceptor handles the Session lifecycle then.

Alternatively, if you allow your getSession calls to create a Session and write proper try-catch blocks in your DAOs, you can get correct lifecycle behavior without HibernateInterceptor. The following would be proper DAO code, participating in transactions or executing non-transactionally if no current transaction:

Code:
public myDataAccessMethod() {
  Session session = SessionFactoryUtils.getSession(getSessionFactory(), true);
  try {
    // do some Hibernate access with the Session
  }
  catch (HibernateException ex) {
    SessionFactoryUtils.closeSessionIfNecessary(session, getSessionFactory());
    throw SessionFactoryUtils.convertHibernateAccessException(ex);
  }
}


Regarding the templating approach: If you need to throw checked application exceptions, it's indeed better to choose alternative ways, particularly for transaction demarcation: ignore TransactionTemplate then, TransactionInterceptor or the combo convenience class TransactionProxyFactoryBean are more appropriate choices. I tend to prefer such declarative transaction management in general, as it avoids repetitive TransactionTemplate code in each transactional service method.

HibernateTemplate is a bit different, as it not only provides the callback implementation mechanism but also a lot of pre-built convenience methods. For typical simple Hibernate access code, it can reduce your DAO implementation methods to one-liners:

Code:
public Account loadAccount(int id) {
  return (Account) getHibernateTemplate().load(new Integer(id));
}


I recommend using those convenience methods for most cases, just falling back to manual Session handling if you really need to throw a checked exception from *within* Hibernate access code. It often turns out that checked application exceptions can easily be thrown *after* the Hibernate access code, which works nicely with HibernateTemplate too.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 11, 2003 8:14 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
P.S.: I guess you already know the article at http://www.hibernate.org/110.html - please have a look at the examples there, they illustrate many of the basic principles. There are still some issues that are not discussed in the article yet, though; I rework it from time to time, so it should be getting there :-)

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 11, 2003 8:36 am 
Expert
Expert

Joined: Fri Nov 07, 2003 4:24 am
Posts: 315
Location: Cape Town, South Africa
Thanks for the advice.

The reason I was wrapping Spring's WebApplicationContext in my custom service locator was because I was locating DAOs from my service layer and wasn't happy propagating the web context up into the business logic tier (for the lookup). Your suggestions provide a clean solution to this.

Thanks again

Justin


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 11, 2003 10:17 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
drj wrote:
Thanks for the advice.

The reason I was wrapping Spring's WebApplicationContext in my custom service locator was because I was locating DAOs from my service layer and wasn't happy propagating the web context up into the business logic tier (for the lookup). Your suggestions provide a clean solution to this.

Thanks again

Justin


I agree that the service layer shouldn't see a WebApplicationContext in any case. If you ever need to make your service objects aware of the application context, use the ApplicationContext interface that WebApplicationContext is a sub-interface of. In test suites or other environments, you can easily pass a non-web ClassPathXmlApplicationContext or StaticApplicationContext to your service objects then.

Note that if an application object implement Spring's ApplicationContextAware interface, it will automatically receive a reference to the containing application context on startup - you do not need to pass the application context to them yourself. Furthermore, there's the ApplicationObjectSupport base class that provides a convenient pre-built implementation of ApplicationContextAware. But again, application objects normally don't need to be context-aware.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 11, 2003 11:18 pm 
Regular
Regular

Joined: Fri Sep 05, 2003 12:01 am
Posts: 80
Location: Bogot
thanks for your insight Juergen!!



Quote:
You could use Spring's ApplicationContext itself as service locator, instead of wrapping it with a custom service locator. You can simply fetch a reference to the ApplicationContext from within a Struts action via WebApplicationContextUtils.getWebApplicationContext(ServletContext), for example. With Spring's own web MVC, you don't need to do that in the first place, as you can use bean references again to link your web controllers with your service objects.


I've used struts+hibernate+spring succesfuly in my last two projects, and I would like to contribute with some sample code to help people see a way they could integrate (based on your help before!).

I dont use spring's MVC because to tell the truth I think its a bit too much to throw away all my struts knowledge right now! BUT: I'm deeply interested in seeing how one could extend struts to use properly initialized DAO's by the spring context!!..

Have you thought of any alternatives to implement this?

_________________
Mauricio Hern


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 12, 2003 1:27 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Please contribute using the Wiki.


Top
 Profile  
 
 Post subject: A parallel thought to this Service concept
PostPosted: Wed Nov 12, 2003 12:03 pm 
Newbie

Joined: Wed Nov 12, 2003 11:16 am
Posts: 9
This may be a bit more Spring related than Hibernate, but I'm going to ask the question anyway as I believe it applies to this thread.

It appears from this example, you know the types of Services that you wish to provide ahead of time. By knowing them ahead of time, you can configure them in your bean applicationContext.xml file for Spring.

However, what if you don't know the types of services ahead of time. Say you are configuring the Services from a Database profile. Is it true that you would then add your new Service Beans into the Spring framework programmatically? Doing this programmatically would also allow you to add the services for the particular TransactionProxy thing as well. That way all the Services, both predefined in the applicationContext.xml and those added programmatically, would participate in the same transaction groups.

I believe this to be a true process, but I'm just looking for some confirmation either way.


I am currently working on a product that will utilize Echo+Spring+Hibernate

Echo: http://www.nextapp.com/products/echo

Thanks so much for your indulgence
Mark


Top
 Profile  
 
 Post subject: Re: A parallel thought to this Service concept
PostPosted: Thu Nov 13, 2003 5:05 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
mnickel wrote:
However, what if you don't know the types of services ahead of time. Say you are configuring the Services from a Database profile. Is it true that you would then add your new Service Beans into the Spring framework programmatically?


There are basically two ways to approach this:

1.
Use your own ApplicationContext implementation, possibly derived from AbstractApplicationContext. You can plug in your own bean factory then, for example the out-of-the-box JdbcBeanFactory, or one that parses any custom bean definition source. In the root web application context case, specify a "contextClass" context-param in web.xml to make ContextLoaderListener load your context implementation instead of the default XmlWebApplicationContext.

2.
If you want to keep some beans in the standard XML format but add additional ones from another bean definition source on startup, implement a custom BeanFactoryPostProcessor bean and define in in your standard XML file. The application context will automatically detect this bean and invoke its postProcessBeanFactory(ConfigurableListableBeanFactory) method on startup, before touching any other beans.

Normally, this mechanism is used for overriding certain property values of XML bean definitions, for example in the out-of-the-box PropertyOverrideConfigurer and PropertyPlaceholderConfigurer beans. If you cast the given bean factory to ListableBeanFactoryImpl (which it is in the default XmlWebApplicationContext case), you can also programmatically register new bean definitions that may reference XML-defined beans and vice versa. This works seamlessly as application beans will get instantiated after the post processor has been executed.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 13, 2003 11:32 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
micho2001 wrote:
I've used struts+hibernate+spring succesfuly in my last two projects, and I would like to contribute with some sample code to help people see a way they could integrate (based on your help before!).


Note that as of 1.0 M2, Spring ships with a reworked Petclinic that provides both a Hibernate implementation and a JDBC implementation of its DAO. The out-of-the-box configuration runs on Hibernate and HSQL. This should provide a pretty good starting point -- that is, a working sample app -- for Spring/Hibernate combos. Of course, it would still be fine if you share your particular setup and experiences :-)

Regarding Struts on top: From the point of view of Struts actions, whether Hibernate is used underneath the business layer simply shouldn't matter. A Struts action simply accesses Spring-managed business facade objects, and in rare case the Spring transaction manager. It should not have to be concerned with the underlying persistence implementation at all.

micho2001 wrote:
I dont use spring's MVC because to tell the truth I think its a bit too much to throw away all my struts knowledge right now! BUT: I'm deeply interested in seeing how one could extend struts to use properly initialized DAO's by the spring context!!..


That's a fine choice - reuse of existing knowledge (and tools) is important. This is the main reason why we actively provide support for Struts/Spring and WebWork/Spring integration.

In terms of how to address Struts/Spring integration, there are basically two strategies: Either explictly access the application context from within a Struts action implementation (as I usually suggest), or configure your Struts actions in a Spring application context (what Don Brown does in his Spring-Struts integration project). The latter leads to double-definition of actions in struts-config and Spring's context definition.

I strongly favor the former approach: Struts actions aren't reusable components anyway, therefore I don't see much value in IoC-wiring actions themselves. The same issue arises with WebWork2/Spring integration: Atlassian are currently implementing support for referencing Spring-managed beans from XWork action definitions, after a proposal of mine - a level that is comparable to my Struts/Spring approach.

Essentially, these efforts would even allow for mixing various web MVC frameworks in the same web application: The business, data access, and resource layers would be kept in a single Spring root application context. Various dispatcher servlets and their actions (be it Spring's own web MVC, Struts, WebWork, Tapestry, or custom servlets) can then all access the very same Spring-managed business facades.

Juergen


Top
 Profile  
 
 Post subject: Re: A parallel thought to this Service concept
PostPosted: Thu Nov 13, 2003 11:48 am 
Newbie

Joined: Wed Nov 12, 2003 11:16 am
Posts: 9
jhoeller wrote:
1....
You can plug in your own bean factory then, for example the out-of-the-box JdbcBeanFactory, or one that parses any custom bean definition source.


Wow. I didn't know that you could have different types of bean factories. I thought that you only had 1 way of instantiating beans and that was from the XML file. I didn't get to custom bean factories in the source code yet... :)

jhoeller wrote:
2.
If you want to keep some beans in the standard XML format but add additional ones from another bean definition source on startup, implement a custom BeanFactoryPostProcessor bean and define in in your standard XML file.


Excellent!

I'm going to get that it would be possible to combine the two of these concepts... I do indeed have some beans that I know ahead of time and these would be in the applicationContext.xml file. Other beans I'm going to need to create are based on properties that are stored within a database. As with everything in the Spring Framework, it should then just be a matter of properly wiring everything up. Very cool.

You've most definitely set me on the path.

Is reading the Javadocs and source code going to be my best bet for learning more about how to utilize the JdbcBeanFactory and the postProcessBeanFactory methods? These features seem about one step beyond the intro documentation and the Petclinic demo. :)

Thanks. I'm finding both the Spring framework and Hibernate to be extremely robust. Honestly, my mind reels with the posibilities... :)

Mark


Top
 Profile  
 
 Post subject: Re: A parallel thought to this Service concept
PostPosted: Thu Nov 13, 2003 12:20 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
mnickel wrote:
Wow. I didn't know that you could have different types of bean factories. I thought that you only had 1 way of instantiating beans and that was from the XML file. I didn't get to custom bean factories in the source code yet... :)


Actually, there are quite a few out-of-the-box alternatives to XML bean definitions: ListableBeanFactoryImpl can do programmatic registration and read in properties files; JdbcBeanFactory is an extension of ListableBeanFactoryImpl that reads in bean definitions from a database table. If you want your own way of storing bean definitions in the database, you can easily write your own subclass of or wrapper for ListableBeanFactoryImpl.

mnickel wrote:
Is reading the Javadocs and source code going to be my best bet for learning more about how to utilize the JdbcBeanFactory and the postProcessBeanFactory methods? These features seem about one step beyond the intro documentation and the Petclinic demo. :)


Currently yes. The javadocs are pretty extensive, so you should be able to find your way through. For BeanFactoryPostProcessor, you can have a look at the out-of-the-box post processor implementations, namely PropertyOverrideConfigurer and PropertyPlaceholderConfigurer.

Note that both BeanFactoryPostProcessor and JdbcBeanFactory have changed slightly for the upcoming 1.0 M3 (to be released at the end of next week), as we've introduced a new BeanFactory SPI interface layer. If you'll start with M2, don't worry - migration will be straightforward.

Juergen


Top
 Profile  
 
 Post subject: Re: A parallel thought to this Service concept
PostPosted: Thu Nov 13, 2003 1:07 pm 
Newbie

Joined: Wed Nov 12, 2003 11:16 am
Posts: 9
jhoeller wrote:
Currently yes. The javadocs are pretty extensive, so you should be able to find your way through. For BeanFactoryPostProcessor, you can have a look at the out-of-the-box post processor implementations, namely PropertyOverrideConfigurer and PropertyPlaceholderConfigurer.


How do you classify your out-of-the-box implementations for the various aspects of Spring. Are they gathered together in a common area within the Javadocs?

I have no problems RTFM'ing, but it helps to have the pointers.

I'm feeling motiviated enough to tutorial-ize my experience. That would be fun.

Thanks again.
Mark


Top
 Profile  
 
 Post subject: Re: A parallel thought to this Service concept
PostPosted: Thu Nov 13, 2003 1:51 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
mnickel wrote:
How do you classify your out-of-the-box implementations for the various aspects of Spring. Are they gathered together in a common area within the Javadocs?


They are typically in subpackages of the corresponding functionality package. PropertyOverrideConfigurer and PropertyPlaceholderConfigurer are in org.springframework.context.config, for example. Out-of-the-box implementations are typically linked in the javadocs of the callback interface, so you'll find references to the configurers in the BeanFactoryPostProcessor javadocs.

Juergen


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.