mybatis没有与Spring整合前是这样使用的
@Test
public void test03(){
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//1.获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession
SqlSession session = sqlSessionFactory.openSession();
//3.获取mapper
TblEmployeeMapper mapper = session.getMapper(TblEmployeeMapper.class);
TblEmployeePO tblEmployeePO=new TblEmployeePO();
tblEmployeePO.setId(null);
tblEmployeePO.setLastName("王五");
tblEmployeePO.setGender("1");
tblEmployeePO.setEmail("a");
//4.调用增删改查方法
mapper.insert(tblEmployeePO);
session.commit();
session.close();}1234567891011121314151617181920可以看到要执行增删改查之前必须获得,sqlSessionFactory,SqlSession 和对应的mapper。
Spring整合mybatis
整合部分的代码:
可以看到通过标签往容器中注入的是sqlSessionFactoryBean,注入的并不是sqlSessionFactory,或者SqlSession,看看这个sqlSessionFactoryBean是什么。
SqlSessionFactoryBean
class SqlSessionFactoryBean implements FactoryBean
可以看到它实现了FactoryBean
1.实现FactoryBean有什么用?
FactoryBean接口:实现了该接口的类,在调getBean的时候会返回该工厂返回的实例对象,也就是再调一次getObject方法返回工厂的实例。也就是说SqlSessionFactoryBean 的getObject方法能返回SqlSessionFactory的实例对象。
2.实现InitializingBean有什么用?
InitializingBean接口:实现了这个接口,那么当bean初始化的时候,spring就会调用该接口的实现类的afterPropertiesSet方法,去实现当spring初始化该Bean 的时候所需要的逻辑。
SqlSessionFactoryBean的初始化
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
//创建一个sqlSessionFactory,注意这个sqlSessionFactory在这里并没有被注入到springIOC容器中
this.sqlSessionFactory = this.buildSqlSessionFactory();}1234567从中我们可以看到,sqlSessionFactory的实例化便在这个方法里面实例化,buildSqlSessionFactory()方法会对我们的sqlSessionFactory做定制的初始化,初始化sqlSessionFactory有两种方式,一种是我们直接通过property直接注入到该实例中,另一种是通过解析xml的方式,就是我们在全局配置文件里面的配置,根据这些配置做了相应的初始化操作,里面也是一些标签的解析属性的获取,操作,和Spring的默认标签解析有点类似,这里就不再重复说明。
获取SqlSessionFactoryBean实例
因为SqlSessionFactoryBean实现了FactoryBean接口,所以当我们通过getBean获取它的实例的时候实际是调用他的getObject方法,获取到的是sqlSessionFactory。
//返回一个sqlSessionFactory对象,这个对象会添加到容器中,这里才把sqlSessionFactory给添加到容器中
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}1234567MapperFactoryBean
在使用mybatis的时候,我们获取dao的方式一般是这样
SqlSession openSession = sqlSessionFactory.openSession();DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);12
但在我们在spring的测试用例中使用mybatis的时候是这样使用的:
TblEmployeeMapper bean = ioc.getBean(TblEmployeeMapper.class);1
也就是说xxxMapper已经是在ioc容器中的了。
MapperFactoryBean:根据指定的Mapper接口生成Bean实例
public class MapperFactoryBean
获取MapperFactoryBean实例
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);}123看到这里,我们会恍然大悟,原来在这里封装了getMapper操作,返回接口的实例,怪不得在Spring中使用MyBatis我们不用管理sqlSession了。
问题1:那么sqlSession是获取的呢?
SqlSessionDaoSupport是MapperFactoryBean父类
SqlSessionDaoSupport类看到:
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;}发现其实获取到的SqlSession是sqlSessionTemplate类型的
SqlSessionDaoSupport类看到:
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
}}证实了
protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);}123456789101112131415问题2:之前SqlSessionFactoryBean被注入到了容器中,MapperFactoryBean是如何获取到SqlSessionFactory ,然后利用SqlSessionFactory 创建sqlSession的呢?
1.mapperInterface:用于指定接口2.sqlSessionFactory:从容器中获取sqlSessionFactory并赋值到属性sqlSessionFactory中3.sqlSessionTemplate:用于指定SqlSessionTemplate。如果和sqlSessionFactory同时配置,则只会启用sqlSessionTemplate。1234567
这里通过,把sqlSessionFactory给注入到了MapperFactoryBean中,然后MapperFactoryBean就能利用sqlSessionFactory创建SqlSession了。
MapperFactoryBean初始化
MapperFactoryBean继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承DaoSupport,DaoSupport实现了InitializingBean接口,让我们开看看它这接口的实现:
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
// Let abstract subclasses check their configuration.
checkDaoConfig();
// Let concrete implementations initialize themselves.
try {
initDao();
}
catch (Exception ex) {
throw new BeanInitializationException("Initialization of DAO failed", ex);
}}123456789101112该方法主要包含两个功能,一个是调用checkDaoConfig()方法,一个是调用initDao方法。checkDaoConfig方法在DaoSupport是抽象方法,让我看看它在MapperFactoryBean的实现:
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Throwable t) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
throw new IllegalArgumentException(t);
} finally {
ErrorContext.instance().reset();
}
}}12345678910111213141516该方法主要是检查dao的配置,主要是检验sqlSessionFactory和mapperInterface属性不能为空,以及检测接口对于的映射文件是否存在,如果存在,那么就把它添加到configuration里面去,注册mapper。这个configuration是SqlSessionFactory实现类DefaultSqlSessionFactory的属性。
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);}SqlSessionTemplate类:这里的configuration就是DefaultSqlSessionFactory中的
public注:我们一般不直接使用MapperFactoryBean,如果在配置文件中直接使用MapperFactoryBean(具体配置看问题2),那么项目中那么多的xxxMapper,不太现实,使用MapperScannerConfigurer可以解决这个问题。
MapperScannerConfigurer
如果我们的dao在一个包下面又好几十个,那么我可以可以通过扫描的方式添加dao,像下面一样使用
123456789101112
看到上面的配置,我们会很好奇,在spring这样添加就可以扫描的方式添加dao配置,怎么做到的?让我打开类实现,具体看一下
MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,如果MapperScannerConfigurer实现了该接口,那么说明在application初始化的时候该接口会被调用,具体实现,让我先看看:
/**
* {@inheritDoc}
*
* @since 1.0.2
*/
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (this.processPropertyPlaceHolders) {
//执行属性的处理,简单的说,就是把xml中${XXX}中的XXX替换成属性文件中的相应的值
processPropertyPlaceHolders();
}
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();//该方法主要做了以下操作://1)扫描basePackage下面的java文件//2)解析扫描到的java文件//3)调用各个在上一步骤注册的过滤器,执行相应的方法。//4)为解析后的java注册bean,注册方式采用编码的动态注册实现。//5)构造MapperFactoryBean的属性,mapperInterface,sqlSessionFactory等等,填充到BeanDefinition里面去。
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}12345678910111213141516171819202122232425262728293031做完这些,MapperFactoryBean对象也就构造完成了,扫描方式添加dao的工作也完成了。
附:
SqlSessionTemplate:
https://zhidao.baidu.com/question/2016521463125168748.html1
关于Mybatis与Spring整合之后SqlSession与mapper对象之间数量的问题。
https://www.cnblogs.com/ljdblog/p/7123430.html1
SqlSessionFactoryBean和MapperFactoryBean作用:
https://www.jianshu.com/p/3e39a3bf7ccb1
spring 整合 mybatis原理
https://blog.csdn.net/qq_43193797/article/details/850116831
Mybatis之工作原理
https://blog.csdn.net/u014297148/article/details/786960961
SqlSessionFactoryBean
-----为整合应用提供SqlSession对象资源,取得SqlSessionFactoryBean实例
123456
MapperFactoryBean
------根据指定的Mapper接口生成Bean实例
MapperFactoryBean创建的代理类实现了UserMapper接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而不是一个具体的实现类。
上面的配置有一个很大的缺点,就是系统有很多的配置文件时全部需要手动编写,太麻烦了。
1.mapperInterface:用于指定接口2.sqlSessionFactory:从容器中获取sqlSessionFactory并赋值到属性sqlSessionFactory中3.sqlSessionTemplate:用于指定SqlSessionTemplate。如果和sqlSessionFactory同时配置,则只会启用sqlSessionTemplate。1234567
MapperScannerConfigurer
它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它 们 创 建 成 MapperFactoryBean。
老式写法:
1234
新写法:新写法的注解形式@MapperScan("org.mybatis.spring.sample.mapper")
转自:https://blog.csdn.net/weixin_42412601/article/details/104600907

0条评论
点击登录参与评论