MyBatis相信很多人都会使用,但是当MyBatis整合到了Spring中,我们发现在Spring中使用更加方便了。例如获取Dao的实例,在Spring的我们只需要使用注入的方式就可以了使用Dao了,完全不需要调用SqlSession的getMapper方法去获取Dao的实例,更不需要我们去管理SqlSessionFactory,也不需要去创建SqlSession之类的了,对于插入操作也不需要我们commit。
既然那么方便,Spring到底为我们做了哪些工作呢,它如何将MyBatis整合到Spring中的呢,Spring在整合MyBatis时候做了哪些封装,以及做了哪些拓展,又是怎么实现这些封装以及拓展的,让我们来打开这一部分的源代码,一探究竟。
首先我们来先回顾下MyBatis的用法,以及Spring中MyBatis的使用方法。
po用于对于数据库中数据的映射,使得开发者更加专注于Java类的使用,而不是对数据库的操作
/** * @author: Fighter168 */ public class Person { private String id; private String name; //set get 方法、、、 }
mapper是数据库操作的映射文件,也就是我们常说的dao文件
/** * @author: Fighter168 */ public interface PersonDao { public Listquery(); public void save(Person p); public void delete(String id); }
配置文件主要用于程序中可变性高的设置,Mybatis的配置文件主要存在于configuration.xml中,当然configuration.xml中省略了其他mybatis的配置,例如settings里面的配置等等,如果没有玩过MyBatis的同学可以去参考网上MyBatis的教程自己去了解了解。
映射文件对应于Mybatis全局配置中的mappers配置属性,主要用于建立对应数据库操作接口的SQL映射。
insert into person(id,name) value(#{id,jdbcType=CHAR},#{name,jdbcType=CHAR}) delete from person where id=#{id,jdbcType=CHAR}
/** * @author: Fighter168 */ public class Test { public static void main(String[] args) throws Exception { Reader reader=Resources.getResourceAsReader("resource/configuration.xml"); SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader); SqlSession session=sessionFactory.openSession(); PersonDao personDao=session.getMapper(PersonDao.class); Person person=new Person("11","Fighter168"); personDao.save(person); //这里一定要提交,不然数据无法插入 session.commit(); session.close(); } }
insert into person(id,name) value(#{id,jdbcType=CHAR},#{name,jdbcType=CHAR}) delete from person where id=#{id,jdbcType=CHAR}
/** * @author: Fighter168 */ public class SpringTest { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("resource/ApplicationContext.xml"); PersonDao personDao=(PersonDao) context.getBean("personDao"); Person person=new Person("12","Fighter168"); personDao.save(person); } }
/** * {@inheritDoc} */ public void afterPropertiesSet() throws Exception { notNull(dataSource, "Property 'dataSource' is required"); notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); this.sqlSessionFactory = buildSqlSessionFactory(); }
/** * {@inheritDoc} */ public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; }所以我们在给dao注入sqlSessionFactory的时候,依赖填写SqlSessionFactoryBean 的实例就可以了。
SqlSession session=sessionFactory.openSession(); PersonDao personDao=session.getMapper(PersonDao.class);但在我们在spring的测试用例中使用mybatis的时候是这样使用的:
PersonDao personDao=(PersonDao) context.getBean("personDao");为什么spring可以这样做呢,答案就在MapperFactoryBean这里
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); } }
/** * {@inheritDoc} */ @Override protected void checkDaoConfig() { super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); 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(); } } }
/** * {@inheritDoc} */ public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }
/** * {@inheritDoc} * * @since 1.0.2 */ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { if (this.processPropertyPlaceHolders) { 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(); scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }