mybatis 作为一个轻量级的orm 框架 具有减少sql编写,提高开发效率的能力.而且在插件化这块 做到了可插拔功能.
实现了 简单 易用
groupid | artifactId | version |
---|---|---|
org.mybatis | mybatis | 3.2.8 |
org.mybatis | mybatis-spring | 1.2.3 |
tk.mybatis | mapper | 3.3.0 |
申明mybatis mapper.xml 路径 插件 数据源配置等
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="xxx" />
<property name="url" value="xxx" />
<property name="username" value="xxx" />
<property name="password" value="xxx" />
<property name="maxActive" value="xxx" />
<property name="initialSize" value="xxx" />
<property name="minIdle" value="xxx" />
<property name="maxWait" value="xxx" />
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<list>
<value>classpath:mapper/*.xmlvalue>
list>
property>
<property name="typeAliasesPackage" value="com.sun.model"/>
<property name="plugins">
<array>
<bean class="com.sun.plugins.DataSourceSharePlugin"/>
array>
property>
bean>
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.sun.mapper.**"/>
<property name="markerInterface" value="com.sun.mapper.base.BaseBillMapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
bean>
beans>
org.mybatis.spring.SqlSessionFactoryBean: 字面意思 sqlSession的生产工厂
tk.mybatis.spring.mapper.MapperScannerConfigurer: 扫描mapper接口 生成一个代理类 并注入到spring 容器中
主要完成:mybatis mapper.xml的映射 插件初始化 sqlSessiong构建
这个类 实现了InitializingBean 接口 ,这个接口的只提供了一个afterPropertiesSet 方法,spring 容器在初始化bean之后就会执行该方法
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
/**
* {@inheritDoc}
*/
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
/** 构造factory */
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
/** 配置类 */
Configuration configuration;
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
}
configuration = new Configuration();
configuration.setVariables(this.configurationProperties);
}
if (this.objectFactory != null) {
configuration.setObjectFactory(this.objectFactory);
}
if (this.objectWrapperFactory != null) {
configuration.setObjectWrapperFactory(this.objectWrapperFactory);
}
/** 设置类型别名的package */
if (hasLength(this.typeAliasesPackage)) {
String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packageToScan : typeAliasPackageArray) {
configuration.getTypeAliasRegistry().registerAliases(packageToScan,
typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
}
}
}
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 (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.typeHandlers)) {
for (TypeHandler> typeHandler : this.typeHandlers) {
configuration.getTypeHandlerRegistry().register(typeHandler);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Registered type handler: '" + typeHandler + "'");
}
}
}
if (xmlConfigBuilder != null) {
try {
xmlConfigBuilder.parse();
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 (this.transactionFactory == null) {
this.transactionFactory = new SpringManagedTransactionFactory();
}
/** 设置 事务 数据源 */
configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
if (this.databaseIdProvider != null) {
try {
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}
if (!isEmpty(this.mapperLocations)) {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
/** 实现mapper xml解析 */
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} 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");
}
}
/** 构造sqlSessionFactory */
return this.sqlSessionFactoryBuilder.build(configuration);
}
SqlSessionFactoryBuilder
public class SqlSessionFactoryBuilder {
//省略其他方法
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {
/** 其他方法省略 */
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
/**
* sqlSession 是mybatis 的sql执行器 默认有 DefaultSqlSession
* SqlSessionManager SqlSessionTemplate 3个实现类
* 默认使用 DefaultSqlSession 实现
*/
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
/** 最终sql的执行器 默认使用 SimpleExecutor */
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
主要功能:完成mapper interface 接口生成代理类 并注入到spring的容器中
/** 继承了mybatis 的 MapperScannerConfigurer 由于 父类 实现了
* BeanDefinitionRegistryPostProcessor 接口
* 所以初始化会调用 postProcessBeanDefinitionRegistry 方法.
* */
public class MapperScannerConfigurer extends org.mybatis.spring.mapper.MapperScannerConfigurer {
/**
* 注册完成后,对MapperFactoryBean的类进行特殊处理
*
* @param registry
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
super.postProcessBeanDefinitionRegistry(registry);
//如果没有注册过接口,就注册默认的Mapper接口
this.mapperHelper.ifEmptyRegisterDefaultInterface();
String[] names = registry.getBeanDefinitionNames();
GenericBeanDefinition definition;
for (String name : names) {
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
if (beanDefinition instanceof GenericBeanDefinition) {
definition = (GenericBeanDefinition) beanDefinition;
if (StringUtil.isNotEmpty(definition.getBeanClassName())
&& definition.getBeanClassName().equals("org.mybatis.spring.mapper.MapperFactoryBean")) {
/** mapper 代理类生产工厂 */
definition.setBeanClass(MapperFactoryBean.class);
definition.getPropertyValues().add("mapperHelper", this.mapperHelper);
}
}
}
}
}
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
/**
* {@inheritDoc}
* 扫描mapper inteface
* @since 1.0.2
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
/** 扫描并注入spring bean容器 */
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
/** 省略部分代码 */
private Class> markerInterface;
private MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();
/** 生成mybatis mapper对应的 MapperFactoryBean */
private void processBeanDefinitions(Set beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
//通过反射设置属性值
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
//MapperFactoryBean 中 sqlSessionFactory会生成一个实体的引用
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
}
主要功能:mapper代理类生产工厂
FactoryBean 官方文档
/** 该类实现了 FactoryBean 这个接口干嘛的呢
* 请看 [官方文档]
*/
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
/** 最重要的是这个方法 生成接口的代理类
* {@inheritDoc}
*/
@Override
public T getObject() throws Exception {
/** getSqlSession获取的是父类生成的SqlSessionTemplate
*/
return getSqlSession().getMapper(this.mapperInterface);
}
}
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
/** sqlSession 的实例对象实际上是使用了SqlSessionTemplate */
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
}
最后一直往下跟 就会发现MapperProxy 这个类(没错 这就是我们最终的代理类了 spring 注入的就是这个玩意)
/** 实现了 InvocationHandler 的invoke方法*/
public class MapperProxy<T> implements InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
/** 执行的sql的构建 结果的处理 都是在这里完成的
(有兴趣的小伙伴可以继续往下跟) */
return mapperMethod.execute(sqlSession, args);
}
}