现在的位置: 首页 > 综合 > 正文

Spring源代码分析(15)—LocalSessionFactoryBean(工厂的工厂)

2012年09月23日 ⁄ 综合 ⁄ 共 23410字 ⁄ 字号 评论关闭
LocalSessionFacotoryBean其实就是适配了Configuration对象,或者说是一个工厂的工厂,他是Configuration的工厂,生成了Configuration以后,再利用他生成了SessioFactory;

  1. public class LocalSessionFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
  2.     
  3.     //线程变量的DataSource
  4.     private static final ThreadLocal configTimeDataSourceHolder = new ThreadLocal();
  5.     
  6.     //线程变量TransactionManager
  7.     private static final ThreadLocal configTimeTransactionManagerHolder = new ThreadLocal();
  8.     
  9.     //线程变量LoBHandler
  10.     private static final ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
  11.     //取得当前的线程变量,每个线程对应不同的变量;
  12.     public static DataSource getConfigTimeDataSource() {
  13.         return (DataSource) configTimeDataSourceHolder.get();
  14.     }
  15.     public static TransactionManager getConfigTimeTransactionManager() {
  16.         return (TransactionManager) configTimeTransactionManagerHolder.get();
  17.     }
  18.     public static LobHandler getConfigTimeLobHandler() {
  19.         return (LobHandler) configTimeLobHandlerHolder.get();
  20.     }
  21.     protected final Log logger = LogFactory.getLog(getClass());
  22.     
  23.     //一下是一些Hibernate的SessionFactory的配置属性,以前我们可以在hibernate.cfg.xml中配置;
  24.     private Class configurationClass = Configuration.class;
  25.     private Resource[] configLocations;
  26.     
  27.     //如下是对象和数据库表对应的hbm.xml文件
  28.     private Resource[] mappingLocations;
  29.     private Resource[] cacheableMappingLocations;
  30.     private Resource[] mappingJarLocations;
  31.     private Resource[] mappingDirectoryLocations;
  32.     
  33.     //Hibernate的属性设置
  34.     private Properties hibernateProperties;
  35.     
  36.     //数据源
  37.     private DataSource dataSource;
  38.     private boolean useTransactionAwareDataSource = false;
  39.     private boolean exposeTransactionAwareSessionFactory = true;
  40.     private TransactionManager jtaTransactionManager;
  41.     private LobHandler lobHandler;
  42.     private Interceptor entityInterceptor;
  43.     private NamingStrategy namingStrategy;
  44.     private Properties entityCacheStrategies;
  45.     private Properties collectionCacheStrategies;
  46.     private TypeDefinitionBean[] typeDefinitions;
  47.     private FilterDefinition[] filterDefinitions;
  48.     private Map eventListeners;
  49.     private boolean schemaUpdate = false;
  50.     private Configuration configuration;
  51.     
  52.     //该对象是FactoryBean,会用getObject返回正真的对象;
  53.     private SessionFactory sessionFactory;
  54.     public void setConfigurationClass(Class configurationClass) {
  55.         if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
  56.             throw new IllegalArgumentException(
  57.                     "configurationClass must be assignable to [org.hibernate.cfg.Configuration]");
  58.         }
  59.         this.configurationClass = configurationClass;
  60.     }
  61.     
  62.     public void setMappingJarLocations(Resource[] mappingJarLocations) {
  63.         this.mappingJarLocations = mappingJarLocations;
  64.     }
  65.     
  66.     public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
  67.         this.mappingDirectoryLocations = mappingDirectoryLocations;
  68.     }
  69.     public void setHibernateProperties(Properties hibernateProperties) {
  70.         this.hibernateProperties = hibernateProperties;
  71.     }
  72.     public Properties getHibernateProperties() {
  73.         if (this.hibernateProperties == null) {
  74.             this.hibernateProperties = new Properties();
  75.         }
  76.         return this.hibernateProperties;
  77.     }
  78.     
  79.     public void setDataSource(DataSource dataSource) {
  80.         this.dataSource = dataSource;
  81.     }
  82.     
  83.     public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
  84.         this.useTransactionAwareDataSource = useTransactionAwareDataSource;
  85.     }
  86.     
  87.     public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
  88.         this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
  89.     }
  90.     
  91.     public void setJtaTransactionManager(TransactionManager jtaTransactionManager) {
  92.         this.jtaTransactionManager = jtaTransactionManager;
  93.     }
  94.     
  95.     public void setLobHandler(LobHandler lobHandler) {
  96.         this.lobHandler = lobHandler;
  97.     }
  98.     
  99.     public void setEntityInterceptor(Interceptor entityInterceptor) {
  100.         this.entityInterceptor = entityInterceptor;
  101.     }
  102.     
  103.     public void setNamingStrategy(NamingStrategy namingStrategy) {
  104.         this.namingStrategy = namingStrategy;
  105.     }
  106.     =
  107.     public void setEntityCacheStrategies(Properties entityCacheStrategies) {
  108.         this.entityCacheStrategies = entityCacheStrategies;
  109.     }
  110.     =
  111.     public void setCollectionCacheStrategies(Properties collectionCacheStrategies) {
  112.         this.collectionCacheStrategies = collectionCacheStrategies;
  113.     }
  114.     public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) {
  115.         this.typeDefinitions = typeDefinitions;
  116.     }
  117.     public void setFilterDefinitions(FilterDefinition[] filterDefinitions) {
  118.         this.filterDefinitions = filterDefinitions;
  119.     }
  120. =
  121.     public void setEventListeners(Map eventListeners) {
  122.         this.eventListeners = eventListeners;
  123.     }
  124.     /**
  125.      * Set whether to execute a schema update after SessionFactory initialization.
  126.      * <p>For details on how to make schema update scripts work, see the Hibernate
  127.      * documentation, as this class leverages the same schema update script support
  128.      * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
  129.      * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
  130.      * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
  131.      */
  132.     public void setSchemaUpdate(boolean schemaUpdate) {
  133.         this.schemaUpdate = schemaUpdate;
  134.     }
  135.     /**
  136.      * Initialize the SessionFactory for the given or the default location.
  137.      * @throws IllegalArgumentException in case of illegal property values
  138.      * @throws HibernateException in case of Hibernate initialization errors
  139.      */
  140.     //在这里开始生成一个真正的SessionFactory对象;然后利用getObjecy生成出来;
  141.     public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
  142.         // Create Configuration instance.
  143.         //根据反射成成一个Configuration类;准备用他来生成SessioNFactory;
  144.         //把接受到的configuration的属性设置给Configuration
  145.         Configuration config = newConfiguration();
  146.         if (this.dataSource != null) {
  147.             // Make given DataSource available for SessionFactory configuration.
  148.             configTimeDataSourceHolder.set(this.dataSource);
  149.         }
  150.         if (this.jtaTransactionManager != null) {
  151.             // Make Spring-provided JTA TransactionManager available.
  152.             configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
  153.         }
  154.         if (this.lobHandler != null) {
  155.             // Make given LobHandler available for SessionFactory configuration.
  156.             // Do early because because mapping resource might refer to custom types.
  157.             configTimeLobHandlerHolder.set(this.lobHandler);
  158.         }
  159.         try {
  160.             if (this.jtaTransactionManager != null) {
  161.                 // Set Spring-provided JTA TransactionManager as Hibernate property.
  162.                 config.setProperty(
  163.                         Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
  164.                 config.setProperty(
  165.                         Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
  166.             }
  167.             else {
  168.                 // Set connection release mode "on_close" as default.
  169.                 // This was the case for Hibernate 3.0; Hibernate 3.1 changed
  170.                 // it to "auto" (i.e. "after_statement" or "after_transaction").
  171.                 // However, for Spring's resource management (in particular for
  172.                 // HibernateTransactionManager), "on_close" is the better default.
  173.                 config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());
  174.             }
  175.             if (this.entityInterceptor != null) {
  176.                 // Set given entity interceptor at SessionFactory level.
  177.                 config.setInterceptor(this.entityInterceptor);
  178.             }
  179.             if (this.namingStrategy != null) {
  180.                 // Pass given naming strategy to Hibernate Configuration.
  181.                 config.setNamingStrategy(this.namingStrategy);
  182.             }
  183.             if (this.typeDefinitions != null) {
  184.                 // Register specified Hibernate type definitions.
  185.                 Mappings mappings = config.createMappings();
  186.                 for (int i = 0; i < this.typeDefinitions.length; i++) {
  187.                     TypeDefinitionBean typeDef = this.typeDefinitions[i];
  188.                     mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
  189.                 }
  190.             }
  191.             if (this.filterDefinitions != null) {
  192.                 // Register specified Hibernate FilterDefinitions.
  193.                 for (int i = 0; i < this.filterDefinitions.length; i++) {
  194.                     config.addFilterDefinition(this.filterDefinitions[i]);
  195.                 }
  196.             }
  197.             if (this.configLocations != null) {
  198.                 for (int i = 0; i < this.configLocations.length; i++) {
  199.                     // Load Hibernate configuration from given location.
  200.                     config.configure(this.configLocations[i].getURL());
  201.                 }
  202.             }
  203.             if (this.hibernateProperties != null) {
  204.                 // Add given Hibernate properties to Configuration.
  205.                 config.addProperties(this.hibernateProperties);
  206.             }
  207.             if (this.dataSource != null) {
  208.                 boolean actuallyTransactionAware =
  209.                         (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);
  210.                 // Set Spring-provided DataSource as Hibernate ConnectionProvider.
  211.                 config.setProperty(Environment.CONNECTION_PROVIDER,
  212.                         actuallyTransactionAware ?
  213.                         TransactionAwareDataSourceConnectionProvider.class.getName() :
  214.                         LocalDataSourceConnectionProvider.class.getName());
  215.             }
  216.             if (this.mappingLocations != null) {
  217.                 // Register given Hibernate mapping definitions, contained in resource files.
  218.                 for (int i = 0; i < this.mappingLocations.length; i++) {
  219.                     config.addInputStream(this.mappingLocations[i].getInputStream());
  220.                 }
  221.             }
  222.             if (this.cacheableMappingLocations != null) {
  223.                 // Register given cacheable Hibernate mapping definitions, read from the file system.
  224.                 for (int i = 0; i < this.cacheableMappingLocations.length; i++) {
  225.                     config.addCacheableFile(this.cacheableMappingLocations[i].getFile());
  226.                 }
  227.             }
  228.             if (this.mappingJarLocations != null) {
  229.                 // Register given Hibernate mapping definitions, contained in jar files.
  230.                 for (int i = 0; i < this.mappingJarLocations.length; i++) {
  231.                     Resource resource = this.mappingJarLocations[i];
  232.                     config.addJar(resource.getFile());
  233.                 }
  234.             }
  235.             if (this.mappingDirectoryLocations != null) {
  236.                 // Register all Hibernate mapping definitions in the given directories.
  237.                 for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
  238.                     File file = this.mappingDirectoryLocations[i].getFile();
  239.                     if (!file.isDirectory()) {
  240.                         throw new IllegalArgumentException(
  241.                                 "Mapping directory location [" + this.mappingDirectoryLocations[i] +
  242.                                 "] does not denote a directory");
  243.                     }
  244.                     config.addDirectory(file);
  245.                 }
  246.             }
  247.             if (this.entityCacheStrategies != null) {
  248.                 // Register cache strategies for mapped entities.
  249.                 for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
  250.                     String className = (String) classNames.nextElement();
  251.                     config.setCacheConcurrencyStrategy(className, this.entityCacheStrategies.getProperty(className));
  252.                 }
  253.             }
  254.             if (this.collectionCacheStrategies != null) {
  255.                 // Register cache strategies for mapped collections.
  256.                 for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
  257.                     String collRole = (String) collRoles.nextElement();
  258.                     config.setCollectionCacheConcurrencyStrategy(
  259.                             collRole, this.collectionCacheStrategies.getProperty(collRole));
  260.                 }
  261.             }
  262.              
  263.             //增加时间处理器;
  264.             if (this.eventListeners != null) {
  265.                 // Register specified Hibernate event listeners.
  266.                 for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
  267.                     Map.Entry entry = (Map.Entry) it.next();
  268.                     String listenerType = (String) entry.getKey();
  269.                     Object listenerObject = entry.getValue();
  270.                     config.setListener(listenerType, listenerObject);
  271.                 }
  272.             }
  273.             //注意,这里是一个默认实现,其实我们可以叫钩子,他能够在Configuration生成之际是对其进行拦截处理;
  274.             postProcessConfiguration(config);
  275.             // Build SessionFactory instance.
  276.             logger.info("Building new Hibernate SessionFactory");
  277.             this.configuration = config;
  278.             SessionFactory sf = newSessionFactory(config);
  279.             //是否生成代理sessionFactoty对象,这个代理对象不同的是,他不能调用close方法,无用;
  280.             if (this.exposeTransactionAwareSessionFactory) {
  281.                 this.sessionFactory = getTransactionAwareSessionFactoryProxy(sf);
  282.             }
  283.             else {
  284.                 this.sessionFactory = sf;
  285.             }
  286.             // Execute schema update if requested.
  287.             if (this.schemaUpdate) {
  288.                 updateDatabaseSchema();
  289.             }
  290.         }
  291.         finally {
  292.             if (this.dataSource != null) {
  293.                 // Reset DataSource holder.
  294.                 configTimeDataSourceHolder.set(null);
  295.             }
  296.             if (this.jtaTransactionManager != null) {
  297.                 // Reset TransactionManager holder.
  298.                 configTimeTransactionManagerHolder.set(null);
  299.             }
  300.             if (this.lobHandler != null) {
  301.                 // Reset LobHandler holder.
  302.                 configTimeLobHandlerHolder.set(null);
  303.             }
  304.         }
  305.     }
  306.     /**
  307.      * Subclasses can override this method to perform custom initialization
  308.      * of the Configuration instance used for SessionFactory creation.
  309.      * The properties of this LocalSessionFactoryBean will be applied to
  310.      * the Configuration object that gets returned here.
  311.      * <p>The default implementation creates a new Configuration instance.
  312.      * A custom implementation could prepare the instance in a specific way,
  313.      * or use a custom Configuration subclass.
  314.      * @return the Configuration instance
  315.      * @throws HibernateException in case of Hibernate initialization errors
  316.      * @see org.hibernate.cfg.Configuration#Configuration()
  317.      */
  318.     //以下是Configuration生成SessionFactory的典型做法;
  319.     protected Configuration newConfiguration() throws HibernateException {
  320.         return (Configuration) BeanUtils.instantiateClass(this.configurationClass);
  321.     }
  322.     /**
  323.      * To be implemented by subclasses that want to to perform custom
  324.      * post-processing of the Configuration object after this FactoryBean
  325.      * performed its default initialization.
  326.      * @param config the current Configuration object
  327.      * @throws HibernateException in case of Hibernate initialization errors
  328.      */
  329.     protected void postProcessConfiguration(Configuration config) throws HibernateException {
  330.     }
  331.     /**
  332.      * Subclasses can override this method to perform custom initialization
  333.      * of the SessionFactory instance, creating it via the given Configuration
  334.      * object that got prepared by this LocalSessionFactoryBean.
  335.      * <p>The default implementation invokes Configuration's buildSessionFactory.
  336.      * A custom implementation could prepare the instance in a specific way,
  337.      * or use a custom SessionFactoryImpl subclass.
  338.      * @param config Configuration prepared by this LocalSessionFactoryBean
  339.      * @return the SessionFactory instance
  340.      * @throws HibernateException in case of Hibernate initialization errors
  341.      * @see org.hibernate.cfg.Configuration#buildSessionFactory
  342.      */
  343.     protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
  344.         return config.buildSessionFactory();
  345.     }
  346.     /**
  347.      * Wrap the given SessionFactory with a proxy that delegates every method call
  348.      * to it but delegates <code>getCurrentSession</code> calls to SessionFactoryUtils,
  349.      * for participating in Spring-managed transactions.
  350.      * @param target the original SessionFactory to wrap
  351.      * @return the wrapped SessionFactory
  352.      * @see org.hibernate.SessionFactory#getCurrentSession()
  353.      * @see SessionFactoryUtils#doGetSession(org.hibernate.SessionFactory, boolean)
  354.      */
  355.     protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {
  356.         Class sfInterface = SessionFactory.class;
  357.         if (target instanceof SessionFactoryImplementor) {
  358.             sfInterface = SessionFactoryImplementor.class;
  359.         }
  360.         return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),
  361.                 new Class[] {sfInterface}, new TransactionAwareInvocationHandler(target));
  362.     }
  363.   =
  364.     public void dropDatabaseSchema() throws DataAccessException {
  365.         logger.info("Dropping database schema for Hibernate SessionFactory");
  366.         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  367.         hibernateTemplate.execute(
  368.             new HibernateCallback() {
  369.                 public Object doInHibernate(Session session) throws HibernateException, SQLException {
  370.                     Connection con = session.connection();
  371.                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
  372.                     String[] sql = configuration.generateDropSchemaScript(dialect);
  373.                     executeSchemaScript(con, sql);
  374.                     return null;
  375.                 }
  376.             }
  377.         );
  378.     }
  379.     /**
  380.      * Execute schema creation script, determined by the Configuration object
  381.      * used for creating the SessionFactory. A replacement for Hibernate's
  382.      * SchemaExport class, to be invoked on application setup.
  383.      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
  384.      * SessionFactory to be able to invoke this method, e.g. via
  385.      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
  386.      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
  387.      * connection to perform the script.
  388.      * @throws DataAccessException in case of script execution errors
  389.      * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript
  390.      * @see org.hibernate.tool.hbm2ddl.SchemaExport#create
  391.      */
  392.     public void createDatabaseSchema() throws DataAccessException {
  393.         logger.info("Creating database schema for Hibernate SessionFactory");
  394.         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  395.         hibernateTemplate.execute(
  396.             new HibernateCallback() {
  397.                 public Object doInHibernate(Session session) throws HibernateException, SQLException {
  398.                     Connection con = session.connection();
  399.                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
  400.                     String[] sql = configuration.generateSchemaCreationScript(dialect);
  401.                     executeSchemaScript(con, sql);
  402.                     return null;
  403.                 }
  404.             }
  405.         );
  406.     }
  407.     /**
  408.      * Execute schema update script, determined by the Configuration object
  409.      * used for creating the SessionFactory. A replacement for Hibernate's
  410.      * SchemaUpdate class, for automatically executing schema update scripts
  411.      * on application startup. Can also be invoked manually.
  412.      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
  413.      * SessionFactory to be able to invoke this method, e.g. via
  414.      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
  415.      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
  416.      * connection to perform the script.
  417.      * @throws DataAccessException in case of script execution errors
  418.      * @see #setSchemaUpdate
  419.      * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
  420.      * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
  421.      */
  422.     public void updateDatabaseSchema() throws DataAccessException {
  423.         logger.info("Updating database schema for Hibernate SessionFactory");
  424.         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  425.         hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
  426.         hibernateTemplate.execute(
  427.             new HibernateCallback() {
  428.                 public Object doInHibernate(Session session) throws HibernateException, SQLException {
  429.                     Connection con = session.connection();
  430.                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
  431.                     DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
  432.                     String[] sql = configuration.generateSchemaUpdateScript(dialect, metadata);
  433.                     executeSchemaScript(con, sql);
  434.                     return null;
  435.                 }
  436.             }
  437.         );
  438.     }
  439.     
  440.     protected void executeSchemaScript(Connection con, String[] sql) throws SQLException {
  441.         if (sql != null && sql.length > 0) {
  442.             boolean oldAutoCommit = con.getAutoCommit();
  443.             if (!oldAutoCommit) {
  444.                 con.setAutoCommit(true);
  445.             }
  446.             try {
  447.                 Statement stmt = con.createStatement();
  448.                 try {
  449.                     for (int i = 0; i < sql.length; i++) {
  450.                         executeSchemaStatement(stmt, sql[i]);
  451.                     }
  452.                 }
  453.                 finally {
  454.                     JdbcUtils.closeStatement(stmt);
  455.                 }
  456.             }
  457.             finally {
  458.                 if (!oldAutoCommit) {
  459.                     con.setAutoCommit(false);
  460.                 }
  461.             }
  462.         }
  463.     }
  464.    
  465.     protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException {
  466.         if (logger.isDebugEnabled()) {
  467.             logger.debug("Executing schema statement: " + sql);
  468.         }
  469.         try {
  470.             stmt.executeUpdate(sql);
  471.         }
  472.         catch (SQLException ex) {
  473.             if (logger.isWarnEnabled()) {
  474.                 logger.warn("Unsuccessful schema statement: " + sql, ex);
  475.             }
  476.         }
  477.     }
  478.     /**
  479.      * Return the Configuration object used to build the SessionFactory.
  480.      * Allows access to configuration metadata stored there (rarely needed).
  481.      */
  482.     public Configuration getConfiguration() {
  483.         return this.configuration;
  484.     }
  485.     /**
  486.      * Return the singleton SessionFactory.
  487.      */
  488.     public Object getObject() {
  489.         return this.sessionFactory;
  490.     }
  491.     public Class getObjectType() {
  492.         return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
  493.     }
  494.     public boolean isSingleton() {
  495.         return true;
  496.     }
  497.     /**
  498.      * Close the SessionFactory on bean factory shutdown.
  499.  

抱歉!评论已关闭.