Spring源代码解析(八):Spring驱动Hibernate的实现

SPRING 专栏收录该内容
26 篇文章 0 订阅

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. }  
    /**
     * 这是FactoryBean需要实现的接口方法,直接取得当前的sessionFactory的值
     */
    public Object getObject() {
        return this.sessionFactory;
    }


这个值在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. }  
    public void afterPropertiesSet() throws Exception {
        //这个buildSessionFactory是通过配置信息得到SessionFactory的地方
        SessionFactory rawSf = buildSessionFactory();
        //这里使用了Proxy方法插入对getCurrentSession的拦截,得到和事务相关的session
        this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
    }


我们先看看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. }  
    protected SessionFactory buildSessionFactory() throws Exception {
        SessionFactory sf = null;

        // Create Configuration instance.
        Configuration config = newConfiguration();

        //这里配置数据源,事务管理器,LobHander到Holder中,这个Holder是一个ThreadLocal变量,这样这些资源就和线程绑定了
        if (this.dataSource != null) {
            // Make given DataSource available for SessionFactory configuration.
            configTimeDataSourceHolder.set(this.dataSource);
        }

        if (this.jtaTransactionManager != null) {
            // Make Spring-provided JTA TransactionManager available.
            configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
        }

        if (this.lobHandler != null) {
            // Make given LobHandler available for SessionFactory configuration.
            // Do early because because mapping resource might refer to custom types.
            configTimeLobHandlerHolder.set(this.lobHandler);
        }

        //这里是使用Hibernate的各个属性的配置,这里使用了Configuration类来抽象这些数据
        try {
            // Set connection release mode "on_close" as default.
            // This was the case for Hibernate 3.0; Hibernate 3.1 changed
            // it to "auto" (i.e. "after_statement" or "after_transaction").
            // However, for Spring's resource management (in particular for
            // HibernateTransactionManager), "on_close" is the better default.
            config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());

            if (!isExposeTransactionAwareSessionFactory()) {
                // Not exposing a SessionFactory proxy with transaction-aware
                // getCurrentSession() method -> set Hibernate 3.1 CurrentSessionContext
                // implementation instead, providing the Spring-managed Session that way.
                // Can be overridden by a custom value for corresponding Hibernate property.
                config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS,
                        "org.springframework.orm.hibernate3.SpringSessionContext");
            }

            if (this.entityInterceptor != null) {
                // Set given entity interceptor at SessionFactory level.
                config.setInterceptor(this.entityInterceptor);
            }

            if (this.namingStrategy != null) {
                // Pass given naming strategy to Hibernate Configuration.
                config.setNamingStrategy(this.namingStrategy);
            }

            if (this.typeDefinitions != null) {
                // Register specified Hibernate type definitions.
                Mappings mappings = config.createMappings();
                for (int i = 0; i < this.typeDefinitions.length; i++) {
                    TypeDefinitionBean typeDef = this.typeDefinitions[i];
                    mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
                }
            }

            if (this.filterDefinitions != null) {
                // Register specified Hibernate FilterDefinitions.
                for (int i = 0; i < this.filterDefinitions.length; i++) {
                    config.addFilterDefinition(this.filterDefinitions[i]);
                }
            }

            if (this.configLocations != null) {
                for (int i = 0; i < this.configLocations.length; i++) {
                    // Load Hibernate configuration from given location.
                    config.configure(this.configLocations[i].getURL());
                }
            }

            if (this.hibernateProperties != null) {
                // Add given Hibernate properties to Configuration.
                config.addProperties(this.hibernateProperties);
            }

            if (this.dataSource != null) {
                boolean actuallyTransactionAware =
                        (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);
                // Set Spring-provided DataSource as Hibernate ConnectionProvider.
                config.setProperty(Environment.CONNECTION_PROVIDER,
                        actuallyTransactionAware ?
                        TransactionAwareDataSourceConnectionProvider.class.getName() :
                        LocalDataSourceConnectionProvider.class.getName());
            }

            if (this.jtaTransactionManager != null) {
                // Set Spring-provided JTA TransactionManager as Hibernate property.
                config.setProperty(
                        Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
            }

            if (this.mappingLocations != null) {
                // Register given Hibernate mapping definitions, contained in resource files.
                for (int i = 0; i < this.mappingLocations.length; i++) {
                    config.addInputStream(this.mappingLocations[i].getInputStream());
                }
            }

            if (this.cacheableMappingLocations != null) {
                // Register given cacheable Hibernate mapping definitions, read from the file system.
                for (int i = 0; i < this.cacheableMappingLocations.length; i++) {
                    config.addCacheableFile(this.cacheableMappingLocations[i].getFile());
                }
            }

            if (this.mappingJarLocations != null) {
                // Register given Hibernate mapping definitions, contained in jar files.
                for (int i = 0; i < this.mappingJarLocations.length; i++) {
                    Resource resource = this.mappingJarLocations[i];
                    config.addJar(resource.getFile());
                }
            }

            if (this.mappingDirectoryLocations != null) {
                // Register all Hibernate mapping definitions in the given directories.
                for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
                    File file = this.mappingDirectoryLocations[i].getFile();
                    if (!file.isDirectory()) {
                        throw new IllegalArgumentException(
                                "Mapping directory location [" + this.mappingDirectoryLocations[i] +
                                "] does not denote a directory");
                    }
                    config.addDirectory(file);
                }
            }

            if (this.entityCacheStrategies != null) {
                // Register cache strategies for mapped entities.
                for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
                    String className = (String) classNames.nextElement();
                    String[] strategyAndRegion =
                            StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className));
                    if (strategyAndRegion.length > 1) {
                        config.setCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]);
                    }
                    else if (strategyAndRegion.length > 0) {
                        config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);
                    }
                }
            }

            if (this.collectionCacheStrategies != null) {
                // Register cache strategies for mapped collections.
                for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
                    String collRole = (String) collRoles.nextElement();
                    String[] strategyAndRegion =
                            StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole));
                    if (strategyAndRegion.length > 1) {
                        config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]);
                    }
                    else if (strategyAndRegion.length > 0) {
                        config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);
                    }
                }
            }

            if (this.eventListeners != null) {
                // Register specified Hibernate event listeners.
                for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
                    Map.Entry entry = (Map.Entry) it.next();
                    Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");
                    String listenerType = (String) entry.getKey();
                    Object listenerObject = entry.getValue();
                    if (listenerObject instanceof Collection) {
                        Collection listeners = (Collection) listenerObject;
                        EventListeners listenerRegistry = config.getEventListeners();
                        Object[] listenerArray =
                                (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
                        listenerArray = listeners.toArray(listenerArray);
                        config.setListeners(listenerType, listenerArray);
                    }
                    else {
                        config.setListener(listenerType, listenerObject);
                    }
                }
            }

            // Perform custom post-processing in subclasses.
            postProcessConfiguration(config);

            // 这里是根据Configuration配置创建SessionFactory的地方
            logger.info("Building new Hibernate SessionFactory");
            this.configuration = config;
            sf = newSessionFactory(config);
        }
        //最后把和线程绑定的资源清空
        finally {
            if (this.dataSource != null) {
                // Reset DataSource holder.
                configTimeDataSourceHolder.set(null);
            }

            if (this.jtaTransactionManager != null) {
                // Reset TransactionManager holder.
                configTimeTransactionManagerHolder.set(null);
            }

            if (this.lobHandler != null) {
                // Reset LobHandler holder.
                configTimeLobHandlerHolder.set(null);
            }
        }

        // Execute schema update if requested.
        if (this.schemaUpdate) {
            updateDatabaseSchema();
        }

        return sf;
    }


而直接调用org.hibernate.cfg.Configuration来得到需要的SessionFactory:

Java代码 复制代码
  1. protected  SessionFactory newSessionFactory(Configuration config)  throws  HibernateException {   
  2.      return  config.buildSessionFactory();   
  3. }  
    protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
        return config.buildSessionFactory();
    }


所以我们这里看到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.     }  
//这里先根据当前的SessionFactory的类型得到Proxy,然后插入Spring定义好的getCurrentSession拦截器
    protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {
        Class sfInterface = SessionFactory.class;
        if (target instanceof SessionFactoryImplementor) {
            sfInterface = SessionFactoryImplementor.class;
        }
        return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),
                new Class[] {sfInterface}, new TransactionAwareInvocationHandler(target));
    }


拦截器的实现如下:

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. }  
    private static class TransactionAwareInvocationHandler implements InvocationHandler {

        private final SessionFactory target;

        public TransactionAwareInvocationHandler(SessionFactory target) {
            this.target = target;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // Invocation on SessionFactory/SessionFactoryImplementor interface coming in...
            // 这里对getCurrentSession方法进行拦截,得到一个和当前事务绑定的session交给用户
            if (method.getName().equals("getCurrentSession")) {
                // Handle getCurrentSession method: return transactional Session, if any.
                try {
                    return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);
                }
                catch (IllegalStateException ex) {
                    throw new HibernateException(ex.getMessage());
                }
            }
            else if (method.getName().equals("equals")) {
                // Only consider equal when proxies are identical.
                return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
            }
            else if (method.getName().equals("hashCode")) {
                // Use hashCode of SessionFactory proxy.
                return new Integer(hashCode());
            }

            // 这里是需要运行的SessionFactory的目标方法
            try {
                return method.invoke(this.target, args);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }


我们看看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 != se
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

参与评论
请先登录 后发表评论~
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值