Mybatis最重要的两个配置文件
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <mappers> <package name="com.heoller.dao" /> </mappers> ... </configuration>
MapperXML.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.heoller.dao.EmployeeDao"> ... </mapper>
最简单的示例程序
// 1.获取配置文件输入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 2.解析配置文件并返回SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 3.获取接口的动态代理对象 EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class); // 执行SQL查询 employeeDao.queryById(1);
从示例程序可以看出,要想执行SQL查询,需要先有SqlSessionFactory对象,然后通过SqlSessionFactory获取到sqlSession,最后获得接口的动态代理对象。
按照这个思路再来看Spring集成Mybatis时所做的工作就很清晰了。
Spring集成Mybatis
最重要的两个Bean
org.mybatis.spring.SqlSessionFactoryBean
- 所属依赖包
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.0.2</version> </dependency>
- spring-beans.xml配置
<context:property-placeholder location="classpath:db.properties" /> <!-- 配置数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClass}" /> <property name="url" value="${jdbc.jdbcUrl}" /> <property name="username" value="${jdbc.user}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置Mybatis SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 指定数据源 --> <property name="dataSource" ref="dataSource" /> <!-- 指定Mapper配置文件位置 --> <property name="mapperLocations" value="classpath:mapper/*.xml" /> <!-- 指定Mybatis全局配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml" /> </bean>
SqlSessionFactoryBean
类实现了InitializingBean接口,Spring在getBean过程中,实例化完对象之后执行AbstractAutowireCapableBeanFactory#invokeInitMethods,对于实现了InitializingBean接口的实例,会执行实例的afterPropertiesSet方法。
/** * {@inheritDoc} */ public void afterPropertiesSet() throws Exception { ... // buildSqlSessionFactory方法解析了mybatis的配置文件,并实例化了SqlSessionFactory this.sqlSessionFactory = buildSqlSessionFactory(); }
org.mybatis.spring.mapper.MapperScannerConfigurer
- spring-beans.xml配置
<!-- 扫描Mybatis的Mapper接口并将动态代理对象放入Spring容器中 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.heoller.dao" /> </bean>
- 作用
MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,是个Bean工厂的后置处理器。Spring在getBean之前会执行Bean工厂的后置处理器的postProcessBeanDefinitionRegistry方法(AbstractApplicationContext#invokeBeanFactoryPostProcessors)。/** * {@inheritDoc} */ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { Scanner scanner = new Scanner(beanDefinitionRegistry); scanner.setResourceLoader(this.applicationContext); // 扫描Mapper接口 scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } // 内部Scanner类 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); ...(省略分支代码) for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); ... // 加入MapperFactoryBean类的bean定义 definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName()); definition.setBeanClass(MapperFactoryBean.class); ... } } return beanDefinitions; }
每个Mapper接口都会对应一个MapperFactoryBean类的bean定义,所以在每次注入Mapper接口时都会获得MapperProxy对象(单例),有了Mapper动态代理对象,我们就能执行Sql操作啦。public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); } } // DefaultSqlSession.class public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }