zoukankan      html  css  js  c++  java
  • Spring源代码分析(1)---LocalSessionFactoryBean(工厂的工厂)

    LocalSessionFacotoryBean其实就是适配了Configuration对象,或者说是一个工厂的工厂,他是Configuration的工厂,生成了Configuration以后,再利用他生成了SessioFactory;

      

    public class LocalSessionFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
        
        //线程变量的DataSource
        private static final ThreadLocal configTimeDataSourceHolder = new ThreadLocal();
        
        //线程变量TransactionManager
        private static final ThreadLocal configTimeTransactionManagerHolder = new ThreadLocal();
        
        //线程变量LoBHandler
        private static final ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
        //取得当前的线程变量,每个线程对应不同的变量;
        public static DataSource getConfigTimeDataSource() {
            return (DataSource) configTimeDataSourceHolder.get();
        }
        public static TransactionManager getConfigTimeTransactionManager() {
            return (TransactionManager) configTimeTransactionManagerHolder.get();
        }
        public static LobHandler getConfigTimeLobHandler() {
            return (LobHandler) configTimeLobHandlerHolder.get();
        }
        protected final Log logger = LogFactory.getLog(getClass());
        
        //一下是一些Hibernate的SessionFactory的配置属性,以前我们可以在hibernate.cfg.xml中配置;
        private Class configurationClass = Configuration.class;
        private Resource[] configLocations;
        
        //如下是对象和数据库表对应的hbm.xml文件
        private Resource[] mappingLocations;
        private Resource[] cacheableMappingLocations;
        private Resource[] mappingJarLocations;
        private Resource[] mappingDirectoryLocations;
        
        //Hibernate的属性设置
        private Properties hibernateProperties;
        
        //数据源
        private DataSource dataSource;
        private boolean useTransactionAwareDataSource = false;
        private boolean exposeTransactionAwareSessionFactory = true;
        private TransactionManager jtaTransactionManager;
        private LobHandler lobHandler;
        private Interceptor entityInterceptor;
        private NamingStrategy namingStrategy;
        private Properties entityCacheStrategies;
        private Properties collectionCacheStrategies;
        private TypeDefinitionBean[] typeDefinitions;
        private FilterDefinition[] filterDefinitions;
        private Map eventListeners;
        private boolean schemaUpdate = false;
        private Configuration configuration;
        
        //该对象是FactoryBean,会用getObject返回正真的对象;
        private SessionFactory sessionFactory;
        public void setConfigurationClass(Class configurationClass) {
            if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
                throw new IllegalArgumentException(
                        "configurationClass must be assignable to [org.hibernate.cfg.Configuration]");
            }
            this.configurationClass = configurationClass;
        }
        
        public void setMappingJarLocations(Resource[] mappingJarLocations) {
            this.mappingJarLocations = mappingJarLocations;
        }
        
        public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
            this.mappingDirectoryLocations = mappingDirectoryLocations;
        }
        public void setHibernateProperties(Properties hibernateProperties) {
            this.hibernateProperties = hibernateProperties;
        }
        public Properties getHibernateProperties() {
            if (this.hibernateProperties == null) {
                this.hibernateProperties = new Properties();
            }
            return this.hibernateProperties;
        }
        
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
        
        public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
            this.useTransactionAwareDataSource = useTransactionAwareDataSource;
        }
        
        public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
            this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
        }
        
        public void setJtaTransactionManager(TransactionManager jtaTransactionManager) {
            this.jtaTransactionManager = jtaTransactionManager;
        }
        
        public void setLobHandler(LobHandler lobHandler) {
            this.lobHandler = lobHandler;
        }
        
        public void setEntityInterceptor(Interceptor entityInterceptor) {
            this.entityInterceptor = entityInterceptor;
        }
        
        public void setNamingStrategy(NamingStrategy namingStrategy) {
            this.namingStrategy = namingStrategy;
        }
        =
        public void setEntityCacheStrategies(Properties entityCacheStrategies) {
            this.entityCacheStrategies = entityCacheStrategies;
        }
        =
        public void setCollectionCacheStrategies(Properties collectionCacheStrategies) {
            this.collectionCacheStrategies = collectionCacheStrategies;
        }
        public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) {
            this.typeDefinitions = typeDefinitions;
        }
        public void setFilterDefinitions(FilterDefinition[] filterDefinitions) {
            this.filterDefinitions = filterDefinitions;
        }
    =
        public void setEventListeners(Map eventListeners) {
            this.eventListeners = eventListeners;
        }
        /**
         * Set whether to execute a schema update after SessionFactory initialization.
         * <p>For details on how to make schema update scripts work, see the Hibernate
         * documentation, as this class leverages the same schema update script support
         * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
         * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
         * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
         */
        public void setSchemaUpdate(boolean schemaUpdate) {
            this.schemaUpdate = schemaUpdate;
        }
        /**
         * Initialize the SessionFactory for the given or the default location.
         * @throws IllegalArgumentException in case of illegal property values
         * @throws HibernateException in case of Hibernate initialization errors
         */
        //在这里开始生成一个真正的SessionFactory对象;然后利用getObjecy生成出来;
        public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
            // Create Configuration instance.
            //根据反射成成一个Configuration类;准备用他来生成SessioNFactory;
            //把接受到的configuration的属性设置给Configuration
            Configuration config = newConfiguration();
            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);
            }
            try {
                if (this.jtaTransactionManager != null) {
                    // Set Spring-provided JTA TransactionManager as Hibernate property.
                    config.setProperty(
                            Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
                    config.setProperty(
                            Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
                }
                else {
                    // 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 (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.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();
                        config.setCacheConcurrencyStrategy(className, this.entityCacheStrategies.getProperty(className));
                    }
                }
                if (this.collectionCacheStrategies != null) {
                    // Register cache strategies for mapped collections.
                    for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
                        String collRole = (String) collRoles.nextElement();
                        config.setCollectionCacheConcurrencyStrategy(
                                collRole, this.collectionCacheStrategies.getProperty(collRole));
                    }
                }
                 
                //增加时间处理器;
                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();
                        String listenerType = (String) entry.getKey();
                        Object listenerObject = entry.getValue();
                        config.setListener(listenerType, listenerObject);
                    }
                }
                //注意,这里是一个默认实现,其实我们可以叫钩子,他能够在Configuration生成之际是对其进行拦截处理;
                postProcessConfiguration(config);
                // Build SessionFactory instance.
                logger.info("Building new Hibernate SessionFactory");
                this.configuration = config;
                SessionFactory sf = newSessionFactory(config);
                //是否生成代理sessionFactoty对象,这个代理对象不同的是,他不能调用close方法,无用;
                if (this.exposeTransactionAwareSessionFactory) {
                    this.sessionFactory = getTransactionAwareSessionFactoryProxy(sf);
                }
                else {
                    this.sessionFactory = sf;
                }
                // Execute schema update if requested.
                if (this.schemaUpdate) {
                    updateDatabaseSchema();
                }
            }
            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);
                }
            }
        }
        /**
         * Subclasses can override this method to perform custom initialization
         * of the Configuration instance used for SessionFactory creation.
         * The properties of this LocalSessionFactoryBean will be applied to
         * the Configuration object that gets returned here.
         * <p>The default implementation creates a new Configuration instance.
         * A custom implementation could prepare the instance in a specific way,
         * or use a custom Configuration subclass.
         * @return the Configuration instance
         * @throws HibernateException in case of Hibernate initialization errors
         * @see org.hibernate.cfg.Configuration#Configuration()
         */
        //以下是Configuration生成SessionFactory的典型做法;
        protected Configuration newConfiguration() throws HibernateException {
            return (Configuration) BeanUtils.instantiateClass(this.configurationClass);
        }
        /**
         * To be implemented by subclasses that want to to perform custom
         * post-processing of the Configuration object after this FactoryBean
         * performed its default initialization.
         * @param config the current Configuration object
         * @throws HibernateException in case of Hibernate initialization errors
         */
        protected void postProcessConfiguration(Configuration config) throws HibernateException {
        }
        /**
         * Subclasses can override this method to perform custom initialization
         * of the SessionFactory instance, creating it via the given Configuration
         * object that got prepared by this LocalSessionFactoryBean.
         * <p>The default implementation invokes Configuration's buildSessionFactory.
         * A custom implementation could prepare the instance in a specific way,
         * or use a custom SessionFactoryImpl subclass.
         * @param config Configuration prepared by this LocalSessionFactoryBean
         * @return the SessionFactory instance
         * @throws HibernateException in case of Hibernate initialization errors
         * @see org.hibernate.cfg.Configuration#buildSessionFactory
         */
        protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
            return config.buildSessionFactory();
        }
        /**
         * Wrap the given SessionFactory with a proxy that delegates every method call
         * to it but delegates <code>getCurrentSession</code> calls to SessionFactoryUtils,
         * for participating in Spring-managed transactions.
         * @param target the original SessionFactory to wrap
         * @return the wrapped SessionFactory
         * @see org.hibernate.SessionFactory#getCurrentSession()
         * @see SessionFactoryUtils#doGetSession(org.hibernate.SessionFactory, boolean)
         */
        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));
        }
      =
        public void dropDatabaseSchema() throws DataAccessException {
            logger.info("Dropping database schema for Hibernate SessionFactory");
            HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
            hibernateTemplate.execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session) throws HibernateException, SQLException {
                        Connection con = session.connection();
                        Dialect dialect = Dialect.getDialect(configuration.getProperties());
                        String[] sql = configuration.generateDropSchemaScript(dialect);
                        executeSchemaScript(con, sql);
                        return null;
                    }
                }
            );
        }
        /**
         * Execute schema creation script, determined by the Configuration object
         * used for creating the SessionFactory. A replacement for Hibernate's
         * SchemaExport class, to be invoked on application setup.
         * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
         * SessionFactory to be able to invoke this method, e.g. via
         * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
         * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
         * connection to perform the script.
         * @throws DataAccessException in case of script execution errors
         * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript
         * @see org.hibernate.tool.hbm2ddl.SchemaExport#create
         */
        public void createDatabaseSchema() throws DataAccessException {
            logger.info("Creating database schema for Hibernate SessionFactory");
            HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
            hibernateTemplate.execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session) throws HibernateException, SQLException {
                        Connection con = session.connection();
                        Dialect dialect = Dialect.getDialect(configuration.getProperties());
                        String[] sql = configuration.generateSchemaCreationScript(dialect);
                        executeSchemaScript(con, sql);
                        return null;
                    }
                }
            );
        }
        /**
         * Execute schema update script, determined by the Configuration object
         * used for creating the SessionFactory. A replacement for Hibernate's
         * SchemaUpdate class, for automatically executing schema update scripts
         * on application startup. Can also be invoked manually.
         * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
         * SessionFactory to be able to invoke this method, e.g. via
         * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
         * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
         * connection to perform the script.
         * @throws DataAccessException in case of script execution errors
         * @see #setSchemaUpdate
         * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
         * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
         */
        public void updateDatabaseSchema() throws DataAccessException {
            logger.info("Updating database schema for Hibernate SessionFactory");
            HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
            hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
            hibernateTemplate.execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session) throws HibernateException, SQLException {
                        Connection con = session.connection();
                        Dialect dialect = Dialect.getDialect(configuration.getProperties());
                        DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
                        String[] sql = configuration.generateSchemaUpdateScript(dialect, metadata);
                        executeSchemaScript(con, sql);
                        return null;
                    }
                }
            );
        }
        
        protected void executeSchemaScript(Connection con, String[] sql) throws SQLException {
            if (sql != null && sql.length > 0) {
                boolean oldAutoCommit = con.getAutoCommit();
                if (!oldAutoCommit) {
                    con.setAutoCommit(true);
                }
                try {
                    Statement stmt = con.createStatement();
                    try {
                        for (int i = 0; i < sql.length; i++) {
                            executeSchemaStatement(stmt, sql[i]);
                        }
                    }
                    finally {
                        JdbcUtils.closeStatement(stmt);
                    }
                }
                finally {
                    if (!oldAutoCommit) {
                        con.setAutoCommit(false);
                    }
                }
            }
        }
       
        protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException {
            if (logger.isDebugEnabled()) {
                logger.debug("Executing schema statement: " + sql);
            }
            try {
                stmt.executeUpdate(sql);
            }
            catch (SQLException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Unsuccessful schema statement: " + sql, ex);
                }
            }
        }
        /**
         * Return the Configuration object used to build the SessionFactory.
         * Allows access to configuration metadata stored there (rarely needed).
         */
        public Configuration getConfiguration() {
            return this.configuration;
        }
        /**
         * Return the singleton SessionFactory.
         */
        public Object getObject() {
            return this.sessionFactory;
        }
        public Class getObjectType() {
            return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
        }
        public boolean isSingleton() {
            return true;
        }
        /**
         * Close the SessionFactory on bean factory shutdown.
         */
        public void destroy() throws HibernateException {
            logger.info("Closing Hibernate SessionFactory");
            if (this.dataSource != null) {
                // Make given DataSource available for potential SchemaExport,
                // which unfortunately reinstantiates a ConnectionProvider.
                configTimeDataSourceHolder.set(this.dataSource);
            }
            try {
                this.sessionFactory.close();
            }
            finally {
                if (this.dataSource != null) {
                    // Reset DataSource holder.
                    configTimeDataSourceHolder.set(null);
                }
            }
        }
        /**
         * Invocation handler that delegates <code>getCurrentSession()</code> calls
         * to SessionFactoryUtils, for being aware of thread-bound transactions.
         */
        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...
                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());
                }
                // Invoke method on target SessionFactory.
                try {
                    return method.invoke(this.target, args);
                }
                catch (InvocationTargetException ex) {
                    throw ex.getTargetException();
                }
            }
        }
    }
  • 相关阅读:
    8-6.布局元素实战
    Unity3D NGUI插件(3.12/2018/2019)
    GoLang 数据结构-二叉树
    GoLang 数据结构-哈希表(散列表)
    GoLang 四大经典排序(冒泡排序,选择排序,插入排序,快速排序)写法及执行效率
    GoLang 数据结构-单向链表,双向链表,单向环形链表
    GoLang 数据结构-环形队列
    GoLang 数据结构-稀疏数组
    GoLang 海量用户聊天系统(TCP-Socket网络编程+Redis数据库+协程)
    GoLang 使用协程和管道获取随机数
  • 原文地址:https://www.cnblogs.com/xjcheng1/p/7153151.html
Copyright © 2011-2022 走看看