瀏覽代碼

合并代码.

nieqiuqiu 6 年之前
父節點
當前提交
3eb9519d37

+ 384 - 361
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/spring/MybatisSqlSessionFactoryBean.java

@@ -21,19 +21,22 @@ import com.baomidou.mybatisplus.core.MybatisConfiguration;
 import com.baomidou.mybatisplus.core.MybatisXMLConfigBuilder;
 import com.baomidou.mybatisplus.core.config.GlobalConfig;
 import com.baomidou.mybatisplus.core.enums.IEnum;
-import com.baomidou.mybatisplus.core.toolkit.*;
+import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.baomidou.mybatisplus.extension.handlers.EnumAnnotationTypeHandler;
 import com.baomidou.mybatisplus.extension.handlers.EnumTypeHandler;
 import com.baomidou.mybatisplus.extension.toolkit.AopUtils;
 import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
 import com.baomidou.mybatisplus.extension.toolkit.PackageHelper;
 import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+
 import org.apache.ibatis.builder.xml.XMLMapperBuilder;
 import org.apache.ibatis.cache.Cache;
 import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.io.VFS;
-import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.mapping.DatabaseIdProvider;
 import org.apache.ibatis.mapping.Environment;
 import org.apache.ibatis.plugin.Interceptor;
@@ -46,6 +49,8 @@ import org.apache.ibatis.transaction.TransactionFactory;
 import org.apache.ibatis.type.EnumOrdinalTypeHandler;
 import org.apache.ibatis.type.TypeHandler;
 import org.apache.ibatis.type.TypeHandlerRegistry;
+import org.mybatis.logging.Logger;
+import org.mybatis.logging.LoggerFactory;
 import org.mybatis.spring.SqlSessionFactoryBean;
 import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
 import org.springframework.beans.factory.FactoryBean;
@@ -58,12 +63,20 @@ import org.springframework.core.NestedIOException;
 import org.springframework.core.io.Resource;
 import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
 
-import javax.sql.DataSource;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.sql.DataSource;
 
 import static org.springframework.util.Assert.notNull;
 import static org.springframework.util.Assert.state;
@@ -73,8 +86,8 @@ import static org.springframework.util.StringUtils.tokenizeToStringArray;
 
 /**
  * <p>
- * 拷贝类 org.mybatis.spring.SqlSessionFactoryBean 修改方法 buildSqlSessionFactory()
- * 加载自定义 MybatisXmlConfigBuilder
+ * 拷贝类 org.mybatis.spring.SqlSessionFactoryBean 修改方法 buildSqlSessionFactory() 加载自定义
+ * MybatisXmlConfigBuilder
  * </p>
  *
  * @author hubin
@@ -82,7 +95,7 @@ import static org.springframework.util.StringUtils.tokenizeToStringArray;
  */
 public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
 
-    private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(SqlSessionFactoryBean.class);
 
     private Resource configLocation;
 
@@ -141,142 +154,173 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
     /**
      * Sets the ObjectFactory.
      *
-     * @param objectFactory
      * @since 1.1.2
+     * @param objectFactory a custom ObjectFactory
      */
     public void setObjectFactory(ObjectFactory objectFactory) {
         this.objectFactory = objectFactory;
     }
 
-    /**
-     * Sets the ObjectWrapperFactory.
-     *
-     * @param objectWrapperFactory
-     * @since 1.1.2
-     */
-    public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
-        this.objectWrapperFactory = objectWrapperFactory;
-    }
-
-    /**
-     * Gets the DatabaseIdProvider
-     *
-     * @return
-     * @since 1.1.0
-     */
-    public DatabaseIdProvider getDatabaseIdProvider() {
-        return databaseIdProvider;
-    }
-
-    /**
-     * Sets the DatabaseIdProvider.
-     * As of version 1.2.2 this variable is not initialized by default.
-     *
-     * @param databaseIdProvider
-     * @since 1.1.0
-     */
-    public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) {
-        this.databaseIdProvider = databaseIdProvider;
-    }
-
-    public Class<? extends VFS> getVfs() {
-        return this.vfs;
-    }
-
-    public void setVfs(Class<? extends VFS> vfs) {
-        this.vfs = vfs;
-    }
-
-    public Cache getCache() {
-        return this.cache;
-    }
-
-    public void setCache(Cache cache) {
-        this.cache = cache;
-    }
-
-    /**
-     * Mybatis plugin list.
-     *
-     * @param plugins list of plugins
-     * @since 1.0.1
-     */
-    public void setPlugins(Interceptor[] plugins) {
-        this.plugins = plugins;
-    }
-
-    /**
-     * 支持 typeAliasesPackage 多项每项都有通配符 com.a.b.*.po, com.c.*.po
-     * ISSUE https://gitee.com/baomidou/mybatis-plus/issues/IKJ48
-     */
-    public void setTypeAliasesPackage(String typeAliasesPackage) {
-        this.typeAliasesPackage = typeAliasesPackage;
-    }
+  /**
+   * Sets the ObjectWrapperFactory.
+   *
+   * @since 1.1.2
+   * @param objectWrapperFactory a specified ObjectWrapperFactory
+   */
+  public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
+    this.objectWrapperFactory = objectWrapperFactory;
+  }
+
+  /**
+   * Gets the DatabaseIdProvider
+   *
+   * @since 1.1.0
+   * @return a specified DatabaseIdProvider
+   */
+  public DatabaseIdProvider getDatabaseIdProvider() {
+    return databaseIdProvider;
+  }
+
+  /**
+   * Sets the DatabaseIdProvider.
+   * As of version 1.2.2 this variable is not initialized by default.
+   *
+   * @since 1.1.0
+   * @param databaseIdProvider a DatabaseIdProvider
+   */
+  public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider) {
+    this.databaseIdProvider = databaseIdProvider;
+  }
+
+  /**
+   * Gets the VFS.
+   * @return a specified VFS
+   */
+  public Class<? extends VFS> getVfs() {
+    return this.vfs;
+  }
+
+  /**
+   * Sets the VFS.
+   * @param vfs a VFS
+   */
+  public void setVfs(Class<? extends VFS> vfs) {
+    this.vfs = vfs;
+  }
+
+  /**
+   * Gets the Cache.
+   * @return a specified Cache
+   */
+  public Cache getCache() {
+    return this.cache;
+  }
+
+  /**
+   * Sets the Cache.
+   * @param cache a Cache
+   */
+  public void setCache(Cache cache) {
+    this.cache = cache;
+  }
+
+  /**
+   * Mybatis plugin list.
+   *
+   * @since 1.0.1
+   *
+   * @param plugins list of plugins
+   *
+   */
+  public void setPlugins(Interceptor[] plugins) {
+    this.plugins = plugins;
+  }
+
+  /**
+   * Packages to search for type aliases.
+   * 支持 typeAliasesPackage 多项每项都有通配符 com.a.b.*.po, com.c.*.po ISSUE https://gitee.com/baomidou/mybatis-plus/issues/IKJ48
+   * @since 1.0.1
+   *
+   * @param typeAliasesPackage package to scan for domain objects
+   *
+   */
+  public void setTypeAliasesPackage(String typeAliasesPackage) {
+    this.typeAliasesPackage = typeAliasesPackage;
+  }
 
     public void setTypeEnumsPackage(String typeEnumsPackage) {
         this.typeEnumsPackage = typeEnumsPackage;
     }
 
-    /**
-     * Super class which domain objects have to extend to have a type alias created.
-     * No effect if there is no package to scan configured.
-     *
-     * @param typeAliasesSuperType super class for domain objects
-     * @since 1.1.2
-     */
-    public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
-        this.typeAliasesSuperType = typeAliasesSuperType;
-    }
-
-    /**
-     * Packages to search for type handlers.
-     *
-     * @param typeHandlersPackage package to scan for type handlers
-     * @since 1.0.1
-     */
-    public void setTypeHandlersPackage(String typeHandlersPackage) {
-        this.typeHandlersPackage = typeHandlersPackage;
-    }
-
-    /**
-     * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with {@code MappedJdbcTypes}
-     *
-     * @param typeHandlers Type handler list
-     * @since 1.0.1
-     */
-    public void setTypeHandlers(TypeHandler<?>[] typeHandlers) {
-        this.typeHandlers = typeHandlers;
-    }
-
-    /**
-     * List of type aliases to register. They can be annotated with {@code Alias}
-     *
-     * @param typeAliases Type aliases list
-     * @since 1.0.1
-     */
-    public void setTypeAliases(Class<?>[] typeAliases) {
-        this.typeAliases = typeAliases;
-    }
-
-    /**
-     * If true, a final check is done on Configuration to assure that all mapped
-     * statements are fully loaded and there is no one still pending to resolve
-     * includes. Defaults to false.
-     *
-     * @param failFast enable failFast
-     * @since 1.0.1
-     */
-    public void setFailFast(boolean failFast) {
-        this.failFast = failFast;
-    }
-
-    /**
-     * Set the location of the MyBatis {@code SqlSessionFactory} config file. A typical value is
-     * "WEB-INF/mybatis-configuration.xml".
-     */
-    public void setConfigLocation(Resource configLocation) {
-        this.configLocation = configLocation;
-    }
+  /**
+   * Super class which domain objects have to extend to have a type alias created.
+   * No effect if there is no package to scan configured.
+   *
+   * @since 1.1.2
+   *
+   * @param typeAliasesSuperType super class for domain objects
+   *
+   */
+  public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
+    this.typeAliasesSuperType = typeAliasesSuperType;
+  }
+
+  /**
+   * Packages to search for type handlers.
+   *
+   * @since 1.0.1
+   *
+   * @param typeHandlersPackage package to scan for type handlers
+   *
+   */
+  public void setTypeHandlersPackage(String typeHandlersPackage) {
+    this.typeHandlersPackage = typeHandlersPackage;
+  }
+
+  /**
+   * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with {@code MappedJdbcTypes}
+   *
+   * @since 1.0.1
+   *
+   * @param typeHandlers Type handler list
+   */
+  public void setTypeHandlers(TypeHandler<?>[] typeHandlers) {
+    this.typeHandlers = typeHandlers;
+  }
+
+  /**
+   * List of type aliases to register. They can be annotated with {@code Alias}
+   *
+   * @since 1.0.1
+   *
+   * @param typeAliases Type aliases list
+   */
+  public void setTypeAliases(Class<?>[] typeAliases) {
+    this.typeAliases = typeAliases;
+  }
+
+  /**
+   * If true, a final check is done on Configuration to assure that all mapped
+   * statements are fully loaded and there is no one still pending to resolve
+   * includes. Defaults to false.
+   *
+   * @since 1.0.1
+   *
+   * @param failFast enable failFast
+   */
+  public void setFailFast(boolean failFast) {
+    this.failFast = failFast;
+  }
+
+  /**
+   * Set the location of the MyBatis {@code SqlSessionFactory} config file. A typical value is
+   * "WEB-INF/mybatis-configuration.xml".
+   *
+   * @param configLocation a location the MyBatis config file
+   */
+  public void setConfigLocation(Resource configLocation) {
+    this.configLocation = configLocation;
+  }
 
     /**
      * Set a customized MyBatis configuration.
@@ -288,119 +332,128 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
         this.configuration = configuration;
     }
 
-    /**
-     * Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory}
-     * configuration at runtime.
-     * <p>
-     * This is an alternative to specifying "&lt;sqlmapper&gt;" entries in an MyBatis config file.
-     * This property being based on Spring's resource abstraction also allows for specifying
-     * resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".
-     */
-    public void setMapperLocations(Resource[] mapperLocations) {
-        this.mapperLocations = mapperLocations;
-    }
-
-    /**
-     * Set optional properties to be passed into the SqlSession configuration, as alternative to a
-     * {@code &lt;properties&gt;} tag in the configuration xml file. This will be used to
-     * resolve placeholders in the config file.
-     */
-    public void setConfigurationProperties(Properties sqlSessionFactoryProperties) {
-        this.configurationProperties = sqlSessionFactoryProperties;
-    }
-
-    /**
-     * Set the JDBC {@code DataSource} that this instance should manage transactions for. The {@code DataSource}
-     * should match the one used by the {@code SqlSessionFactory}: for example, you could specify the same
-     * JNDI DataSource for both.
-     * <p>
-     * A transactional JDBC {@code Connection} for this {@code DataSource} will be provided to application code
-     * accessing this {@code DataSource} directly via {@code DataSourceUtils} or {@code DataSourceTransactionManager}.
-     * <p>
-     * The {@code DataSource} specified here should be the target {@code DataSource} to manage transactions for, not
-     * a {@code TransactionAwareDataSourceProxy}. Only data access code may work with
-     * {@code TransactionAwareDataSourceProxy}, while the transaction manager needs to work on the
-     * underlying target {@code DataSource}. If there's nevertheless a {@code TransactionAwareDataSourceProxy}
-     * passed in, it will be unwrapped to extract its target {@code DataSource}.
-     */
-    public void setDataSource(DataSource dataSource) {
-        if (dataSource instanceof TransactionAwareDataSourceProxy) {
-            // If we got a TransactionAwareDataSourceProxy, we need to perform
-            // transactions for its underlying target DataSource, else data
-            // access code won't see properly exposed transactions (i.e.
-            // transactions for the target DataSource).
-            this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
-        } else {
-            this.dataSource = dataSource;
-        }
-    }
-
-    /**
-     * Sets the {@code SqlSessionFactoryBuilder} to use when creating the {@code SqlSessionFactory}.
-     * <p>
-     * This is mainly meant for testing so that mock SqlSessionFactory classes can be injected. By
-     * default, {@code SqlSessionFactoryBuilder} creates {@code DefaultSqlSessionFactory} instances.
-     */
-    public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder) {
-        this.sqlSessionFactoryBuilder = sqlSessionFactoryBuilder;
-    }
-
-    /**
-     * Set the MyBatis TransactionFactory to use. Default is {@code SpringManagedTransactionFactory}
-     * <p>
-     * The default {@code SpringManagedTransactionFactory} should be appropriate for all cases:
-     * be it Spring transaction management, EJB CMT or plain JTA. If there is no active transaction,
-     * SqlSession operations will execute SQL statements non-transactionally.
-     * <p>
-     * <b>It is strongly recommended to use the default {@code TransactionFactory}.</b> If not used, any
-     * attempt at getting an SqlSession through Spring's MyBatis framework will throw an exception if
-     * a transaction is active.
-     *
-     * @param transactionFactory the MyBatis TransactionFactory
-     * @see SpringManagedTransactionFactory
-     */
-    public void setTransactionFactory(TransactionFactory transactionFactory) {
-        this.transactionFactory = transactionFactory;
-    }
-
-    /**
-     * <b>NOTE:</b> This class <em>overrides</em> any {@code Environment} you have set in the MyBatis
-     * config file. This is used only as a placeholder name. The default value is
-     * {@code SqlSessionFactoryBean.class.getSimpleName()}.
-     *
-     * @param environment the environment name
-     */
-    public void setEnvironment(String environment) {
-        this.environment = environment;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        notNull(dataSource, "Property 'dataSource' is required");
-        notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
-        state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
-            "Property 'configuration' and 'configLocation' can not specified with together");
-
-        this.sqlSessionFactory = buildSqlSessionFactory();
-        //TODO: 3.0 注入到globalConfig
-    }
+  /**
+   * Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory}
+   * configuration at runtime.
+   *
+   * This is an alternative to specifying "&lt;sqlmapper&gt;" entries in an MyBatis config file.
+   * This property being based on Spring's resource abstraction also allows for specifying
+   * resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".
+   *
+   * @param mapperLocations location of MyBatis mapper files
+   */
+  public void setMapperLocations(Resource[] mapperLocations) {
+    this.mapperLocations = mapperLocations;
+  }
+
+  /**
+   * Set optional properties to be passed into the SqlSession configuration, as alternative to a
+   * {@code &lt;properties&gt;} tag in the configuration xml file. This will be used to
+   * resolve placeholders in the config file.
+   *
+   * @param  sqlSessionFactoryProperties optional properties for the SqlSessionFactory
+   */
+  public void setConfigurationProperties(Properties sqlSessionFactoryProperties) {
+    this.configurationProperties = sqlSessionFactoryProperties;
+  }
+
+  /**
+   * Set the JDBC {@code DataSource} that this instance should manage transactions for. The {@code DataSource}
+   * should match the one used by the {@code SqlSessionFactory}: for example, you could specify the same
+   * JNDI DataSource for both.
+   *
+   * A transactional JDBC {@code Connection} for this {@code DataSource} will be provided to application code
+   * accessing this {@code DataSource} directly via {@code DataSourceUtils} or {@code DataSourceTransactionManager}.
+   *
+   * The {@code DataSource} specified here should be the target {@code DataSource} to manage transactions for, not
+   * a {@code TransactionAwareDataSourceProxy}. Only data access code may work with
+   * {@code TransactionAwareDataSourceProxy}, while the transaction manager needs to work on the
+   * underlying target {@code DataSource}. If there's nevertheless a {@code TransactionAwareDataSourceProxy}
+   * passed in, it will be unwrapped to extract its target {@code DataSource}.
+   *
+   * @param dataSource a JDBC {@code DataSource}
+   *
+   */
+  public void setDataSource(DataSource dataSource) {
+    if (dataSource instanceof TransactionAwareDataSourceProxy) {
+      // If we got a TransactionAwareDataSourceProxy, we need to perform
+      // transactions for its underlying target DataSource, else data
+      // access code won't see properly exposed transactions (i.e.
+      // transactions for the target DataSource).
+      this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
+    } else {
+      this.dataSource = dataSource;
+    }
+  }
+
+  /**
+   * Sets the {@code SqlSessionFactoryBuilder} to use when creating the {@code SqlSessionFactory}.
+   *
+   * This is mainly meant for testing so that mock SqlSessionFactory classes can be injected. By
+   * default, {@code SqlSessionFactoryBuilder} creates {@code DefaultSqlSessionFactory} instances.
+   *
+   * @param sqlSessionFactoryBuilder a SqlSessionFactoryBuilder
+   *
+   */
+  public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder) {
+    this.sqlSessionFactoryBuilder = sqlSessionFactoryBuilder;
+  }
+
+  /**
+   * Set the MyBatis TransactionFactory to use. Default is {@code SpringManagedTransactionFactory}
+   *
+   * The default {@code SpringManagedTransactionFactory} should be appropriate for all cases:
+   * be it Spring transaction management, EJB CMT or plain JTA. If there is no active transaction,
+   * SqlSession operations will execute SQL statements non-transactionally.
+   *
+   * <b>It is strongly recommended to use the default {@code TransactionFactory}.</b> If not used, any
+   * attempt at getting an SqlSession through Spring's MyBatis framework will throw an exception if
+   * a transaction is active.
+   *
+   * @see SpringManagedTransactionFactory
+   * @param transactionFactory the MyBatis TransactionFactory
+   */
+  public void setTransactionFactory(TransactionFactory transactionFactory) {
+    this.transactionFactory = transactionFactory;
+  }
+
+  /**
+   * <b>NOTE:</b> This class <em>overrides</em> any {@code Environment} you have set in the MyBatis
+   * config file. This is used only as a placeholder name. The default value is
+   * {@code SqlSessionFactoryBean.class.getSimpleName()}.
+   *
+   * @param environment the environment name
+   */
+  public void setEnvironment(String environment) {
+    this.environment = environment;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void afterPropertiesSet() throws Exception {
+    notNull(dataSource, "Property 'dataSource' is required");
+    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
+    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
+              "Property 'configuration' and 'configLocation' can not specified with together");
+
+    this.sqlSessionFactory = buildSqlSessionFactory();
+  }
 
     /**
      * Build a {@code SqlSessionFactory} instance.
      * <p>
      * The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a
-     * {@code SqlSessionFactory} instance based on an Reader.
-     * Since 1.3.0, it can be specified a {@link Configuration} instance directly(without config file).
+     * {@code SqlSessionFactory} instance based on an Reader. Since 1.3.0, it can be specified a
+     * {@link Configuration} instance directly(without config file).
      *
      * @return SqlSessionFactory
      * @throws IOException if loading the config file failed
      */
     protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
 
-        MybatisConfiguration configuration;
+        final MybatisConfiguration configuration;
 
         // TODO 加载自定义 MybatisXmlConfigBuilder
         MybatisXMLConfigBuilder xmlConfigBuilder = null;
@@ -415,16 +468,13 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
             xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
             configuration = xmlConfigBuilder.getConfiguration();
         } else {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
-            }
+            LOGGER.debug(() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
             // TODO 使用自定义配置
             configuration = new MybatisConfiguration();
-            if (this.configurationProperties != null) {
-                configuration.setVariables(this.configurationProperties);
-            }
+            Optional.ofNullable(this.configurationProperties).ifPresent(configuration::setVariables);
         }
 
+
         // TODO 无配置启动所必须的
         if (this.globalConfig == null) {
             this.globalConfig = GlobalConfigUtils.defaults();
@@ -440,13 +490,9 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
             configuration.setObjectFactory(this.objectFactory);
         }
 
-        if (this.objectWrapperFactory != null) {
-            configuration.setObjectWrapperFactory(this.objectWrapperFactory);
-        }
-
-        if (this.vfs != null) {
-            configuration.setVfsImpl(this.vfs);
-        }
+        Optional.ofNullable(this.objectFactory).ifPresent(configuration::setObjectFactory);
+        Optional.ofNullable(this.objectWrapperFactory).ifPresent(configuration::setObjectWrapperFactory);
+        Optional.ofNullable(this.vfs).ifPresent(configuration::setVfsImpl);
 
         if (hasLength(this.typeAliasesPackage)) {
             // TODO 支持自定义通配符
@@ -454,7 +500,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
             if (typeAliasesPackage.contains(StringPool.ASTERISK) && !typeAliasesPackage.contains(StringPool.COMMA) && !typeAliasesPackage.contains(StringPool.SEMICOLON)) {
                 String[] convertTypeAliasesPackages = PackageHelper.convertTypeAliasesPackage(this.typeAliasesPackage);
                 if (ArrayUtils.isEmpty(convertTypeAliasesPackages)) {
-                    LOGGER.warn("Can't find class in '[" + this.typeAliasesPackage + "]' package. Please check your configuration.");
+                    LOGGER.warn(() -> "Can't find class in '[" + this.typeAliasesPackage + "]' package. Please check your configuration.");
                 } else {
                     typeAliasPackageList.addAll(Arrays.asList(convertTypeAliasesPackages));
                 }
@@ -464,7 +510,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
                     if (one.contains(StringPool.ASTERISK)) {
                         String[] convertTypeAliasesPackages = PackageHelper.convertTypeAliasesPackage(one);
                         if (ArrayUtils.isEmpty(convertTypeAliasesPackages)) {
-                            LOGGER.warn("Can't find class in '[" + one + "]' package. Please check your configuration.");
+                            LOGGER.warn(() -> "Can't find class in '[" + one + "]' package. Please check your configuration.");
                         } else {
                             typeAliasPackageList.addAll(Arrays.asList(convertTypeAliasesPackages));
                         }
@@ -476,9 +522,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
             for (String packageToScan : typeAliasPackageList) {
                 configuration.getTypeAliasRegistry().registerAliases(packageToScan,
                     typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
-                }
+                LOGGER.debug(() -> "Scanned package: '" + packageToScan + "' for aliases");
             }
         }
 
@@ -489,7 +533,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
                 && !typeEnumsPackage.contains(StringPool.SEMICOLON)) {
                 classes = PackageHelper.scanTypePackage(typeEnumsPackage);
                 if (classes.isEmpty()) {
-                    LOGGER.warn("Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
+                    LOGGER.warn(() -> "Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
                 }
             } else {
                 String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage,
@@ -499,7 +543,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
                 for (String typePackage : typeEnumsPackageArray) {
                     Set<Class> scanTypePackage = PackageHelper.scanTypePackage(typePackage);
                     if (scanTypePackage.isEmpty()) {
-                        LOGGER.warn("Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
+                        LOGGER.warn(() -> "Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
                     } else {
                         classes.addAll(PackageHelper.scanTypePackage(typePackage));
                     }
@@ -526,69 +570,56 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
             }
         }
 
-        if (!isEmpty(this.typeAliases)) {
-            for (Class<?> typeAlias : this.typeAliases) {
-                configuration.getTypeAliasRegistry().registerAlias(typeAlias);
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Registered type alias: '" + typeAlias + "'");
-                }
-            }
-        }
-
-        if (!isEmpty(this.plugins)) {
-            for (Interceptor plugin : this.plugins) {
-                configuration.addInterceptor(plugin);
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Registered plugin: '" + plugin + "'");
-                }
-            }
-        }
+    if (!isEmpty(this.typeAliases)) {
+      Stream.of(this.typeAliases).forEach(typeAlias -> {
+        configuration.getTypeAliasRegistry().registerAlias(typeAlias);
+        LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
+      });
+    }
 
-        if (hasLength(this.typeHandlersPackage)) {
-            String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
-                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
-            for (String packageToScan : typeHandlersPackageArray) {
-                configuration.getTypeHandlerRegistry().register(packageToScan);
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
-                }
-            }
-        }
+    if (!isEmpty(this.plugins)) {
+      Stream.of(this.plugins).forEach(plugin -> {
+          configuration.addInterceptor(plugin);
+        LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
+      });
+    }
 
-        if (!isEmpty(this.typeHandlers)) {
-            for (TypeHandler<?> typeHandler : this.typeHandlers) {
-                configuration.getTypeHandlerRegistry().register(typeHandler);
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Registered type handler: '" + typeHandler + "'");
-                }
-            }
-        }
+    if (hasLength(this.typeHandlersPackage)) {
+      String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
+          ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+      Stream.of(typeHandlersPackageArray).forEach(packageToScan -> {
+          configuration.getTypeHandlerRegistry().register(packageToScan);
+        LOGGER.debug(() -> "Scanned package: '" + packageToScan + "' for type handlers");
+      });
+    }
 
-        if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
-            try {
-                configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
-            } catch (SQLException e) {
-                throw new NestedIOException("Failed getting a databaseId", e);
-            }
-        }
+    if (!isEmpty(this.typeHandlers)) {
+      Stream.of(this.typeHandlers).forEach(typeHandler -> {
+          configuration.getTypeHandlerRegistry().register(typeHandler);
+        LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
+      });
+    }
 
-        if (this.cache != null) {
-            configuration.addCache(this.cache);
-        }
+    if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
+      try {
+          configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
+      } catch (SQLException e) {
+        throw new NestedIOException("Failed getting a databaseId", e);
+      }
+    }
 
-        if (xmlConfigBuilder != null) {
-            try {
-                xmlConfigBuilder.parse();
+    Optional.ofNullable(this.cache).ifPresent(configuration::addCache);
 
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
-                }
-            } catch (Exception ex) {
-                throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
-            } finally {
-                ErrorContext.instance().reset();
-            }
-        }
+    if (xmlConfigBuilder != null) {
+      try {
+        xmlConfigBuilder.parse();
+        LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
+      } catch (Exception ex) {
+        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
+      } finally {
+        ErrorContext.instance().reset();
+      }
+    }
 
         if (this.transactionFactory == null) {
             this.transactionFactory = new SpringManagedTransactionFactory();
@@ -634,23 +665,16 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
                     ErrorContext.instance().reset();
                 }
 
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
-                }
+                LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
             }
         } else {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
-            }
+            LOGGER.debug(() -> "Property 'mapperLocations' was not specified or no matching resources found");
         }
         return sqlSessionFactory;
     }
 
     /**
-     * 处理普通枚举
-     * 把带{@link EnumValue}的field注册到处理器中
-     *
-     * @param clazz
+     * 处理普通枚举 把带{@link EnumValue}的field注册到处理器中
      */
     protected Class<?> dealEnumType(Class<?> clazz) {
         if (clazz.isEnum()) {
@@ -668,49 +692,48 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 
     /**
      * 对原生枚举的处理类,默认{@link EnumOrdinalTypeHandler}
-     *
-     * @param typeHandlerRegistry
-     * @param enumClazz
      */
     protected void registerOriginalEnumTypeHandler(TypeHandlerRegistry typeHandlerRegistry, Class<?> enumClazz) {
         typeHandlerRegistry.register(enumClazz, EnumOrdinalTypeHandler.class);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public SqlSessionFactory getObject() throws Exception {
-        if (this.sqlSessionFactory == null) {
-            afterPropertiesSet();
-        }
-        return this.sqlSessionFactory;
-    }
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SqlSessionFactory getObject() throws Exception {
+    if (this.sqlSessionFactory == null) {
+      afterPropertiesSet();
+    }
+
+    return this.sqlSessionFactory;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Class<? extends SqlSessionFactory> getObjectType() {
+    return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isSingleton() {
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void onApplicationEvent(ApplicationEvent event) {
+    if (failFast && event instanceof ContextRefreshedEvent) {
+      // fail-fast -> check all statements are completed
+      this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
+    }
+  }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Class<? extends SqlSessionFactory> getObjectType() {
-        return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isSingleton() {
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onApplicationEvent(ApplicationEvent event) {
-        if (failFast && event instanceof ContextRefreshedEvent) {
-            // fail-fast -> check all statements are completed
-            this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
-        }
-    }
 }