sqlSessionFactory創建


 前言

分析上篇文章的整合的配置文件,我們可以知道配置的bean是成樹狀結構的,而在樹的最頂層是類型為org.mybatis.Spring.SqlSessionFactoryBean的bean,它將其他相關的bean組裝在了一起,那么我們的分析就從此類開始。

sqlSessionFactory創建

 對於配置文件的讀取,Spring是通過org.mybatis.Spring.SqlSessionFactoryBean封裝了MyBatis中的實現。首先來看一下這個類的類圖:

根據上圖對兩個感興趣的接口FactoryBean和InitializingBean。

  ❤ InitializingBean:實現此接口的bean會在初始化時調用其afterPropertiesSet方法來進行bean的邏輯初始化。

  ❤ FactoryBean:一旦某個bean實現此接口,那么通過getBean方法獲取bean時其實是獲取此類的getObject返回的實例。

1.sqlSessionFactoryBean的初始化

 查看org.mybatis.Spring.SqlSessionFactoryBean類型的bean在初始化時做了哪些邏輯實現。

public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.dataSource, "Property 'dataSource' is required");
        Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
        this.sqlSessionFactory = this.buildSqlSessionFactory();
    }

很顯然,此函數的主要目的是對於sqlSessionFactory的初始化,sqlSessionFactory是所有MyBatis功能的基礎。

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
        XMLConfigBuilder xmlConfigBuilder = null;
        Configuration configuration;
        if (this.configuration != null) {
            configuration = this.configuration;
            if (configuration.getVariables() == null) {
                configuration.setVariables(this.configurationProperties);
            } else if (this.configurationProperties != null) {
                configuration.getVariables().putAll(this.configurationProperties);
            }
        } else if (this.configLocation != null) {
            xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
            configuration = xmlConfigBuilder.getConfiguration();
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
            }

            configuration = new Configuration();
            if (this.configurationProperties != null) {
                configuration.setVariables(this.configurationProperties);
            }
        }

        if (this.objectFactory != null) {
            configuration.setObjectFactory(this.objectFactory);
        }

        if (this.objectWrapperFactory != null) {
            configuration.setObjectWrapperFactory(this.objectWrapperFactory);
        }

        if (this.vfs != null) {
            configuration.setVfsImpl(this.vfs);
        }

        String[] typeHandlersPackageArray;
        String[] var4;
        int var5;
        int var6;
        String packageToScan;
        if (StringUtils.hasLength(this.typeAliasesPackage)) {
            typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeAliasesPackage, ",; \t\n");
            var4 = typeHandlersPackageArray;
            var5 = typeHandlersPackageArray.length;

            for(var6 = 0; var6 < var5; ++var6) {
                packageToScan = var4[var6];
                configuration.getTypeAliasRegistry().registerAliases(packageToScan, this.typeAliasesSuperType == null ? Object.class : this.typeAliasesSuperType);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
                }
            }
        }

        int var27;
        if (!ObjectUtils.isEmpty(this.typeAliases)) {
            Class[] var25 = this.typeAliases;
            var27 = var25.length;

            for(var5 = 0; var5 < var27; ++var5) {
                Class<?> typeAlias = var25[var5];
                configuration.getTypeAliasRegistry().registerAlias(typeAlias);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Registered type alias: '" + typeAlias + "'");
                }
            }
        }

        if (!ObjectUtils.isEmpty(this.plugins)) {
            Interceptor[] var26 = this.plugins;
            var27 = var26.length;

            for(var5 = 0; var5 < var27; ++var5) {
                Interceptor plugin = var26[var5];
                configuration.addInterceptor(plugin);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Registered plugin: '" + plugin + "'");
                }
            }
        }

        if (StringUtils.hasLength(this.typeHandlersPackage)) {
            typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeHandlersPackage, ",; \t\n");
            var4 = typeHandlersPackageArray;
            var5 = typeHandlersPackageArray.length;

            for(var6 = 0; var6 < var5; ++var6) {
                packageToScan = var4[var6];
                configuration.getTypeHandlerRegistry().register(packageToScan);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
                }
            }
        }

        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            TypeHandler[] var28 = this.typeHandlers;
            var27 = var28.length;

            for(var5 = 0; var5 < var27; ++var5) {
                TypeHandler<?> typeHandler = var28[var5];
                configuration.getTypeHandlerRegistry().register(typeHandler);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Registered type handler: '" + typeHandler + "'");
                }
            }
        }

        if (this.databaseIdProvider != null) {
            try {
                configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
            } catch (SQLException var24) {
                throw new NestedIOException("Failed getting a databaseId", var24);
            }
        }

        if (this.cache != null) {
            configuration.addCache(this.cache);
        }

        if (xmlConfigBuilder != null) {
            try {
                xmlConfigBuilder.parse();
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
                }
            } catch (Exception var22) {
                throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var22);
            } finally {
                ErrorContext.instance().reset();
            }
        }

        if (this.transactionFactory == null) {
            this.transactionFactory = new SpringManagedTransactionFactory();
        }

        configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
        if (!ObjectUtils.isEmpty(this.mapperLocations)) {
            Resource[] var29 = this.mapperLocations;
            var27 = var29.length;

            for(var5 = 0; var5 < var27; ++var5) {
                Resource mapperLocation = var29[var5];
                if (mapperLocation != null) {
                    try {
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments());
                        xmlMapperBuilder.parse();
                    } catch (Exception var20) {
                        throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var20);
                    } finally {
                        ErrorContext.instance().reset();
                    }

                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
                    }
                }
            }
        } else if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
        }

        return this.sqlSessionFactoryBuilder.build(configuration);
    }

從函數中可以看到,盡管我們還是習慣於將MyBatis的配置和Spring的配置獨立出來,但是,這並不代表Spring中的配置不支持直接配置。也就是說,在上篇文章的示例中,完全褲取消配置中的configLocation屬性,而把其中的屬性直接寫在sqlSessionFactoryBean中。

從這個函數中還可以得知,配置文件還可以支持其他多種屬性的配置,如configLocation、objectFactory、objectWrapperFactory、typeAliasesPackage、typeAliases、typeHandlersPackage、plugins、typeHandlers、transactionFactory、databaseIdProvider、mapperLocations。

其實,如果只按照常用的配置,那么我們只需要在函數最開始按照如下方式處理configLocation:

   xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(),null,this.configurationProperties);
    configuration = xmlConfigBuilder.getConfiguration();

 根據configLocation構造XMLConfigBuilder並進行解析,但是,為了體現Spring更強大的兼容性,Spring還整合了MyBatis中其他屬性的注入,並通過實例configuration來承載每一步所獲取的信息並最終使用sqlSessionFactoryBuilder實例根據解析到的configuration創建sqlSessionFactory實例。

2.獲取SqlSessionFactoryBean實例

 由於sqlSessionFactoryBean實現了FactoryBean接口,所以當通過getBean方法獲取對應實例時,其實是獲取該類的getObject函數返回的實例,也就是獲得初始化后的sqlSessionFactory屬性。

public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }

 參考:《Spring源碼深度解析》 郝佳 編著: 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM