zoukankan      html  css  js  c++  java
  • Spring源代码解析(八):Spring驱动Hibernate的实现

    O/R工具出现之后,简化了许多复杂的信息持久化的开发。Spring应用开发者可以通过Spring提供的O/R方案更方便的使用各种持久化工具,比如Hibernate;下面我们就Spring+Hibernate中的Spring实现做一个简单的剖析。 
    Spring对Hinberanate的配置是通过LocalSessionFactoryBean来完成的,这是一个工厂Bean的实现,在基类AbstractSessionFactoryBean中: 
    Java代码  收藏代码
    1. /** 
    2.  * 这是FactoryBean需要实现的接口方法,直接取得当前的sessionFactory的值 
    3.  */  
    4. public Object getObject() {  
    5.     return this.sessionFactory;  
    6. }  

    这个值在afterPropertySet中定义: 
    Java代码  收藏代码
    1. public void afterPropertiesSet() throws Exception {  
    2.     //这个buildSessionFactory是通过配置信息得到SessionFactory的地方  
    3.     SessionFactory rawSf = buildSessionFactory();  
    4.     //这里使用了Proxy方法插入对getCurrentSession的拦截,得到和事务相关的session  
    5.     this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);  
    6. }  

    我们先看看SessionFactory是怎样创建的,这个方法很长,包含了创建Hibernate的SessionFactory的详尽步骤: 
    Java代码  收藏代码
    1. protected SessionFactory buildSessionFactory() throws Exception {  
    2.     SessionFactory sf = null;  
    3.   
    4.     // Create Configuration instance.  
    5.     Configuration config = newConfiguration();  
    6.   
    7.     //这里配置数据源,事务管理器,LobHander到Holder中,这个Holder是一个ThreadLocal变量,这样这些资源就和线程绑定了  
    8.     if (this.dataSource != null) {  
    9.         // Make given DataSource available for SessionFactory configuration.  
    10.         configTimeDataSourceHolder.set(this.dataSource);  
    11.     }  
    12.   
    13.     if (this.jtaTransactionManager != null) {  
    14.         // Make Spring-provided JTA TransactionManager available.  
    15.         configTimeTransactionManagerHolder.set(this.jtaTransactionManager);  
    16.     }  
    17.   
    18.     if (this.lobHandler != null) {  
    19.         // Make given LobHandler available for SessionFactory configuration.  
    20.         // Do early because because mapping resource might refer to custom types.  
    21.         configTimeLobHandlerHolder.set(this.lobHandler);  
    22.     }  
    23.   
    24.     //这里是使用Hibernate的各个属性的配置,这里使用了Configuration类来抽象这些数据  
    25.     try {  
    26.         // Set connection release mode "on_close" as default.  
    27.         // This was the case for Hibernate 3.0; Hibernate 3.1 changed  
    28.         // it to "auto" (i.e. "after_statement" or "after_transaction").  
    29.         // However, for Spring's resource management (in particular for  
    30.         // HibernateTransactionManager), "on_close" is the better default.  
    31.         config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());  
    32.   
    33.         if (!isExposeTransactionAwareSessionFactory()) {  
    34.             // Not exposing a SessionFactory proxy with transaction-aware  
    35.             // getCurrentSession() method -> set Hibernate 3.1 CurrentSessionContext  
    36.             // implementation instead, providing the Spring-managed Session that way.  
    37.             // Can be overridden by a custom value for corresponding Hibernate property.  
    38.             config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS,  
    39.                     "org.springframework.orm.hibernate3.SpringSessionContext");  
    40.         }  
    41.   
    42.         if (this.entityInterceptor != null) {  
    43.             // Set given entity interceptor at SessionFactory level.  
    44.             config.setInterceptor(this.entityInterceptor);  
    45.         }  
    46.   
    47.         if (this.namingStrategy != null) {  
    48.             // Pass given naming strategy to Hibernate Configuration.  
    49.             config.setNamingStrategy(this.namingStrategy);  
    50.         }  
    51.   
    52.         if (this.typeDefinitions != null) {  
    53.             // Register specified Hibernate type definitions.  
    54.             Mappings mappings = config.createMappings();  
    55.             for (int i = 0; i < this.typeDefinitions.length; i++) {  
    56.                 TypeDefinitionBean typeDef = this.typeDefinitions[i];  
    57.                 mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());  
    58.             }  
    59.         }  
    60.   
    61.         if (this.filterDefinitions != null) {  
    62.             // Register specified Hibernate FilterDefinitions.  
    63.             for (int i = 0; i < this.filterDefinitions.length; i++) {  
    64.                 config.addFilterDefinition(this.filterDefinitions[i]);  
    65.             }  
    66.         }  
    67.   
    68.         if (this.configLocations != null) {  
    69.             for (int i = 0; i < this.configLocations.length; i++) {  
    70.                 // Load Hibernate configuration from given location.  
    71.                 config.configure(this.configLocations[i].getURL());  
    72.             }  
    73.         }  
    74.   
    75.         if (this.hibernateProperties != null) {  
    76.             // Add given Hibernate properties to Configuration.  
    77.             config.addProperties(this.hibernateProperties);  
    78.         }  
    79.   
    80.         if (this.dataSource != null) {  
    81.             boolean actuallyTransactionAware =  
    82.                     (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);  
    83.             // Set Spring-provided DataSource as Hibernate ConnectionProvider.  
    84.             config.setProperty(Environment.CONNECTION_PROVIDER,  
    85.                     actuallyTransactionAware ?  
    86.                     TransactionAwareDataSourceConnectionProvider.class.getName() :  
    87.                     LocalDataSourceConnectionProvider.class.getName());  
    88.         }  
    89.   
    90.         if (this.jtaTransactionManager != null) {  
    91.             // Set Spring-provided JTA TransactionManager as Hibernate property.  
    92.             config.setProperty(  
    93.                     Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());  
    94.         }  
    95.   
    96.         if (this.mappingLocations != null) {  
    97.             // Register given Hibernate mapping definitions, contained in resource files.  
    98.             for (int i = 0; i < this.mappingLocations.length; i++) {  
    99.                 config.addInputStream(this.mappingLocations[i].getInputStream());  
    100.             }  
    101.         }  
    102.   
    103.         if (this.cacheableMappingLocations != null) {  
    104.             // Register given cacheable Hibernate mapping definitions, read from the file system.  
    105.             for (int i = 0; i < this.cacheableMappingLocations.length; i++) {  
    106.                 config.addCacheableFile(this.cacheableMappingLocations[i].getFile());  
    107.             }  
    108.         }  
    109.   
    110.         if (this.mappingJarLocations != null) {  
    111.             // Register given Hibernate mapping definitions, contained in jar files.  
    112.             for (int i = 0; i < this.mappingJarLocations.length; i++) {  
    113.                 Resource resource = this.mappingJarLocations[i];  
    114.                 config.addJar(resource.getFile());  
    115.             }  
    116.         }  
    117.   
    118.         if (this.mappingDirectoryLocations != null) {  
    119.             // Register all Hibernate mapping definitions in the given directories.  
    120.             for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {  
    121.                 File file = this.mappingDirectoryLocations[i].getFile();  
    122.                 if (!file.isDirectory()) {  
    123.                     throw new IllegalArgumentException(  
    124.                             "Mapping directory location [" + this.mappingDirectoryLocations[i] +  
    125.                             "] does not denote a directory");  
    126.                 }  
    127.                 config.addDirectory(file);  
    128.             }  
    129.         }  
    130.   
    131.         if (this.entityCacheStrategies != null) {  
    132.             // Register cache strategies for mapped entities.  
    133.             for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {  
    134.                 String className = (String) classNames.nextElement();  
    135.                 String[] strategyAndRegion =  
    136.                         StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className));  
    137.                 if (strategyAndRegion.length > 1) {  
    138.                     config.setCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]);  
    139.                 }  
    140.                 else if (strategyAndRegion.length > 0) {  
    141.                     config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);  
    142.                 }  
    143.             }  
    144.         }  
    145.   
    146.         if (this.collectionCacheStrategies != null) {  
    147.             // Register cache strategies for mapped collections.  
    148.             for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {  
    149.                 String collRole = (String) collRoles.nextElement();  
    150.                 String[] strategyAndRegion =  
    151.                         StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole));  
    152.                 if (strategyAndRegion.length > 1) {  
    153.                     config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]);  
    154.                 }  
    155.                 else if (strategyAndRegion.length > 0) {  
    156.                     config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);  
    157.                 }  
    158.             }  
    159.         }  
    160.   
    161.         if (this.eventListeners != null) {  
    162.             // Register specified Hibernate event listeners.  
    163.             for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {  
    164.                 Map.Entry entry = (Map.Entry) it.next();  
    165.                 Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");  
    166.                 String listenerType = (String) entry.getKey();  
    167.                 Object listenerObject = entry.getValue();  
    168.                 if (listenerObject instanceof Collection) {  
    169.                     Collection listeners = (Collection) listenerObject;  
    170.                     EventListeners listenerRegistry = config.getEventListeners();  
    171.                     Object[] listenerArray =  
    172.                             (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());  
    173.                     listenerArray = listeners.toArray(listenerArray);  
    174.                     config.setListeners(listenerType, listenerArray);  
    175.                 }  
    176.                 else {  
    177.                     config.setListener(listenerType, listenerObject);  
    178.                 }  
    179.             }  
    180.         }  
    181.   
    182.         // Perform custom post-processing in subclasses.  
    183.         postProcessConfiguration(config);  
    184.   
    185.         // 这里是根据Configuration配置创建SessionFactory的地方  
    186.         logger.info("Building new Hibernate SessionFactory");  
    187.         this.configuration = config;  
    188.         sf = newSessionFactory(config);  
    189.     }  
    190.     //最后把和线程绑定的资源清空  
    191.     finally {  
    192.         if (this.dataSource != null) {  
    193.             // Reset DataSource holder.  
    194.             configTimeDataSourceHolder.set(null);  
    195.         }  
    196.   
    197.         if (this.jtaTransactionManager != null) {  
    198.             // Reset TransactionManager holder.  
    199.             configTimeTransactionManagerHolder.set(null);  
    200.         }  
    201.   
    202.         if (this.lobHandler != null) {  
    203.             // Reset LobHandler holder.  
    204.             configTimeLobHandlerHolder.set(null);  
    205.         }  
    206.     }  
    207.   
    208.     // Execute schema update if requested.  
    209.     if (this.schemaUpdate) {  
    210.         updateDatabaseSchema();  
    211.     }  
    212.   
    213.     return sf;  
    214. }  

    而直接调用org.hibernate.cfg.Configuration来得到需要的SessionFactory: 
    Java代码  收藏代码
    1. protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {  
    2.     return config.buildSessionFactory();  
    3. }  

    所以我们这里看到LocalSessionFactory大致起到的一个读取资源配置然后生成SessionFactory的作用;当然这里在得到 SessionFactory之后,还需要对session的事务管理作一些处理 - 使用了一个Proxy模式对getCurrentSession方法进行了拦截; 
    Java代码  收藏代码
    1. //这里先根据当前的SessionFactory的类型得到Proxy,然后插入Spring定义好的getCurrentSession拦截器  
    2.     protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {  
    3.         Class sfInterface = SessionFactory.class;  
    4.         if (target instanceof SessionFactoryImplementor) {  
    5.             sfInterface = SessionFactoryImplementor.class;  
    6.         }  
    7.         return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),  
    8.                 new Class[] {sfInterface}, new TransactionAwareInvocationHandler(target));  
    9.     }  

    拦截器的实现如下: 
    Java代码  收藏代码
    1. private static class TransactionAwareInvocationHandler implements InvocationHandler {  
    2.   
    3.     private final SessionFactory target;  
    4.   
    5.     public TransactionAwareInvocationHandler(SessionFactory target) {  
    6.         this.target = target;  
    7.     }  
    8.   
    9.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
    10.         // Invocation on SessionFactory/SessionFactoryImplementor interface coming in...  
    11.         // 这里对getCurrentSession方法进行拦截,得到一个和当前事务绑定的session交给用户  
    12.         if (method.getName().equals("getCurrentSession")) {  
    13.             // Handle getCurrentSession method: return transactional Session, if any.  
    14.             try {  
    15.                 return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);  
    16.             }  
    17.             catch (IllegalStateException ex) {  
    18.                 throw new HibernateException(ex.getMessage());  
    19.             }  
    20.         }  
    21.         else if (method.getName().equals("equals")) {  
    22.             // Only consider equal when proxies are identical.  
    23.             return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);  
    24.         }  
    25.         else if (method.getName().equals("hashCode")) {  
    26.             // Use hashCode of SessionFactory proxy.  
    27.             return new Integer(hashCode());  
    28.         }  
    29.   
    30.         // 这里是需要运行的SessionFactory的目标方法  
    31.         try {  
    32.             return method.invoke(this.target, args);  
    33.         }  
    34.         catch (InvocationTargetException ex) {  
    35.             throw ex.getTargetException();  
    36.         }  
    37.     }  
    38. }  

    我们看看getCurrentSession的实现,在SessionFactoryUtils中: 
    Java代码  收藏代码
    1. private static Session doGetSession(  
    2.             SessionFactory sessionFactory, Interceptor entityInterceptor,  
    3.             SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)  
    4.             throws HibernateException, IllegalStateException {  
    5.   
    6.         Assert.notNull(sessionFactory, "No SessionFactory specified");  
    7.   
    8.         //这个TransactionSynchronizationManager的Resource是一个ThreadLocal变量,sessionFactory是一个单例,但ThreadLocal是和线程绑定的  
    9.         //这样就实现了Hiberante中常用的通过ThreadLocal的session管理机制  
    10.         SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);  
    11.         if (sessionHolder != null && !sessionHolder.isEmpty()) {  
    12.             // pre-bound Hibernate Session  
    13.             Session session = null;  
    14.             if (TransactionSynchronizationManager.isSynchronizationActive() &&  
    15.                     sessionHolder.doesNotHoldNonDefaultSession()) {  
    16.                 // Spring transaction management is active ->  
    17.                 // register pre-bound Session with it for transactional flushing.  
    18.                 session = sessionHolder.getValidatedSession();  
    19.                 if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {  
    20.                     logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");  
    21.                     TransactionSynchronizationManager.registerSynchronization(  
    22.                             new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));  
    23.                     sessionHolder.setSynchronizedWithTransaction(true);  
    24.                     // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session  
    25.                     // with FlushMode.NEVER, which needs to allow flushing within the transaction.  
    26.                     FlushMode flushMode = session.getFlushMode();  
    27.                     if (flushMode.lessThan(FlushMode.COMMIT) &&  
    28.                             !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {  
    29.                         session.setFlushMode(FlushMode.AUTO);  
    30.                         sessionHolder.setPreviousFlushMode(flushMode);  
    31.                     }  
    32.                 }  
    33.             }  
    34.             else {  
    35.                 // No Spring transaction management active -> try JTA transaction synchronization.  
    36.                 session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);  
    37.             }  
    38.             if (session != null) {  
    39.                 return session;  
    40.             }  
    41.         }  
    42.         //这里直接打开一个Session  
    43.         logger.debug("Opening Hibernate Session");  
    44.         Session session = (entityInterceptor != null ?  
    45.                 sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());  
    46.   
    47.         // Use same Session for further Hibernate actions within the transaction.  
    48.         // Thread object will get removed by synchronization at transaction completion.  
    49.         // 把新打开的Session放到SessionHolder,然后放到ThreadLocal里面去和线程绑定起来,这个ThreadLocal是在 TransactionSynchronizationManager中配置好的,可以根据sessionFactory来索取  
    50.         // 同时根据事务处理的状态来配置session的属性,比如把FlushMode设置为Never,同时把session和事务处理关联起来  
    51.         if (TransactionSynchronizationManager.isSynchronizationActive()) {  
    52.             // We're within a Spring-managed transaction, possibly from JtaTransactionManager.  
    53.             logger.debug("Registering Spring transaction synchronization for new Hibernate Session");  
    54.             SessionHolder holderToUse = sessionHolder;  
    55.             if (holderToUse == null) {  
    56.                 holderToUse = new SessionHolder(session);  
    57.             }  
    58.             else {  
    59.                 holderToUse.addSession(session);  
    60.             }  
    61.             if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {  
    62.                 session.setFlushMode(FlushMode.NEVER);  
    63.             }  
    64.             TransactionSynchronizationManager.registerSynchronization(  
    65.                     new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));  
    66.             holderToUse.setSynchronizedWithTransaction(true);  
    67.             if (holderToUse != sessionHolder) {  
    68.                 TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);  
    69.             }  
    70.         }  
    71.         else {  
    72.             // No Spring transaction management active -> try JTA transaction synchronization.  
    73.             registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);  
    74.         }  
    75.   
    76.         // Check whether we are allowed to return the Session.  
    77.         if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {  
    78.             closeSession(session);  
    79.             throw new IllegalStateException("No Hibernate Session bound to thread, " +  
    80.                 "and configuration does not allow creation of non-transactional one here");  
    81.         }  
    82.   
    83.         return session;  
    84.     }  

    这里就是在Spring中为使用Hiberante的SessionFactory以及Session做的准备工作,在这个基础上,用户可以通过使用 HibernateTemplate来使用Hibernate的O/R功能,和以前看到的一样这是一个execute的回调: 
    Java代码  收藏代码
    1. public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {  
    2.     Assert.notNull(action, "Callback object must not be null");  
    3.     //这里得到配置好的Hibernate的Session  
    4.     Session session = getSession();  
    5.     boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());  
    6.     if (existingTransaction) {  
    7.         logger.debug("Found thread-bound Session for HibernateTemplate");  
    8.     }  
    9.   
    10.     FlushMode previousFlushMode = null;  
    11.     try {  
    12.         previousFlushMode = applyFlushMode(session, existingTransaction);  
    13.         enableFilters(session);  
    14.         Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));  
    15.         //这里是回调的入口  
    16.         Object result = action.doInHibernate(sessionToExpose);  
    17.         flushIfNecessary(session, existingTransaction);  
    18.         return result;  
    19.     }  
    20.     catch (HibernateException ex) {  
    21.         throw convertHibernateAccessException(ex);  
    22.     }  
    23.     catch (SQLException ex) {  
    24.         throw convertJdbcAccessException(ex);  
    25.     }  
    26.     catch (RuntimeException ex) {  
    27.         // Callback code threw application exception...  
    28.         throw ex;  
    29.     }  
    30.     finally {  
    31.         //如果这个调用的方法在一个事务当中,  
    32.         if (existingTransaction) {  
    33.             logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");  
    34.             disableFilters(session);  
    35.             if (previousFlushMode != null) {  
    36.                 session.setFlushMode(previousFlushMode);  
    37.             }  
    38.         } //否则把Session关闭  
    39.         else {  
    40.             // Never use deferred close for an explicitly new Session.  
    41.             if (isAlwaysUseNewSession()) {  
    42.                 SessionFactoryUtils.closeSession(session);  
    43.             }  
    44.             else {  
    45.                 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());  
    46.             }  
    47.         }  
    48.     }  
    49. }  

    我们看看怎样得到对应的Session的,仍然使用了SessionFactoryUtils的方法doGetSession: 
    Java代码  收藏代码
    1. protected Session getSession() {  
    2.     if (isAlwaysUseNewSession()) {  
    3.         return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());  
    4.     }  
    5.     else if (!isAllowCreate()) {  
    6.         return SessionFactoryUtils.getSession(getSessionFactory(), false);  
    7.     }  
    8.     else {  
    9.         return SessionFactoryUtils.getSession(  
    10.                 getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());  
    11.     }  
    12. }  

    这样我们就可以和其他的Template那样使用Hibernate的基本功能了,使用的时候Spring已经为我们对Session的获取和关闭,事务处理的绑定做好了封装 - 从这个角度看也大大方便了用户的使用。 
  • 相关阅读:
    梦幻如初,心不忘。
    整数集和求并
    ACTF 2014 Write up
    适用web的图片
    jqGrid
    angularjs
    【转载】FPGA异步时钟设计中的同步策略
    Cordic的学习之硬件实现
    Cordic的学习初步
    DDS---三角函数发生器的用法
  • 原文地址:https://www.cnblogs.com/chenying99/p/2709154.html
Copyright © 2011-2022 走看看