Mybatis-Spring源碼分析

分析Mybatis如何利用Spring的擴展點集成到框架中的,Mybatis自己的擴展點再也不本次分析範疇html

構建環境

上Github上下載https://github.com/mybatis/spring。經過Git的方式試了幾回沒成功,後來直接Down的zip包,再導入的Idea中的。java

導入的過程中會有點慢,要下載很多東西。記得必定要修改Maven的配置文件和本地倉庫地址,不然可能以前你已經下過的相關包會又下載到C盤的本地倉庫當中mysql

測試代碼

直接在源碼目錄下新建了一個目錄來寫測試代碼git

測試類github

@Configuration
@MapperScan("com.jv.mapper")
@ComponentScan("com.jv.scan")
public class TestMybatis {

  public static void main(String[] args) {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestMybatis.class);
    UserService bean = ac.getBean(UserService.class);
    System.out.println(bean.query());
  }

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    PooledDataSource dataSource = new PooledDataSource();
    dataSource.setDriver("org.mariadb.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://192.168.10.12:3306/acct?useSSL=false&serverTimezone=UTC");
    dataSource.setUsername("dev01");
    dataSource.setPassword("12340101");
    factoryBean.setDataSource(dataSource);
    return factoryBean.getObject();
  }
}

Service類 spring

@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;

  public List<User> query(){
    return userMapper.query();
  }
}

Mapper類sql

public interface UserMapper {
  @Select("SELECT name,age FROM user")
  List<User> query();
}

實體類mybatis

@ToString
public class User {

  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() {
    return age;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  private Integer age;
}

注意:運行以前必定要修改pom.xml。由於Mybatis導入的Spring相關的依賴不在運行時生效app

<scope>provided</scope>所有註釋掉,不然運行的時候會報好不到類框架

表結構:

CREATE TABLE `user` (
  `name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `age` int(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

insert into user(name,age) values("Messi",35);

commit;

源碼分析

從mybatis-spring官方文檔中能夠找到@MapperScan的用法:http://mybatis.org/spring/mappers.html

註冊BeanDefinition

既然和Spring集成是經過@MapperScan完成的,那從它入手

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
....
}

其中@Import(MapperScannerRegistrar.class)是重點,再看MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  /**
   * {@inheritDoc}
   * 
   * @deprecated Since 2.0.2, this method not used never.
   */
  @Override
  @Deprecated
  public void setResourceLoader(ResourceLoader resourceLoader) {
    // NOP
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
    }
  }

  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {

    /**
     * 註冊一個MapperScannerConfigurer的BeanDefinition,MapperScannerConfigurer實現了BeanDefinitionRegistryPostProcessor
     * BeanDefinitionRegistryPostProcessor接口的實現類,一旦放入Spring容器中,那麼在Spring容器啓動的時候它能夠擔任註冊本身須要BeanDefinition的功能
     */

    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    builder.addPropertyValue("processPropertyPlaceHolders", true);

    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      builder.addPropertyValue("annotationClass", annotationClass);
    }

    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      builder.addPropertyValue("markerInterface", markerInterface);
    }

    //自定義BeanNameGenerator
    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
    }

    //自定義MapperFactoryBean
    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
    }

    //自定義sqlSessionTemplate
    String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
    if (StringUtils.hasText(sqlSessionTemplateRef)) {
      builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
    }

    //自定義sqlSessionFactory
    String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
    if (StringUtils.hasText(sqlSessionFactoryRef)) {
      builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
    }

    //生成全部的scan要掃描的基礎包路徑
    List<String> basePackages = new ArrayList<>();
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
        .collect(Collectors.toList()));

    //設置延遲加載
    String lazyInitialization = annoAttrs.getString("lazyInitialization");
    if (StringUtils.hasText(lazyInitialization)) {
      builder.addPropertyValue("lazyInitialization", lazyInitialization);
    }

    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

    //將MapperScannerConfigurer的BeanDefinition註冊
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }

}

MapperScannerRegistrar implements ImportBeanDefinitionRegistrar

這就是它集成到Spring的關鍵點,關於ImportBeanDefinitionRegistrar能夠參考http://www.javashuo.com/article/p-ccwckotr-q.html

MapperScannerRegistrar 在Spring容器初始化的時候完成從外部導入MapperScannerConfigurer類對應的BeanDefinition

MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor(又是Spring的另一個擴展點,也是擴展BeanDefinition註冊功能,但它要晚於ImportBeanDefinitionRegistrar生效,由於前者的做用觸發時機是Spring的ConfigurationClassPostProcessor Implements PriorityOrder。 這個類是掃描路徑下全部Mapper的關鍵類

/**
 * BeanDefinitionRegistryPostProcessor遞歸地從基本包中搜索接口並將它們註冊爲MapperFactoryBean
 *   MapperFactoryBean很是重要,它實現了InitializingBean,Spring會讓Bean屬性設置完以後調用它的抽象方法afterPropertiesSet,完成一些初始化操做
 */
public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

  .................省略部分代碼..................
 
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    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);
    //默認是MapperFactoryBean,能夠是自定義的
    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    scanner.registerFilters();
    //開始掃描
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

  .................省略部分代碼..................

}

ClassPathMapperScanner 繼承自 Spring.ClassPathBeanDefinitionScanner,重寫了doScan方法

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  .................省略部分代碼..................

  /**
   * 重寫了ClassPathBeanDefinitionScanner的doScan方法,可是掃描工做仍是由父類的doScan完成
   */
  @Override
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    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;
  }

  /**
   * 重寫了ClassPathBeanDefinitionScanner的processBeanDefinitions方法
   * 完成BeanDefinition的屬性填充
   * 其中的setAutowireMode=AbstractBeanDefinition.AUTOWIRE_BY_TYPE  是Spring根據類型完成自動注入的關鍵。
   * @param beanDefinitions
   */
  private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      /**
       * 自定義的Mapper接口只是Bean最初的類,當Spring初始化以後Bean的Class其實是MapperFactoryBean
       */
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      //設置BeanClass爲MapperFactoryBean
      definition.setBeanClass(this.mapperFactoryBeanClass);

      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) {
          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) {
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        // 至關的重要,這就是Spring的根據類型進行依賴注入。
        // @Autowired使用的時候,其實Spring默認是沒有自動注入的,也就是說autowireMode是AUTOWIRE_NO
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
      definition.setLazyInit(lazyInitialization);
    }
  }

  .................省略部分代碼..................
}

上面的代碼完成了對basePackage的類掃描,Mybatis根據掃描生成的BeanDefinition作加強,至關重要的兩點:

1.BeanClass=MapperFactoryBean 

也就是說:最開始Spring容器初始化完成以後,全部Mapper並無真正的實例化(能夠經過觀察XXXApplicationContext.beanFactory.FactoryBeanObjectCache中是否有對象),而是它們的FactoryBean已經完成了實例化。當須要Mapper時再建立,若是是單例,則將已經實例化的Bean放到FactoryBeanObjectCache中

2.autowireMode=AUTOWIRE_BY_TYPE

按類型自動注入和@Autowired沒直接聯繫,Spring默認是AUTOWIRE_NO,只不過Spring發現你用了@Autowired註解會自動根據類型注入而已。按類型自動注入必需要有setXXX方法。

表明了被掃描的類支持按類型實例化,爲何要設置這個值喃?咱們本身寫的Mapper牢牢是一個接口,爲何還要注入東西喃。。。根本緣由是MapperFactoryBean extends SqlSessionDaoSupport

SqlSessionDaoSupport裏面有兩個set方法,分別是:

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory)

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)

能夠驗證一下,將「definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)」 註釋掉,報錯:

表明着沒有注入成功,也驗證了AUTOWIRE_BY_TYPE的重要性

 

截止到這裏,Mybatis相關類的BeanDefinition(BeanClass=MapperFactoryBean)所有完成了註冊,接下來就是實例化

實例化

實例化時有兩個很是重要的點:

1.前面說過由於添加到BeanDefinitionMap中的bd都是MapperFactoryBean,因此完成實例化的Mapper都是MapperFactoryBean,而不是真正的Mapper。可是在實例化MapperFactoryBean所須要的SqlSessionFactory,SqlSessionTemplate從哪裏獲取到喃。

 

首先在TestMybatis類中使用了@Bean註解,Spring對於@Bean和ImportBeanDefinitionRegistrar,前者會先處理,也就是說@MapperScan掃描到的類會晚於@Bean修飾的SqlSessionFactory註冊到容器中。因此Spring在實例化MapperFactoryBean的時候自動注入SqlSessionFactory是能夠成功的,具體源碼見:

根據BeanDefinition.propertValues+setterXXX標記的屬性獲取Bean,在這裏就是被setSqlSesstionFactory()標記的SqlSessionFactory屬性:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByType()

protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}

		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		//過濾掉不須要自動注入的屬性,好比沒有setter方法啊,簡單類:Class,URL,Number等
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//循環處理屬性,最終會將要注入的對象獲取到並放入到PVS當中,等候後面的注入
		for (String propertyName : propertyNames) {
			try {
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				// Don't try autowiring by type for type Object: never makes sense,
				// even if it technically is a unsatisfied, non-simple property.
				if (Object.class != pd.getPropertyType()) {
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					// Do not allow eager init for type matching in case of a prioritized post-processor.
					boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
					//獲取到Class對象
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//獲取到Class對象
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
						registerDependentBean(autowiredBeanName, beanName);
						if (logger.isTraceEnabled()) {
							logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
									propertyName + "' to bean named '" + autowiredBeanName + "'");
						}
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}

 

根據獲取到的Bean進行注入:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

/**
	 * Populate the bean instance in the given BeanWrapper with the property values
	 * from the bean definition.  用bean定義中的屬性值填充給定BeanWrapper中的bean實例
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @param bw the BeanWrapper with bean instance
	 */
	@SuppressWarnings("deprecation")  // for postProcessPropertyValues
	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        。。。。省略部分代碼。。。。
		/**
		 * 給任何InstantiationAwareBeanPostProcessors機會在屬性被設置以前修改Bean的狀態(屬性),好比設置特殊的屬性值,
		 * 或者修改PropertyValues中的值
		 */
		boolean continueWithPropertyPopulation = true;
		//第十二次PostProcessor  InstantiationAwareBeanPostProcessors
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		//根據名稱或類型注入依賴
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			// 經過屬性名稱注入依賴  BeanDefinition.autowireMode=AUTOWIRE_BY_NAME
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			// 經過屬性類型注入依賴 BeanDefinition.autowireMode=AUTOWIRE_BY_TYPE
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//PostProcessor  和下面調用是一樣的效果,後者已通過期了,Spring5就是在這裏注入的,
					// -----------------好比對象和屬性值的注入------------------------
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						//PostProcessor
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
      。。。。省略部分代碼。。。。
	}

可是Spring容器中並無SqlSessionTemplate,爲何MapperFactoryBean最後也仍是有喃,由於在注入SqlSessionFactory的時候Mybatis自動實例化了它

public abstract class SqlSessionDaoSupport extends DaoSupport {
  。。。。。註釋部分代碼。。。。
  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
      this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
    }
  }
  。。。。。註釋部分代碼。。。。
}

 

2.執行DML所須要的信息從哪裏來?

接下來看看MapperFactoryBean的類圖

能夠看到最終實現了InitializingBean,Spring針對實現了該接口的Bean,在完成屬性填充以後會調用實現類的afterPropertiesSet()方法。

調用位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			。。。。省略部分代碼。。。。
			if (System.getSecurityManager() != null) {
				。。。。省略部分代碼。。。。
			}
			else {
				//執行實現了InitializingBean子類的afterPropertiesSet
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		//執行設置的InitMethod
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

來看看Mybatis的DaoSupport類的afterPropertiesSet()方法幹了什麼

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        //運行時會調用MapperFactoryBean的checkDaoConfig
        this.checkDaoConfig();

        try {
            this.initDao();
        } catch (Exception var2) {
            throw new BeanInitializationException("Initialization of DAO failed", var2);
        }
    }

checkDaoConfig最終調用的是實現類MapperFactoryBean.checkDaoConfig方法

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 (Exception e) {
        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
        throw new IllegalArgumentException(e);
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }

configuration.addMapper(this.mapperInterface)完成了MappedStatement添加。

configuration是DefaultSqlSesstionFactory(默認的)中的屬性,全局惟一

MappedStatement描述了一個要執行的SQL,參數、返回類型等等

經過這一步,調用真正的query方法所須要的東西都準備好了。

 

總結:Mybatis利用了@Import(class implements ImportBeanDefinitionRegistrar),BeanDefinitionRegistryPostProcessor,InitializingBean三個擴展點來完成整合。

其中Mybatis的以下幾個類很是重要:

MapperScan MapperScannerRegistrar MapperScannerConfigurer ClassPathMapperScanner MapperFactoryBean DefaultSqlSessionFactory Configuration MapperStatement

相關文章
相關標籤/搜索