Spring、OSGi整合Hibernate 一

查询了很多网上的帖子,主流的整合方式大体为4种。前两种不必说了,没什么扩展性,不予考虑。第三种采用Eclipse-RegisterBuddy方式(官方的整合方式)和第四种则采用Eclipse插件的扩展点,这样种都不能脱离Equinox实现,最后还是决定用自己的一套方式。

先来说说整合Hibernate的关键之处。其实用OSGi整合Hibernate很简单,但要通过Bundle方式做到可以扩展新的持久化层面的东西(比如添加新的表和操作)就比较费事了。因为Hibernate在初始化时根据注册的实体类创建SessionFactory,这样当有新的实体类添加进来时就要创建新的SessionFactory,这样系统中出现两个甚至多个SessionFatory会导致一系列的问题。显然整合Hibernate关键就是解决实体类注册与SessionFactory创建的问题。

我的具体思路如下。

首先将Hibernate单独多为一个Bundle(wanged_commons_hibernate)以便提供其他Bundle所需类包。

然后建立一个用于提供实体注册接口的Bundle(wanged_core_persistent_entity_register),代码如下:

package wanged.core.persistent.entity;  
      
    @SuppressWarnings("unchecked")  
    public interface EntityRegister {  
      
        /** 
         * 注册Hibernate的实体Class 
         * @return 
         */  
        Class[] register();  
         
    }  
       建一个用来初始化SessionFactory和事务管理的Bundle(wanged_core_persistent),由于使用Spring提供的LocalSessionFactoryBean会有问题,所以我单独写了两个类。类LocalSessionFactoryBean的代码:
package wanged.core.persistent;  
      
    import java.util.HashMap;  
    import java.util.Properties;  
      
    import javax.sql.DataSource;  
      
    import org.hibernate.ConnectionReleaseMode;  
    import org.hibernate.HibernateException;  
    import org.hibernate.SessionFactory;  
    import org.hibernate.cfg.Configuration;  
    import org.hibernate.cfg.Environment;  
    import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;  
    import org.springframework.orm.hibernate3.AbstractSessionFactoryBean;  
    import org.springframework.orm.hibernate3.SpringSessionContext;  
    import org.springframework.orm.hibernate3.TransactionAwareDataSourceConnectionProvider;  
      
    import wanged.core.persistent.entity.EntityRegister;  
      
    @SuppressWarnings("unchecked")  
    public class LocalSessionFactoryBean extends AbstractSessionFactoryBean {  
      
        private static final ThreadLocal configTimeDataSourceHolder = new ThreadLocal();  
      
        private Properties hibernateProperties;  
      
        private HashMapnew HashMap
      
        private Configuration configuration;  
      
        public static DataSource getConfigTimeDataSource() {  
            return (DataSource) configTimeDataSourceHolder.get();  
        }  
      
        /** 
         * 注册Entity的Class数组 
         *  
         * @param er 
         */  
        @SuppressWarnings("unchecked")  
        public void setEntityRegister(EntityRegister[] erArr) {  
            for (EntityRegister er : erArr) {  
                this.addEntityRegister(er);  
            }  
      
        }  
          
        @SuppressWarnings("unchecked")  
        public void setEntityRegister(EntityRegister er) {  
            this.addEntityRegister(er);  
        }  
      
        private void addEntityRegister(EntityRegister er){  
            // TODO:对registerClass()中取得的数组进行验证  
            this.entityClasses.put(er, er.register());  
        }  
          
        /** 
         * 卸载Entity的Class数组 
         *  
         * @param er 
         */  
        public void unsetEntityRegister(EntityRegister er) {  
            this.entityClasses.remove(er);  
      
            // TODO:重新初始化SessionFactory  
      
        }  
      
        public void setHibernateProperties(Properties hibernateProperties) {  
            this.hibernateProperties = hibernateProperties;  
        }  
      
        public Properties getHibernateProperties() {  
            if (this.hibernateProperties == null) {  
                this.hibernateProperties = new Properties();  
            }  
            return this.hibernateProperties;  
        }  
      
        @SuppressWarnings("unchecked")  
        protected SessionFactory buildSessionFactory() {  
            Configuration config = new Configuration();  
            DataSource dataSource = getDataSource();  
            if (dataSource != null) {  
                configTimeDataSourceHolder.set(dataSource);  
            }  
      
            try {  
                config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());  
      
                if (isExposeTransactionAwareSessionFactory()) {  
                    config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());  
                }  
      
                if (this.hibernateProperties != null) {  
                    config.addProperties(this.hibernateProperties);  
                }  
      
                if (dataSource != null) {  
                    boolean actuallyTransactionAware = (isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy);  
                    config.setProperty(Environment.CONNECTION_PROVIDER, actuallyTransactionAware ? TransactionAwareDataSourceConnectionProvider.class  
                                    .getName() : LocalDataSourceConnectionProvider.class.getName());  
                }  
      
                // 添加Entity的类  
                for (Class[] cArr : this.entityClasses.values()) {  
                    for (Class c : cArr) {  
                        config.addClass(c);  
                    }  
                }  
                this.configuration = config;  
                return config.buildSessionFactory();  
            } finally {  
                if (dataSource != null) {  
                    configTimeDataSourceHolder.set(null);  
                }  
            }  
        }  
      
        /** 
         * Return the Configuration object used to build the SessionFactory. Allows 
         * access to configuration metadata stored there (rarely needed). 
         *  
         * @throws IllegalStateException 
         *             if the Configuration object has not been initialized yet 
         */  
        public final Configuration getConfiguration() {  
            if (this.configuration == null) {  
                throw new IllegalStateException("Configuration not initialized yet");  
            }  
            return this.configuration;  
        }  
      
        public void destroy() throws HibernateException {  
            DataSource dataSource = getDataSource();  
            if (dataSource != null) {  
                configTimeDataSourceHolder.set(dataSource);  
            }  
            try {  
                super.destroy();  
            } finally {  
                if (dataSource != null) {  
                    configTimeDataSourceHolder.set(null);  
                }  
            }  
        }  
    }  
类LocalDataSourceConnectionProvider的代码:
package wanged.core.persistent;  
      
    import java.sql.Connection;  
    import java.sql.SQLException;  
    import java.util.Properties;  
      
    import javax.sql.DataSource;  
      
    import org.hibernate.HibernateException;  
    import org.hibernate.connection.ConnectionProvider;  
    import org.hibernate.util.JDBCExceptionReporter;  
      
    public class LocalDataSourceConnectionProvider implements ConnectionProvider {  
      
        private DataSource dataSource;  
      
        private DataSource dataSourceToUse;  
      
      
        public void configure(Properties props) throws HibernateException {  
            this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource();  
            if (this.dataSource == null) {  
                throw new HibernateException("No local DataSource found for configuration - " +  
                    "dataSource property must be set on LocalSessionFactoryBean");  
            }  
            this.dataSourceToUse = getDataSourceToUse(this.dataSource);  
        }  
      
        protected DataSource getDataSourceToUse(DataSource originalDataSource) {  
            return originalDataSource;  
        }  
      
        public DataSource getDataSource() {  
            return dataSource;  
        }  
      
        public Connection getConnection() throws SQLException {  
            try {  
                return this.dataSourceToUse.getConnection();  
            }  
            catch (SQLException ex) {  
                JDBCExceptionReporter.logExceptions(ex);  
                throw ex;  
            }  
        }  
      
        public void closeConnection(Connection con) throws SQLException {  
            try {  
                con.close();  
            }  
            catch (SQLException ex) {  
                JDBCExceptionReporter.logExceptions(ex);  
                throw ex;  
            }  
        }  
      
        public void close() {  
        }  
      
        public boolean supportsAggressiveRelease() {  
            return false;  
        }  
      
    }  
如果你对比其与Spring提供的同名类中的代码,相差不大。

下面来看看配置文件,我把Bean的初始化放在bean.xml中:

 
  1. <!-- 本地调试使用连接池-->  
  2.   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  3.     <property name="driverClassName" value="org.gjt.mm.mysql.Driver" />  
  4.     <property name="url" value="jdbc:mysql://localhost:3306/cms" />  
  5.     <property name="username" value="root" />  
  6.     <property name="password" value="root" />  
  7.     <property name="connectionProperties">  
  8.       <props>  
  9.         <prop key="useUnicode">true</prop>  
  10.         <prop key="characterEncoding">GBK</prop>  
  11.       </props>  
  12.     </property>  
  13.   </bean>  
  14.    
  15.   <!-- 服务实现类定义 -->  
  16.   <bean id="sessionFactory" class="wanged.core.persistent.LocalSessionFactoryBean">  
  17.     <property name="hibernateProperties">  
  18.       <props>  
  19.         <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
  20.         <prop key="hibernate.show_sql">false</prop>  
  21.         <prop key="hibernate.cache.use_query_cache">true</prop>  
  22.         <prop key="hibernate.jdbc.batch_size">20</prop>  
  23.       </props>  
  24.     </property>  
  25.     <property name="dataSource" ref="dataSource" />  
  26.     <property name="entityRegister" ref="entityRegister" />  
  27.   </bean>  
  28.   
  29.   <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  30.     <property name="sessionFactory" ref="sessionFactory" />  
  31.   </bean>  

而服务与引用的声明放在osgi-service.xml中:

 
  1. <osgi:reference id="entityRegister"  interface="wanged.core.persistent.entity.EntityRegister" cardinality="1..n"/>    
  2.   
  3. <osgi:service interface="org.hibernate.SessionFactory" ref="sessionFactory" />    
  4.   
  5. <osgi:service interface="org.springframework.transaction.PlatformTransactionManager" ref="txManager" />    
这里的引用 "实体注册" 服务需要在我们的实体Bundle中实现,现在已经搭好了架子,下一步就需要创建自己的实体Bundle和数据库操作的Bundle。由于这个Blog保存时经常保存不住,需要重写,所以我尽可能的将其划分开来写。

相关推荐