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的获取和关闭,事务处理的绑定做好了封装 - 从这个角度看也大大方便了用户的使用。 
  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/chenying99/p/2709154.html
Copyright © 2011-2022 走看看