1,使用配置
1.1 引入mybatis整合spring的jar包
<!--mybatis 和Spring整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
1.2,在spring的applicationContext.xml中配置SqlSessionFactoryBean,它是用来帮助我们创建会话的。同时配置需要扫描Mapper接口的路径。
<!-- 在Spring启动时创建 sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.gupaoedu.crud.dao"/>
</bean>
2,创建会话工厂
我们在spring配置文件中配置了SqlSessionFactoryBean,我们来看下这个类。
它实现了InitializingBean接口,所以要实现afterPropertiesSet()方法,这个方法会在bean的属性值设置完的时候被调用。
又实现了FactoryBean接口,所以它初始化的时候,实际上是调用getObject()方法,它里面调用的也是afterPropertiesSet()方法。
在afterPropertiesSet()方法中,我们实际上执行的还是mybatis那一步来创建初始化configuration对象和解析mapper文件,把接口和对应的MapperProxyFactory注册到mapperRegistry中。
最后调用sqlSessionFactoryBuilder.build(targetConfiguration)返回一个DefaultSqlSessionFactory。
3,创建SqlSession
3.1,可以直接使用DefaultSqlSessionFactory创建吗?
不能,它是不安全的,Spring用SqlSessionTemplate对SqlSession进行了包装。在编程式的开发中,我们会在每次请求的时候创建一个SqlSession,但是Spring中只有一个SqlSessionTemplate。SqlSessionTemplate中有SqlSession中的所有方法,不过它都是通过一个代理类对象实现的,这个代理对象是在构造方法里面通过一个代理类创建的。
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
所有的方法都会先走到内部代理类SqlSessionInterceptor的invoke方法,
3.2,怎么拿到一个SqlSessionTemplate?
Dao继承Mybatis提供的SqlSessionDaoSupport,就可以获得。
为了减少代码量我们可以建立一个BaseDao继承SqlSessionDaoSupport拿到SqlSessionTemplate对象,然后定义一些基本的操作,其它的Dao都继承它。
3.3,有没有更好的方法拿到SqlSessionTemplate?
3.2的方式,需要我们的每一个Dao层的接口想拿到SqlSessionTemplate对象,都需要去继承BaseDao编写一个实现类,工作量并不小,另一个我们调用方法的时候其实还是会使用硬编码的方式,MapperProxy根本用不上。那怎么解决呢?我们使用接口的扫描注册。
4,接口的扫描注册
在Service层使用@Autowired自动注入Mapper接口,需要保存在BeanFactory中,也就是说接口肯定在Spring启动的时候就被扫描了,注册过的。
4.1,MapperScannerConfigurer是BeanFactoryPostProcessor的子类,可以通过编码的方式修改,新增或者删除某些Bean的定义。我们只需要重写postProcessBeanDefinitionRegistry()方法,在这里面操作Bean就行了。
5,接口注入使用
我们使用Mapper的时候,只需要在加了Service注解的类里面使用@Autowired注入Mapper接口就好了。
我们启动Spring去实例化EmployeeService的时候,发现它依赖了employeeMapper,这时候我们要根据它的名字去BeanFactory中获取它的BeanDefinition,再从BeanDefinition中获取他的BeanClass,上面已经知道这时候的BeanClass是MapperFactoryBean,因为它实现了FactoryBean接口,同样是调用getObject方法,
通过调用SqlSessionDaoSupport中的getSqlSession拿到SqlSessionTemplate。接着调用mapperRegistry的getMapper方法,然后通过MapperProxyFactory新建一个MappProxy代理对象,最后调用Mapper接口的方法,也是执行MapperProxy的invoke方法。
SqlSessionTemplate:Spring中SqlSession的替代品,线程安全的,通过代理的方式调用DefaultSqlSession的方法。
SqlSessionInterceptor(内部类):代理对象,用来代理DefaultSqlSession对象,在SqlSessionTemplate中使用。
SqlSessionDaoSupport:用于获取SqlSessionTemplate,只需要继承它就行,
MapperFactoryBean:注册到IOC容器中替换接口类,它继承了SqlSessionDaoSupport用于获取SqlSessionTemplate。
SqlSessionHolder:控制SqlSession和事务。
6,设计模式总结
工厂:SqlSessionFactory,MapperProxyFactory
建造者:XMLConfigBuilder
单例模式:SqlSessionFactory,Configuration
代理:
MapperProxy代理Mapper接口
Plugin 插件
模板:BaseExecutor与子类SimpleExecutor,BatchExecutor和ReuseExecutor
装饰器:CachingExecutor对其他Executor额装饰。
责任链:InterceptorChain