Spring对HibernateSession的管理之封装SessionFactory

  我刚刚在上一篇博文中将Spring对HibernateSession的管理做了一些皮毛的分析,主要围绕着Spring是怎样平衡Session的关闭时间。即在是否需要延时Session有效期以保证页面的调用。

  

  那么现在我们来看看Spring是怎样管理Session的生产者:SessionFactory的。

  首先,我们在学习Spring的时候一般都会涉及到将SSH框架整合起来使用了,还记得我们怎样配置Spring吗?

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans
 3     xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:p="http://www.springframework.org/schema/p"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 7 
 8     ……
 9     <bean id="dataSource"
10         class="org.apache.commons.dbcp.BasicDataSource">
11         <property name="driverClassName"
12             value="oracle.jdbc.driver.OracleDriver">
13         </property>
14         <property name="url"
15             value="jdbc:oracle:thin:@localhost:1521:orcl">
16         </property>
17         <property name="username" value="……"></property>
18         <property name="password" value="……"></property>
19     </bean>
20     <bean id="sessionFactory"
21         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
22         <property name="dataSource">
23             <ref bean="dataSource"></ref>
24         </property>
25         <property name="hibernateProperties">
26             <props>
27                 <prop key="hibernate.dialect">
28                     org.hibernate.dialect.Oracle10gDialect
29                 </prop>
30                 <prop key="hibernate.hbm2ddl.auto">update</prop>
31             </props>
32         </property>
33         <property name="mappingResources">
34             <list><value>orm/Users.hbm.xml</value></list>
35         </property>
36     </bean>
37     
38     <bean id="userDao" class="……">
39         <property name="sessionFactory" ref="sessionFactory"/>
40     </bean>
41     <bean id="userServer" class="……">
42         <property name="userdao" ref="userDao"/>
43     </bean>
44     <bean id="userAction" class="……">
45         <property name="userserver" ref="userServer"/>
46     </bean>
47     ……
48 </beans>

  在不涉及到声明性事务和自动装配时我们一般按上述配置(上述配置为MyEclipse环境下的自动生成)。

  不知道大家有没有注意到:我们的Dao需要的SessionFactory是org.hibernate.SessionFactory(我们的Dao为了代码重用,继承自HibernateDaoSupport),而上面的装配却没有给一个SessionFactory或其子类。

  

  org.springframework.orm.hibernate3.support.HibernateDaoSupport源代码(省略了注释):

 1 package org.springframework.orm.hibernate3.support;
 2 
 3 import org.hibernate.HibernateException;
 4 import org.hibernate.Session;
 5 import org.hibernate.SessionFactory;
 6 
 7 import org.springframework.dao.DataAccessException;
 8 import org.springframework.dao.DataAccessResourceFailureException;
 9 import org.springframework.dao.support.DaoSupport;
10 import org.springframework.orm.hibernate3.HibernateTemplate;
11 import org.springframework.orm.hibernate3.SessionFactoryUtils;
12 public abstract class HibernateDaoSupport extends DaoSupport {
13 
14     private HibernateTemplate hibernateTemplate;
15 
16     public final void setSessionFactory(SessionFactory sessionFactory) {
17         if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
18             this.hibernateTemplate = createHibernateTemplate(sessionFactory);
19         }
20     }
21 
22     protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
23         return new HibernateTemplate(sessionFactory);
24     }
25 
26     public final SessionFactory getSessionFactory() {
27         return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
28     }
29 
30     public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
31         this.hibernateTemplate = hibernateTemplate;
32     }
33 
34     public final HibernateTemplate getHibernateTemplate() {
35       return this.hibernateTemplate;
36     }
37 
38     @Override
39     protected final void checkDaoConfig() {
40         if (this.hibernateTemplate == null) {
41             throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
42         }
43     }
44 
45 
46     protected final Session getSession()
47         throws DataAccessResourceFailureException, IllegalStateException {
48 
49         return getSession(this.hibernateTemplate.isAllowCreate());
50     }
51 
52 
53     protected final Session getSession(boolean allowCreate)
54         throws DataAccessResourceFailureException, IllegalStateException {
55 
56         return (!allowCreate ?
57             SessionFactoryUtils.getSession(getSessionFactory(), false) :
58                 SessionFactoryUtils.getSession(
59                         getSessionFactory(),
60                         this.hibernateTemplate.getEntityInterceptor(),
61                         this.hibernateTemplate.getJdbcExceptionTranslator()));
62     }
63 
64     protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
65         return this.hibernateTemplate.convertHibernateAccessException(ex);
66     }
67 
68     protected final void releaseSession(Session session) {
69         SessionFactoryUtils.releaseSession(session, getSessionFactory());
70     }
71 
72 }

  从源代码可以看到,属性所需类型确实为org.hibernate.SessionFactory(上述代码16行处可看出)。

  我是偶然发现这一点的,在后来,我顺着LocalSessionFactoryBean的父类或接口向上追溯:

    LocalSessionFactoryBean extends AbstractSessionFactoryBean implements BeanClassLoaderAware

    AbstractSessionFactoryBean extends HibernateExceptionTranslator
  implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean

  在经过分析后,我把重点放在了FactoryBean<SessionFactory>这个接口上,它实际上是一个泛型接口,原型如下:

  org.springframework.beans.factory.FactoryBean源代码(省略了注释):

 1 package org.springframework.beans.factory;
 2 
 3 public interface FactoryBean<T> {
 4 
 5     T getObject() throws Exception;
 6 
 7     Class<?> getObjectType();
 8 
 9     boolean isSingleton();
10 
11 }

  看到这里,我一度认为自己掌握了这种方式,于是我开始着手进行实验(以下是我进行实验的项目,只是一个添加了Spring支持的Java Project。注意添加Spring的aop支持):

 1 import org.springframework.context.ApplicationContext;
 2 import org.springframework.context.support.ClassPathXmlApplicationContext;
 3 
 4 public class Test {
 5     // main方法,从Spring容器中拿到对象
 6     public static void main(String[] args) {
 7         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
 8         System.out.println(ac.getBean("tt"));
 9     }
10 }
11 // 用作实体类,可以看做org.hibernate.SessionFactory
12 class E {
13 
14 }
15 // 用做泛型接口,可以看作org.springframework.beans.factory.FactoryBean
16 interface MyFactoryBean<T> {
17 
18 }
19 // 用做真正构造得到的类,可以看作org.springframework.orm.hibernate3.LocalSessionFactoryBean
20 class T implements MyFactoryBean<E> {
21     
22 }
23 // 用作使用实体作为属性的类,可以看作org.springframework.orm.hibernate3.support.HibernateDaoSupport
24 class M{
25     private E e;
26     public void setE(E e){
27         this.e = e;
28     }
29 }
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans
 3     xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:p="http://www.springframework.org/schema/p"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 7 
 8     <!-- 我写得不是很语义化,大家重在理解 -->
 9     
10     <!-- 简单理解,此处的dd是实现了泛型接口的类 class T implements MyFactoryBean<E> 而实际上,它和E无关 -->
11     <!-- 此处的M需要一个E来作为属性,它的set方法需要一个E类型的参数,但我们给它一个T -->
12     <bean id="dd" class="T"></bean>
13     <bean id="tt" class="M">
14         <property name="e" ref="dd" />
15     </bean>
16 </beans>

  这样就可以吗?事实证明:NO!

  ps:也对,这样都行的话,国足能进世界杯(进过吗?不清楚)。

  

  得到一个异常(大家翻译一下就明了):java.lang.IllegalStateException: Cannot convert value of type [T] to required type [E] for property 'e': no matching editors or conversion strategy found。

  看到这个异常,我忽然想到:难道是因为没有类似org.springframework.beans.factory.FactoryBean中的getObject方法?

  于是,我连夜进行测试,在接口和实现中添加方法,改进后如下

 1 interface MyFactoryBean<T> {
 2     T getObject() throws Exception;
 3 
 4     Class<?> getObjectType();
 5 
 6     boolean isSingleton();
 7 }
 8 class T implements MyFactoryBean<E> {
 9 
10     @Override
11     public E getObject() throws Exception {
12         return new E();
13     }
14 
15     @Override
16     public Class<?> getObjectType() {
17         return E.class;
18     }
19 
20     @Override
21     public boolean isSingleton() {
22         return false;
23     }
24     
25 }

  结果证明:纯属坑爹,这不是换汤不换药吗?

  最后,我使用了Spring自带的FactoryBean:

 1 import org.springframework.beans.factory.FactoryBean;
 2 //……
 3 class T implements FactoryBean<E> {
 4 
 5     @Override
 6     public E getObject() throws Exception {
 7         return new E();
 8     }
 9 
10     @Override
11     public Class<?> getObjectType() {
12         return E.class;
13     }
14 
15     @Override
16     public boolean isSingleton() {
17         return false;
18     }
19     
20 }
21 //……

  这才成功了!

  由此可见,Spring用了某种转换来搞定这个事情,其中设计到多种设计模式,下次再深入研究。

 

 

 欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

 或者通过QQ与我联系:点击这里给我发消息

 (最后编辑时间2012-10-11 17:32:29)

  

posted @ 2012-10-11 17:29  云中双月  阅读(9238)  评论(0编辑  收藏  举报