Spring中使用Mybatis-spring。java
Spring版本4.3.11,Mybatis-spring版本是1.3.2,Mybatis版本是3.4.6。git
使用示例以下圖1,源碼地址:spring
圖1sql
咱們來看MapperScannerConfigurer的來實現,它的類繼承圖以下圖2mybatis
圖2app
MapperScannerConfigurer實現了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,以下List-1所示:post
List-1ui
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { this.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, ",; \t\n")); }
List-1中,基本上是給ClassPathMapperScanner設置屬性,再來看ClassPathMapperScanner,以下圖3所示:this
圖3debug
List-1中調用的scan方法在ClassPathBeanDefinitionScanner中,以下List-2,doScan方法本來在ClassPathBeanDefinitionScanner中,不過被ClassPathMapperScanner類覆寫了,
List-2
public int scan(String... basePackages) { int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); this.doScan(basePackages); if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } return this.registry.getBeanDefinitionCount() - beanCountAtScanStart; }
List-3
public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { this.processBeanDefinitions(beanDefinitions); } return beanDefinitions; } private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { Iterator var3 = beanDefinitions.iterator(); while(var3.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next(); GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition(); if (this.logger.isDebugEnabled()) { this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface"); } definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); 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; } if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { this.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) { this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { if (this.logger.isDebugEnabled()) { this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); } definition.setAutowireMode(2); } } }
List-3的doScan方法,先調用父方法的doScan方法獲取BeanDefinition,以後調用processBeanDefinitions方法。有沒有想過一個問題,咱們定義的Mapper 類是interface,是不能被實例化的,它是怎麼被注入Spring中讓咱們使用的?List-3的processBeanDefinitions方法中設置BeanClass爲MapperFactoryBean,答案就在這個MapperFactoryBean中。
注意List-3的末尾處有個"definition.setAutowireMode(2);",這是設置注入的類型,哪2是哪一種類型呢,來看AbstractBeanDefinition,以下List-4,2是Autowire_by_name。
List-4
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { public static final String SCOPE_DEFAULT = ""; public static final int AUTOWIRE_NO = 0; public static final int AUTOWIRE_BY_NAME = 1; public static final int AUTOWIRE_BY_TYPE = 2; public static final int AUTOWIRE_CONSTRUCTOR = 3; /** @deprecated */ @Deprecated public static final int AUTOWIRE_AUTODETECT = 4; public static final int DEPENDENCY_CHECK_NONE = 0; public static final int DEPENDENCY_CHECK_OBJECTS = 1; public static final int DEPENDENCY_CHECK_SIMPLE = 2; public static final int DEPENDENCY_CHECK_ALL = 3; ......
咱們繼續看MapperFactoryBean,
圖4
如圖4所示,看到FactoryBean,若是瞭解Spring IOC,那個應該意識到了。在Spring IOC中若是遇到FactoryBean,會調用它的getObject方法,將其結果做爲值注入到IOC,FactoryBean的getObjectType則是返會類型。以下List-5所示:
List-5
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { private Class<T> mapperInterface; private boolean addToConfig = true; public MapperFactoryBean() { } public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } ...... public T getObject() throws Exception { return this.getSqlSession().getMapper(this.mapperInterface); } public Class<T> getObjectType() { return this.mapperInterface; } public boolean isSingleton() { return true; } ......
List-5的getObject()中,調用父類SqlSessionDaoSupport的方法getSqlSession(),來看下SqlSessionDaoSupport,以下List-6
List-6
public abstract class SqlSessionDaoSupport extends DaoSupport { private SqlSession sqlSession; private boolean externalSqlSession; public SqlSessionDaoSupport() { } public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (!this.externalSqlSession) { this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); } } public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSession = sqlSessionTemplate; this.externalSqlSession = true; } public SqlSession getSqlSession() { return this.sqlSession; } protected void checkDaoConfig() { Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); } }
Spring會調用List-6中的方法setSqlSessionFactory方法,爲何這麼說,List-3中"definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));",這樣設置了以後Spring會調用setSqlSessionFactory方法。這樣List-6中,就引用了咱們在圖1中定義的sqlSessionFactory,以後構造出SqlSessionTemplate。
接下來就是分析SqlSessionTemplate。
到目前爲止,咱們知道了Mybatis是如何融入到Spring容器中的。不過仍是遺留了不少問題,好比最重要的,List-5中SqlSessionTemplate的.getMapper(this.mapperInterface)方法底層上是如何實現的。