一. MybatisProperties 在使用 mybatis 時, 還需要對mapper進行配置: mybatis: mapper-locations: classpath:mapper/**Mapper.xml 這些配置其實是映射到 mybatis-spring-boot-autoconfig ...
一. MybatisProperties
在使用 mybatis 時, 還需要對mapper進行配置:
mybatis: mapper-locations: classpath:mapper/**Mapper.xml
這些配置其實是映射到 mybatis-spring-boot-autoconfigure 包下的 MybatisProperties 文件中的.
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) public class MybatisProperties { public static final String MYBATIS_PREFIX = "mybatis"; /** * Location of MyBatis xml config file. */ private String configLocation; /** * Locations of MyBatis mapper files. */ private String[] mapperLocations; /** * Packages to search type aliases. (Package delimiters are ",; \t\n") */ private String typeAliasesPackage; /** * Packages to search for type handlers. (Package delimiters are ",; \t\n") */ private String typeHandlersPackage; /** * Indicates whether perform presence check of the MyBatis xml config file. */ private boolean checkConfigLocation = false; /** * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}. */ private ExecutorType executorType; /** * Externalized properties for MyBatis configuration. */ private Properties configurationProperties; /** * A Configuration object for customize default settings. If {@link #configLocation} * is specified, this property is not used. */ @NestedConfigurationProperty private Configuration configuration; ...... }
二. MybatisAutoConfiguration
MybatisAutoConfiguration 是 mybatis-spring-boot-autoconfigure 中的一個配置類.
在這個配置類中, 主要加入了兩個組件: SqlSessionFactory 和 SqlSessionTemplate
1. SqlSessionFactory
@Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } Configuration configuration = this.properties.getConfiguration(); if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { configuration = new Configuration(); } if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { for (ConfigurationCustomizer customizer : this.configurationCustomizers) { customizer.customize(configuration); } } factory.setConfiguration(configuration); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } if (this.databaseIdProvider != null) { factory.setDatabaseIdProvider(this.databaseIdProvider); } if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); } if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { factory.setMapperLocations(this.properties.resolveMapperLocations()); } return factory.getObject(); }
(從名字可以看出來, SqlSessionFactory 是 SqlSession的一個工廠類. SqlSession 這個類很重要, 裡面定義了 資料庫的一套增刪改查操作的規範.)
MybatisProperties 中的配置會在這個方法中進行解析.
1. 創建了 Configuration 配置類(後面會用到, 這個類也很重要)的實例
2. 通過 factory.getObject() 方法創建了 SqlSessionFactory 類的實例
創建的過程中, 又調用了 protected SqlSessionFactory buildSqlSessionFactory() 方法進行創建, 創建過程比較多, 留給後面在解析.
2. SqlSessionTemplate
@Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType = this.properties.getExecutorType(); if (executorType != null) { return new SqlSessionTemplate(sqlSessionFactory, executorType); } else { return new SqlSessionTemplate(sqlSessionFactory); } }
SqlSessionTemplate 這個類 實現了 SqlSession 介面, 也就是說, 他也有一套 資料庫的 增刪改查的方法. 先看一下構造過程:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); } | | \|/ public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator( sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true)); } | | \|/ public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); }
這裡初始化了一個很重要的屬性: sqlSessionProxy.
sqlSessionProxy 是為 SqlSession 創建了一個代理類, 且代理方法為: SqlSessionInterceptor
看一個 實現了 SqlSession 介面中的 selectOne 方法:
@Override public <T> T selectOne(String statement, Object parameter) { return this.sqlSessionProxy.<T> selectOne(statement, parameter); }
可以看到, 在調用 selectOne 方法的時候, 其實就是調用了 SqlSessionInterceptor 的 invoke 方法.