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)

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM