分析Mybatis如何利用Spring的扩展点集成到框架中的,Mybatis本身的扩展点不再本次分析范畴
构建环境
上Github上下载https://github.com/mybatis/spring。通过Git的方式试了几次没成功,后来直接Down的zip包,再导入的Idea中的。
导入的过程当中会有点慢,要下载不少东西。记得一定要修改Maven的配置文件和本地仓库地址,否则可能之前你已经下过的相关包会又下载到C盘的本地仓库当中
测试代码
直接在源码目录下新建了一个目录来写测试代码
测试类
@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类
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> query(){
return userMapper.query();
}
}
Mapper类
public interface UserMapper {
@Select("SELECT name,age FROM user")
List<User> query();
}
实体类
@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相关的依赖不在运行时生效
<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可以参考https://my.oschina.net/u/3049601/blog/3129295
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
来源:oschina
链接:https://my.oschina.net/u/3049601/blog/3131697