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; }1234567
MapperFactoryBean
在使用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条评论
点击登录参与评论