从源码的角度来解读spring整合mybatis | 您所在的位置:网站首页 › spring整合mybatis源码解析 › 从源码的角度来解读spring整合mybatis |
目录
1、前言2、mybatis2.1 mybatis使用流程2.2 mybatis三个组件2.3 SqlSession2.4 Mapper接口式编程
3、spring整合mybatis3.1 SqlSessionFactoryBean3.3 SqlsessionTemplate3.3 MapperFactoryBean3.4 配置mapperScan
4、mybatis与spring流程小结
1、前言
spring整合mybatis几乎是每个Java开发学习过程中都会接触到的,相信很多人开始学习的时候都和博主一样,跟着视频或者博客把一大堆配置复制粘贴下来,然后运行发现没问题,于是就觉得自己掌握了。 但实际上真要细究spring和mybatis之间的关系时,大多数人都说不出来个所以然。 今天我们就从源码的角度来了解一下,从mybatis到mybatis-spring。 2、mybatis作为一个半ORM框架,mybatis的流行度已经远超hibernate,毕竟hibernate的HQL学起来真是太伤神了。我们先从一个简单的例子来使用一下mybatis: mybatis-config.xml main: public static void main(String[] args) throws IOException { InputStream fileInputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(fileInputStream); SqlSession sqlSession = factory.openSession(true); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectByid(1); System.out.println(user); sqlSession.close(); }service,mapper什么的这里就不贴了,小白请自行去看入门博客~ 2.1 mybatis使用流程从上面的xml配置文件到主方法使用mapper调用查询方法,我们主要做了以下几件事: 配置DataSource,也就是我们要连接的数据库配置mapper位置,因为mybatis需要将mapper.xml与class联系起来读取主配置文件mybatis-config.xml通过SqlSessionFactoryBuilder构建SqlSessionFactory通过SqlSessionFactory打开一个SqlSession通过SqlSession获取Mapper实例得到mapper实例对象之后,我们就可以进行相关操作了。 2.2 mybatis三个组件从上述流程我们可以发现,使用mybatis涉及到了三个组件: SqlSessionFactoryBuilder: 用于构建会话工厂,基于config.xml构建会话工厂,构建完成后即可丢弃。 SqlSessionFactory: 用于生成会话的工厂,作用于整个应用运行期间,一般不需要构造多个工厂对象 SqlSession: 作用于单次会话,如WEB一次请求期间,不能用作于某个对象属性,也不能在多个线程间共享,因为它是线程不安全的。 2.3 SqlSession这里单独把SqlSession列出来,是因为这个接口实在是太重要了。它为我们提供了大量操作数据库的接口。 而在Mybatis中,SqlSession的实现类是DefaultSqlSession 在实际应用中,我们可以通过openSession方法拿到session之后,像JDBC那样去操作数据库: 但是这也太笨重了,如果Mybatis就这的话,还不如使用JDBC。 2.4 Mapper接口式编程Mybatis通过Mapper接口式编程的方式,巧妙的让SqlSession实现类消失了,取而代之的是通过mapper.xml与mapper接口通过反射建立映射生成代理类的方法,用面向对象的方法来编程。 在DefaultSqlSession中,通过getMapper方法,我们可以得到Mapper的代理类实例: public T getMapper(Class type, SqlSession sqlSession) { final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } 3、spring整合mybatis我们都知道spring可以抽象为IOC容器,先不说具体流程,我们来思考一下,刚才mybatis的流程中,有哪些是可以交给spring管理的: 数据源DataSourceSqlSessionFactorySqlSessionTemplateMapper我们通过引入org.mybatis.mybatis-spring包和spring之后,重新来配置一次简单的实例: spring.xml: main: public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserMapper userMapper = context.getBean(UserMapper.class); System.out.println(userMapper.selectByid(1)); }可以看到,spring整合mybatis之后的代码变得清爽了很多。 但是这中间出现了一个我们在之前没见过的东西:SqlSessionTemplate,同时更加令人困惑的是,不仅在配置中没有看到它,就连使用时也没有它,那么它到底是干嘛的呢? 在了解它之前,我们先介绍一下其它的组件。 3.1 SqlSessionFactoryBean在MyBatis中要构建SqlsessionFactory对象,让它来产生 Sqlsession。在Mybatis-Spring中也不例外。 在一开始的数据源配置肯定是必不可少的,DriverManagerDataSource是spring自带的数据源,当然我们也可以选择配置Druid数据源。 而我们之前的SqlSessionFactory也被SqlSessionFactoryBean所替换,这也很好理解,spring把mybatis的SqlSessionFactory作为一个bean加入到了容器中。 3.3 SqlsessionTemplateSqlsessionTemplate( org.mybatis.spring.SqlsessionTemplate)是一个模板类,它是SqlSession的一个实现类,通过Sqlsession来完成工作。 在Mybatis中,对应的就是DefaultSqlSession。而在MyBatis-Spring中,实现类就是我们的SqlsessionTemplate。 它为我们提供了大量方法以及对SqlSession生命周期的操作,我们可以通过添加如下配置来使用它: public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); SqlSessionTemplate sqlSessionTemplate = context.getBean(SqlSessionTemplate.class); sqlSessionTemplate.selectList("……"); }这个使用过程和DefaultSqlSession的使用没有什么差别?直接使用SqlsessionTemplate显得极为笨重,我们一般不会在代码中使用。 但是我们仍然需要操作SqlSession,在Mybatis中通过DefaultSqlSession的getMapper方法完成了对代理类的实例化,但是Spring明显不会每次还要显示调用getMapper方法。于是添加了MapperFactoryBean组件。 3.3 MapperFactoryBean熟悉Spring的同学就应该能了解FactoryBean和BeanFactory的区别,这里简要提一下: 一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂。 如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。 从宏观来看,MapperFactoryBean接口的逻辑就是为我们完成了从mapper的接口类到mapper的代理类创建,然后加入到Spring容器中。 3.4 配置mapperScan假如我们需要第二个mapper时,我们就需要在xml中添加如下配置: 这从使用者的角度来说,简直就是噩梦。还好在mybatis.xml配置mapper时,就已经有包扫描的配置,我们只需要简单的进行如下配置即可: 那么接下来,我先要问你几个问题: 假如指定的包中,存在大量接口类,mybatis会把它们全部扫描进去并创建代理类吗?假如我创建了一个TestMapper接口,但是没有写对应的xml,会报错吗?如果会报错,是在什么时候报错呢?这两个问题大家可以自行实践去查证,答案将在结尾给出。 4、mybatis与spring流程小结我们再来做一次小结,对比一下mybatis与spring的差异: mybatismybatis-springSqlSessionFactory通过SqlSessionFactoryBuilder读取配置文件构建通过SqlSessionFactoryBean的getObject方法获取SqlSession实现类DefaultSqlSessionSqlSessionTemplateMapper实例DefaultSqlSession.getMapper方法通过MapperFactoryBean的getObject方法返回实例,实际上是调用SqlSessionTemplate.getMapper方法其它宏观或者微观细节大致上没有差异,比如xml解析流程,比如映射器和核心类Configuration,这些我虽然没有去求证过,但是想来不会有多少出入。 不过有需要注意的点是,在Spring中,Mapper是单例对象,但是Mapper与SqlSession是绑定在一起的,那这样一来,岂不是SqlSession也是单例的?为什么我们在实际使用过程中,不会出现线程安全问题呢?关于这个问题,博主会另写一篇博客介绍~ 最后回答一下之前的两个问题: 会扫描进去并创建代理类,从而产生大量的无用代理对象,因此我们可以通过配置MapperSacnnerConfigurer来优化启动过程并不会报错,但是使用时会报错,有兴趣的读者可以去了解一下XML解析以及代理方法调用流程 |
CopyRight 2018-2019 实验室设备网 版权所有 |