Spring集成Mybatis配置与源码分析
来源:互联网 发布:tensorflow get shape 编辑:程序博客网 时间:2024/06/05 20:21
1.配置
在spring配置文件中添加如下配置:
<!– SqlSessionFactory bean配置。
configuration与configLocation可以选择其中一个配置,若都配置了则使用configuration配置,若都不配置使用默认配置–>
<bean id=”sqlSessionFactory” class=”org.mybatis.spring.SqlSessionFactoryBean”>
<property name=”dataSource” ref=”dataSource”/>
<!–配置方式:setter注入–>
<property name=”configuration” ref=”configuration”/>
<!–配置方式:配置文件–>
<property name=”configLocation” value=”classpath:config/mybatis-config.xml”/>
<property name=”mapperLocations” value=”classpath:com/wxyh/study/dao/*/.xml”/>
<!–注入其他属性–>
</bean>
<!– spring与mybatis整合配置,扫描所有dao –>
<bean class=”org.mybatis.spring.mapper.MapperScannerConfigurer”>
<property name=”basePackage” value=”com.wxyh.study.dao.**.mapper”/>
<property name=”sqlSessionFactoryBeanName” value=”sqlSessionFactory”/>
</bean>
下面对主要源码进行分析讲解,源码版本mybatis-3.4.4,mybatis-spring-1.3.1。
2.SqlSessionFactoryBean源码分析
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { // 核心字段,这些属性都提供了setter注入方法 private Resource configLocation; private Configuration configuration; private Resource[] mapperLocations; private DataSource dataSource; private TransactionFactory transactionFactory; private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); private SqlSessionFactory sqlSessionFactory; private String environment = SqlSessionFactoryBean.class.getSimpleName(); private boolean failFast; private Interceptor[] plugins; private TypeHandler<?>[] typeHandlers; private String typeHandlersPackage; private Class<?>[] typeAliases; private String typeAliasesPackage; private Class<?> typeAliasesSuperType; private DatabaseIdProvider databaseIdProvider; private Class<? extends VFS> vfs; private Cache cache; private ObjectFactory objectFactory; private ObjectWrapperFactory objectWrapperFactory; @Override public void afterPropertiesSet() throws Exception { notNull(dataSource, "Property 'dataSource' is required"); notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null), "Property 'configuration' and 'configLocation' can not specified with together"); this.sqlSessionFactory = buildSqlSessionFactory(); } protected SqlSessionFactory buildSqlSessionFactory() throws IOException { Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; if (this.configuration != null) { // 注入了configuration bean,优先使用 configuration = this.configuration; if (configuration.getVariables() == null) { configuration.setVariables(this.configurationProperties); } else if (this.configurationProperties != null) { configuration.getVariables().putAll(this.configurationProperties); } } else if (this.configLocation != null) { // 有配置文件,后面会解析配置文件,把相关配置保存在configuration中 xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); configuration = xmlConfigBuilder.getConfiguration(); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration"); } // 没有配置configuration与configLocation,使用默认配置 configuration = new Configuration(); if (this.configurationProperties != null) { configuration.setVariables(this.configurationProperties); } } // 略去设置或解析setter注入属性代码 // ...... if (xmlConfigBuilder != null) { try { // 解析配置文件mybatis-config.xml,详细源码解析见:http://blog.csdn.net/u011424653/article/details/78202010 xmlConfigBuilder.parse(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'"); } } catch (Exception ex) { throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); } finally { ErrorContext.instance().reset(); } } if (this.transactionFactory == null) { this.transactionFactory = new SpringManagedTransactionFactory(); } configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource)); // 解析mapperLocations指定mapper配置文件 if (!isEmpty(this.mapperLocations)) { for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } try { // 逐个解析mapper配置文件,解析源码见:http://blog.csdn.net/u011424653/article/details/78202010#t3 XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'"); } } } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found"); } } // 构建sqlSessionFactory对象 return this.sqlSessionFactoryBuilder.build(configuration); } @Override public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; }}
SqlSessionFactoryBean是SqlSessionFactory的工厂bean。
启动项目时spring首先会创建SqlSessionFactoryBean对象,然后会把getObject()的返回值DefaultSqlSessionFactory对象作为bean注册到容器中。
3.MapperScannerConfigurer源码分析
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { // 核心字段,这些属性都提供了setter注入方法 private String basePackage; private boolean addToConfig = true; private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; private String sqlSessionFactoryBeanName; private String sqlSessionTemplateBeanName; // mapper接口使用的注解类型 private Class<? extends Annotation> annotationClass; // mapper接口的父接口类型 private Class<?> markerInterface; private ApplicationContext applicationContext; private String beanName; private boolean processPropertyPlaceHolders; private BeanNameGenerator nameGenerator; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); // 设置mapper接口使用的注解或父类型 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); // 配置过滤basePackage包中mapper接口的规则,源码分析见4 scanner.registerFilters(); // 扫描basePackage包中mapper接口,将其封装为MapperFactoryBean<T> scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } ......}
4.ClassPathMapperScanner源码分析
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner { // 核心字段,这些属性都提供了setter注入方法 private boolean addToConfig = true; private SqlSessionFactory sqlSessionFactory; private SqlSessionTemplate sqlSessionTemplate; private String sqlSessionTemplateBeanName; private String sqlSessionFactoryBeanName; private Class<? extends Annotation> annotationClass; private Class<?> markerInterface; private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean<Object>(); /** * 配置扫描器以注册basePackage包中正确的接口为mapper */ public void registerFilters() { boolean acceptAllInterfaces = true; // 把basePackage包中有annotationClass类型注解的所有接口注册为mapper if (this.annotationClass != null) { addIncludeFilter(new AnnotationTypeFilter(this.annotationClass)); acceptAllInterfaces = false; } // 把basePackage包中派生自markerInterface类型接口的所有接口注册为mapper, // 重写matchClassName方法,以免注册markerInterface接口为mapper if (this.markerInterface != null) { addIncludeFilter(new AssignableTypeFilter(this.markerInterface) { @Override protected boolean matchClassName(String className) { return false; } }); acceptAllInterfaces = false; } if (acceptAllInterfaces) { // 如果没有设置annotationClass和markerInterface,则注册basePackage包中所有类为mapper // default include filter that accepts all classes addIncludeFilter(new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return true; } }); } // exclude package-info.java addExcludeFilter(new TypeFilter() { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); return className.endsWith("package-info"); } }); } /** * Calls the parent search that will search and register all the candidates. * Then the registered objects are post processed to set them as * MapperFactoryBeans */ @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { // 调用父类方法,扫描basePackages包中的mapper接口,返回BeanDefinitionHolder集合 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { processBeanDefinitions(beanDefinitions); } return beanDefinitions; } /** * 定义mapper的工厂bean MapperFactoryBean */ private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) { logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface"); } // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean // 通过构造函数传参设置MapperFactoryBean所生产bean的类型 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59 definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); // 往MapperFactoryBean注入sqlSessionFactory boolean explicitFactoryUsed = false; if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionFactory != null) { definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true; } // 往MapperFactoryBean注入sqlSessionTemplate. // 如果已注入sqlSessionFactory则忽略该配置,使用sqlSessionTemplate,详见源码 if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { if (logger.isDebugEnabled()) { logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); } definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } } }}
5.MapperFactoryBean源码分析
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { // mapper bean的类型 private Class<T> mapperInterface; // true,添加mapper到MapperRegistry private boolean addToConfig = true; public MapperFactoryBean() { //intentionally empty } public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } @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 { // 添加mapper到MapperRegistry,源码分析见xxxxxxxxxxx configuration.addMapper(this.mapperInterface); } catch (Exception e) { logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e); throw new IllegalArgumentException(e); } finally { ErrorContext.instance().reset(); } } } @Override public T getObject() throws Exception { // getSqlSession()返回的是一个SqlSessionTemplate对象 // getMapper方法从MapperRegistry中获取的是MapperProxyFactory对象 return getSqlSession().getMapper(this.mapperInterface); }}public abstract class SqlSessionDaoSupport extends DaoSupport { // 通过sqlSessionFactory或sqlSessionTemplate,生成的sqlSession对象都是SqlSessionTemplate类型, // 实际上是SqlSession的代理对象 private SqlSession sqlSession; private boolean externalSqlSession; public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (!this.externalSqlSession) { // 如果设置了sqlSessionTemplate,则不再使用sqlSessionFactory了 this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); } } public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSession = sqlSessionTemplate; this.externalSqlSession = true; } /** * Users should use this method to get a SqlSession to call its statement methods * This is SqlSession is managed by spring. Users should not commit/rollback/close it * because it will be automatically done. * * @return Spring managed thread safe SqlSession */ public SqlSession getSqlSession() { return this.sqlSession; } @Override protected void checkDaoConfig() { notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); }}
6.SqlSessionTemplate源码分析
public class SqlSessionTemplate implements SqlSession, DisposableBean { private final SqlSessionFactory sqlSessionFactory; private final ExecutorType executorType; // SqlSession的代理对象 private final SqlSession sqlSessionProxy; private final PersistenceExceptionTranslator exceptionTranslator; public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); } public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator( sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true)); } public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; // 创建sqlSession的代理对象,调用sqlSession的所有方法,都被SqlSessionInterceptor的invoke方法拦截 this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); } /** * 内部类 * jdk动态代理拦截器类 */ private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SqlSession sqlSession = getSqlSession( SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); try { Object result = method.invoke(sqlSession, args); if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() sqlSession.commit(true); } return result; } catch (Throwable t) { Throwable unwrapped = unwrapThrowable(t); if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { // release the connection to avoid a deadlock if the translator is no loaded. See issue #22 closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); sqlSession = null; Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped); if (translated != null) { unwrapped = translated; } } throw unwrapped; } finally { if (sqlSession != null) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } }}
- Spring集成Mybatis配置与源码分析
- Mybatis,Spring集成与事务配置
- MyBatis与Spring集成
- MyBatis与Spring集成
- MyBatis与Spring集成
- Mybatis与Spring集成
- Mybatis-与Spring集成
- Spring与Mybatis集成
- MyBatis Spring 集成源码解析
- Mybatis与Spring集成源码研究之MapperScannerConfigurer
- Spring-Mybatis源码分析
- MyBatis集成spring相关配置
- spring-mybatis集成 xml配置
- 介绍MyBatis与Spring集成
- 深入浅出Mybatis-与Spring集成
- MyBatis与Spring集成示例
- 深入浅出Mybatis-与Spring集成
- 深入浅出Mybatis-与Spring集成
- Value,innerHtml,innerText的区别
- codeforces contest 343 problem D(线段树+dfs序)
- Unity Shader Example 27 (Noise)
- React、React Native面试题
- unity脚本模板
- Spring集成Mybatis配置与源码分析
- ◆程序笔记◆◇第四期◇扩展欧几里得算法
- 洛谷P1120 小木棍[数据加强版](回溯法)
- Ajax学习笔记
- hdu 6001 容斥 + dfs
- 网易2017秋招笔试题3:最长公共子括号序列长度
- 5. 机器学习基石-Why can Machine Learn?
- css继承属性
- Not found in archive 和 Permission denied