mybatis-spring启动到使用

栏目: 数据库 · 发布时间: 5年前

内容简介:看到阿里这道面试题的时候,我就知道是时候看下mybatis源码了首先,Mybatis在初始化SqlSessionFactoryBean的时候,找到mapperLocations路径去解析里面所有的XML文件Mybatis会把每个SQL标签封装成SqlSource对象。然后根据SQL语句的不同,又分为动态SQL和静态SQL。其中,静态SQL包含一段String类型的sql语句;而动态SQL则是由一个个SqlNode组成。

看到阿里这道面试题的时候,我就知道是时候看下mybatis源码了

Mybatis的启动

重要配置

<!-- 会话工厂bean sqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="datasource"></property>
        <!-- 别名 -->
        <property name="typeAliasesPackage" value="com.jesse.bookstore.entities"></property>
        <!-- sql映射文件路径 -->
        <property name="mapperLocations" value="classpath*:com/zhangguo/bookstore/mapper/*Mapper.xml"></property>
    </bean>
    
    <!-- 自动扫描对象关系映射 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!-- 指定要自动扫描接口的基础包,实现接口 -->
        <property name="basePackage" value="com.jesse.bookstore.mapper"></property>
    </bean>
复制代码

解析XML

首先,Mybatis在初始化SqlSessionFactoryBean的时候,找到mapperLocations路径去解析里面所有的XML文件

1. 根据mapper中的每句 SQL 生成对应的SqlSource

Mybatis会把每个SQL标签封装成SqlSource对象。然后根据SQL语句的不同,又分为动态SQL和静态SQL。其中,静态SQL包含一段String类型的sql语句;而动态SQL则是由一个个SqlNode组成。

mybatis-spring启动到使用

** 如下面demo 就生成dynamicSqlSource**

mybatis-spring启动到使用

生成的sqlsource

mybatis-spring启动到使用

2. 创建MappedStatementXML文件中的每一个SQL标签就对应一个MappedStatement对象,这里面有两个属性很重要。

mybatis-spring启动到使用

3. 缓存到Configuration所有xml解析完后,configuration对象具有所有sql信息

mybatis-spring启动到使用

configuration是mybatis非常重要的一个属性

Dao与xml如何生效

讲原理之前我们得知道mybatis是怎么用的

public interface UserMapper {	
	List<User> getUserList();
}

@Service
public class UserServiceImpl implements UserService{
	@Autowired
	UserMapper userDao;
	@Override
	public List<User> getUserList() {
		return userDao.getUserList();
	}
}
复制代码

userDao没有任何实现,为什么可以执行呢?

扫描

首先配置扫描器

mybatis-spring启动到使用

配置了扫描器 又是怎么生效的呢

查看源码注意到 有这么一个类

mybatis-spring启动到使用
它实现了BeanDefinitionRegistryPostProcessor。

在spring中,它可以 动态的注册Bean信息,方法 postProcessBeanDefinitionRegistry()

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	//创建ClassPath扫描器,设置属性,然后调用扫描方法
	ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
	scanner.setAnnotationClass(this.annotationClass);
	scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
	//如果配置了annotationClass,就将其添加到includeFilters
	scanner.registerFilters();
	scanner.scan(this.basePackage);
}

复制代码

复制代码ClassPathMapperScanner继承自Spring中的类ClassPathBeanDefinitionScanner,所以scan方法会调用到父类的scan方法,而在父类的scan方法中又调用到子类的doScan方法。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
	public Set<BeanDefinitionHolder> doScan(String... basePackages) {
		//调用Spring的scan方法。就是将基本包下的类注册为BeanDefinition
		Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
		processBeanDefinitions(beanDefinitions);
		return beanDefinitions;
	}
}
复制代码

super.doScan(basePackages)是Spring中的方法。我主要看它返回的是BeanDefinition的集合。 3、配置BeanDefinition 上面已经扫描到了所有的Mapper接口,并将其注册为BeanDefinition对象。接下来调用processBeanDefinitions()要配置这些BeanDefinition对象。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

	private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean<Object>();
	
	private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
		GenericBeanDefinition definition;
		for (BeanDefinitionHolder holder : beanDefinitions) {
			definition = (GenericBeanDefinition) holder.getBeanDefinition();
			
			//将mapper接口的名称添加到构造参数
			definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
			//设置BeanDefinition的class
			definition.setBeanClass(this.mapperFactoryBean.getClass());
			//添加属性addToConfig
			definition.getPropertyValues().add("addToConfig", this.addToConfig);
			//添加属性sqlSessionFactory
			definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
			......
	}
}
复制代码

复制代码处理的过程很简单,就是往BeanDefinition对象中设置了一些属性。我们重点关注两个。

设置beanClass

设置BeanDefinition对象的BeanClass为MapperFactoryBean<?>。这意味着什么呢?以UserMapper为例,意味着当前的mapper接口在Spring容器中,beanName是userMapper,beanClass是MapperFactoryBean.class。那么在IOC初始化的时候,实例化的对象就是MapperFactoryBean对象。

设置sqlSessionFactory属性

为BeanDefinition对象添加属性sqlSessionFactory,这就意味着,在为BeanDefinition对象设置PropertyValue的时候,会调用到setSqlSessionFactory()。

创建SqlSession的代理

查看MapperFactoryBean

mybatis-spring启动到使用
mybatis-spring启动到使用

上面步骤了解到 我们之前在BeanDefinition对象添加属性sqlSessionFactory,也意味着setSqlSessionFactory()会被执行 进到里面可以看到sqlSession实际上就是SqlSessionTemplate

mybatis-spring启动到使用

最终是给sqlSessionProxy实例化了一个jdk代理对象 在setSqlSessionFactory这个方法里,sqlSession获取到的是SqlSessionTemplate实例。而在SqlSessionTemplate对象中,主要包含sqlSessionFactory和sqlSessionProxy,而sqlSessionProxy实际上是SqlSession接口的代理对象。

创建Mapper接口的代理

现在每一个mapper都是一个MapperFactoryBean MapperFactoryBean是一个工厂Bean

注入mapper

现在我们通过spring注入一个Mapper @Autowired UserMapper userMapper 装配时会执行以下代码

mybatis-spring启动到使用
mybatis-spring启动到使用

有个问题是knownMappers是从哪儿来的呢?它为什么可以根据type接口就能获取到MapperProxyFactory实例呢? 查看DaoSupport发现它实现了InitializingBean 所以会在类初始化时 调用afterPropertiesSet,最终会调用到addMapper的方法

mybatis-spring启动到使用
mybatis-spring启动到使用

getMapper 执行到new Instance()

mybatis-spring启动到使用
也就是说 最终getObject获取到的是一个MapperProxy 此时注入的就是一个MapperProxy

执行mapper的方法

当执行userMapper.XXX()时,会进入

mybatis-spring启动到使用

重要的方法下面的mapperMethod.execute(sqlSession, args)

mybatis-spring启动到使用

这个方法比较简单,就是根据节点的类型,进行相应的处理。比如节点是insert 那就走到insert的逻辑

如果节点类型是select,方法返回值是list,所以代码执行了这个方法

mybatis-spring启动到使用

重点方法在 sqlSession.selectList(command.getName(), param, rowBounds);

上面讲到sqlSession是sqlSessionTemplate 进入方法

mybatis-spring启动到使用
sqlSessionProxy也是个代理对象

,总之它实际会调用到SqlSessionInterceptor.invoke()。

mybatis-spring启动到使用

重点代码几乎已经走完 下面是走到底执行底层jdbc


以上所述就是小编给大家介绍的《mybatis-spring启动到使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人人都是产品经理

人人都是产品经理

苏杰 / 电子工业出版社 / 2012-6 / 45.00元

本书为《人人都是产品经理》的升级版,是写给“1到3岁的产品经理”的书,适合刚入门的产品经理、产品规划师、需求分析师,以及对做产品感兴趣的学生,用户体验、市场运营、技术部门的朋友们,特别是互联网、软件行业。作为一名“4岁的产品经理”,作者讲述了过去3年的经历与体会,与前辈们的书不同,本书就像你走到作者身边,说“嗨,哥们!晚上有空吃个饭吗,随便聊聊做产品的事吧”,然后作者说“好啊”。 书名叫“......一起来看看 《人人都是产品经理》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具