图1
<mapper resource="org/mybatis/example/BlogMapper.xml">
mybatis解析mapper有几种形式。有四种。第一种<mapper resource> 第二种<mapper url=> ,第三种<mapper package> ,第四种<class>
图2
读取配置mybtis-config.xml的配置文件。构建sqlSessionFactory, 建了SqlSession, 添加userMapper。
图3
图4
图5
图6
图7
图8
图9
getMapper(). 产生一个代理类返回。 单个mybatis 的源码过程。因为没有和spring整合,单纯分析的意义不大,不作为重点解析。
图9-0
图9-1
mybatis +spring时的mybatis源码解析。
1个问题mybatis在spring环境的情况下缓存失效问题。
2.问题mybatis 一级缓存底层原理。
1一级缓存的失效原理。
图1
图1-0
图2
运行结果打印两条sql语句,证明缓存失效。 userMapper是一个接口图1-0 userMapper通过一个代理类来实现的。
图3
图4
图4-0
图4-1
图5
MapperFactoryBean是spring 为每个接口文件产生的代理了类, getObject()获取每个接口的代理对象。
图7
图8
图9
图10
图11
此时的mapperInterface=com.luban.mapper.UserMapper , 为userMapper产生代理对象,mapperProxy为invokerHandle .
图12
mapperMethod相当于bd。有方法的相关信息。图13 通过这个mapperMethod可以拿到缓存的级别,sql等等信息。 seqSession ='SqlSessionTemplate' 如果是 单独mybatis时,seqSession='DefaultSqlSession' 具体的对象,图图16-1
图12-1
如果是sqlSession= sqlSessionTEmplate时,他不是自己去执行,而是那到sqlSessionProxy的代理类去执行。图16
图12-0
sqlSession 的三个实现类DefaultSqlSession(单独的mybatis使用),SqlsessionManager,SqlSessionTemplate(在spring环境下使用)
图12-1
SqlSessionTemplate实例化。
图12-2
图12-3
图12-4
在在创建userMapper的时候,实际new MapperFactoryBean ,如图12-4 mbd 的beanClass 为MapperFactoryBean。
图12-5
mapperInterface 需要自动装配吗?不需要。自动装配会忽略Class类型。String类型等等
图12-6
图12-7
图12-8
图12-9
图12-10
图12-11
图12-12
图12-13
图12-14
图12-15
图13
图14
来判断查询的是多条,还是map类型,
图15
判断是不是有列,如果是spring环境下的,此时的sqlSession为SqlSessionTemplate 。如果单独的mybatis下的是DefaultSqlSession 图16 ,图16-1,图16-2
图16
代理对象 seqSessionProxy
图16-1
图16-2
图17-0
图17
这个sqlSession 是DefaultSqlSession 。这个method是selectList 被代理的方法,
总结:
在spring环境下 , SqlSessionTemplate 通过调用seqSessionProxy属性的 selectList对象,执行invoke方法实现来代理DefaultSqlSession的对象的selectList()方法,达到对改方法的增强目的,增强就是把session关闭了。因为执行完这个查询置后关闭了DefalutSeqlSession对象,所以一级缓存失效了。
而单独的mybatis中 直接通过DefaultSqlSession 对象的,selectList()方法执行了。该对象。
图18两种情况的比较。
454行关闭sqlsession.
图18
因为我们在整合mybatis和spring的时候,mybatis提供一个插件包叫mybatis-spring,在这个插件包中提供SqlSessionTemplate类 替代了mybatis默认的DefaultSqlSession类,代理了DefaultSqlSession 的方法对象,对DdfaultSqlSession对象的方法进行了增强,增强的过程中把session关闭了。
问题来了,为什么要关闭session呢? 因为spring 他没有办法关,不在这里关就没有地方关,也就是没有暴露相关的api让我们关,而单独的mybatis可以随意关,他有相应的api
图19
图20
图21
mapper在实例化对象的时候就已经把sql等信息,放在map中了。
图21-0
图21-1
图22
图23
图24
MapperFactoryBean extends SqlSessionDaoSupport extends DaoSupport 。MapperFactoryBean 在实例化后调用 DaoSupport的afterPropertiesSet() 。DaoSupport的afterPropertiesSet() 方法里调用this.checkDaoConfig(),但是在DaoSupport类这个方法是抽象方法古调用子类;SqlSessionDaoSupport 实现了 checkDaoConfig()方法。MapperFactoryBean也实现了checkDaoConfig方法();最终调用了MapperFactoryBean也实现了checkDaoConfig方法;在这个方法usermapper类传进去注解,sql等信息解析。
图25
图26
图27
注册userMapper类。
图28
解析userMapper类的注解。
总结: 问在spring环境中mybatis是怎么初始化的? 他是利用了spring中InitializingBean类 的afterPropertiesSet() 。因为他最终实现了InitializingBean的类,从写了afterPropertiesSet()方法。afterPropertiesSet()方法中完成了mybatis的初始化 图29详细过程。
为什么要这样做呢?
图29
图30-0
执行所有的初始化BeanPostProcessors.执行完后才执行 初始化方法 为什么啊,因为invokeInitMethods 主要执行的afterPropertiesSet()意思是所有类的属性全部se完后执行。因为这些属性对象有可能依赖其他对象。等所有的对象都依赖完成之后才能解析这些,sql,和注解信息。举例图
图30-1
当spring初始化完成以后要执行初始化方法。
图31
同过比较确实init要早于afterPropertiesSet()方法执行。
整个流程图32
图32
图33
自动装配的几种类型,AUTOWIRE_NO ,AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE。默认为AUTOWIRE_NO 。默认AUTOWIRE_NO不自动装配,只有你在属性上加了 @Autowire 或者@ Resource 注解是才会自动装配 图34。如果使用AUTOWIRE_BY_TYPE是根据属性的set方法的,即便是不加@Autowire 或者@ Resource ,加了set方法也可以完成装配 图35。
图34
这个是加了注解的
图35
AUTOWIRE_BY_TYPE 的情况下,只要属性有set方法就可以实现自动装配 ,有没有属性也没有关系。
那mybatis默认使用的是什么呢,图4-1.使用的是AUTOWIRE_BY_TYPE。为什么这么麻烦那为什么不能 直接使用注解来代替这种MapperScannerRegistrar 这种方式。这样为了解耦,为了更少的依赖spring。
图36
MapperFacoryBean需要装配的属性只有一个是addToCofig属性。
图37
父类有一个setSqlSessionFactory 需要自动装配。 问题来了,那这个sqlSessionFactory什么时候示例话的,在图38进行的示例话。
现在分析一下究竟什么样的属性要被by_type自动装配呢,
图37-1
通过图37-1我们可以目前需要自动装配的有四个属性,一个 setSqlSessionTemlate, setSessionFatory,setAddToConfig,setMapperInterface。 MapperInterface是Class类型过滤调不自动装配,我们看下代码。
图37-2
图37-2通过堆栈信息我们看到首先通过getBean获取到Service,spring 发现他的依赖类 userMapper 然后通过getBean获取UserMapper类。自动装配他的属性填充属性。最终结果是注入了这两个。setSessionFatory,setAddToConfig 从什么地方开始注入的呢,又是从什么地方开始过滤呢,
图37-3
图37-3 开始注入,但是为什么开始注入的时候就有一个addToConfig的属性呢,图37-4添加的;通过观察 经过1170行,pvs由1个变为2个.说明在这个autowireByType中进行的处理。图37-5
图37-4
图37-5
图37-5 到propertyNames字符串是我们发现有两个值了 sqlSessionFactory,sqlSessionTemplate。为什么没有Class类型的
图37-6
addToConfig
class Object类的。
maperInterface
getObect();
getObjetType();
sqlSession
剩下的两个就是返回的那两个 sqlSessionFactory,sqlSessionTemplate
图37-6 这个方法的就是判断哪些类需要自动装配。pvs 目前只有一个是addToConfig 通过外部设置给spring的。pds 属性描述器,一共有9个。那什么为readMethod ,什么是WriterMethod呢, 有get方法的属性成为read,有set方法的属性称为 writerMethod,pds通过判断有没有set方法过滤调除sqlSessionFactory,sqlSessionTemplate,addToConfig,maperInterface 四个类,又通过!pvs .contains(pd.getName())过滤调addToConfig。通过isSimpleValueType()方法过滤调maperInterface 最后只剩下sqlSessionFactory,sqlSessionTemplate 需要自动装配。
图37-7
这个构造器注入的是一个字符串类型,但是spring需要的是一个Class类型。这中间是怎么转化的呢,
图37-8
图37-8
图38
图39
总体流程:userMapper 在示例化之前,通过@MapScan 利用ImportBeanDefinitionRegistar类把UserMaper变成MapperFactoryBean;在示例化工程mybatis会产生两个代理对象,一个是Mapper的代理对象,往mapper对象注入一个SqlSessionTemplate 。有了SqlSessionTemplate就可以执行代理了,代理就把session关了。