mybatis plus的自动装配在mybatis-plus-boot-starter包实现,可以看一下meta-INF/spring.factories文件,这个文件里面可以找到自动装配的配置类:
# Auto Configure org.springframework.boot.env.EnvironmentPostProcessor= com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration, com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
可以看到是这个类做的自动装配:
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
这个类主要做了以下几件事:
- 创建SqlSessionFactory
- 创建SqlSessionTemplate
此处使用baomidou的MybatisSqlSessionFactoryBean来创建SqlSessionFactory,前面都是设置必要属性,最重要的是最后的这行代码:
factory.getObject();
会进入到afterPropertiesSet()方法:
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
afterPropertiesSet()方法:
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}
buildSqlSessionFactory()方法做了以下几件事:
- 加载mybatis主配置
- 自定义枚举类扫描处理
- 类型别名、包别名、插件等
- 加载XML Mapper文件
- 创建一个mybatis的SqlSessionFactory并返回
这行代码很重要:
final SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(targetConfiguration);
这里传递的targetConfiguration是com.baomidou.mybatisplus.core.MybatisConfiguration对象,而不是org.apache.ibatis.session.Configuration对象,这一点很重要。
创建SqlSessionTemplate这个方法比较简单,就是创建一个mybatis的SqlSessionTemplate:
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
Mapper接口扫描
MapperScannerConfigurer回顾
在《Autowired注入Service变成了biaomidou的Mapper代理》中,我们了解到mybatis是在ClassPathMapperScanner的processBeanDefinitions方法里面向spring注入Mapper接口的bean definition的:
private void processBeanDefinitions(SetbeanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); String beanClassName = definition.getBeanClassName(); // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // 重新设置beanClass // this.mapperFactoryBeanClass是org.mybatis.spring.mapper.MapperFactoryBean // 他是MapperFactoryBean的FactoryBean的实现 // Spring在创建了FactoryBean实现类的实例之后,会调用他的T getObject()方法获取真实的Bean // 然后将这个Bean放入容器 // MapperFactoryBean内部会为Mapper接口创建Proxy // 多数的接口扫描的框架都是利用Spring FactoryBean + Proxy方式实现的 // MapperFactoryBean内部创建代理的逻辑不在本文讨论范围,暂时省略 definition.setBeanClass(this.mapperFactoryBeanClass); definition.getPropertyValues().add("addToConfig", this.addToConfig); // 以下设置sqlSessionFactory和sqlSessionTemplate的代码在多数情况下都不会执行,因为没有配置 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(""); } definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { LOGGER.warn(""); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } definition.setLazyInit(lazyInitialization); } }
这里是有的是spring的FactoryBean机制,所以需要看一下org.mybatis.spring.mapper.MapperFactoryBean的getBean方法。
MapperFactoryBean.getBean()方法public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
此处调用的是SqlSessionTemplate的getMapper方法。
publicT getMapper(Class type) { return getConfiguration().getMapper(type, this); }
此处getConfiguration()获取到的是com.baomidou.mybatisplus.core.MybatisConfiguration对象,前文已经提到过了。
所以需要看一下com.baomidou.mybatisplus.core.MybatisConfiguration的getMapper方法。
MybatisConfiguration.getMapper方法publicT getMapper(Class type, SqlSession sqlSession) { return mybatisMapperRegistry.getMapper(type, sqlSession); }
mybatisMapperRegistry对象:
protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);
这个是com.baomidou.mybatisplus.core.MybatisMapperRegistry对象。
MybatisMapperRegistry.getMapper方法:
publicT getMapper(Class type, SqlSession sqlSession) { // com.baomidou.mybatisplus.core.override.MybatisMapperProxyFactory final MybatisMapperProxyFactory mapperProxyFactory = (MybatisMapperProxyFactory ) knownMappers.get(type); try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
MybatisMapperProxyFactory.newInstance方法:
public T newInstance(SqlSession sqlSession) {
final MybatisMapperProxy mapperProxy =
new MybatisMapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MybatisMapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(
mapperInterface.getClassLoader(),
new Class[]{mapperInterface},
mapperProxy
);
}
com.baomidou.mybatisplus.core.override.MybatisMapperProxy实现了InvocationHandler接口,实现了代理功能,看一下invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 走这个分支
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
if (m.isDefault()) {
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
// 走这个分支
return new PlainMethodInvoker(
new MybatisMapperMethod(
mapperInterface, method, sqlSession.getConfiguration()
)
);
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
PlainMethodInvoker类:
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MybatisMapperMethod mapperMethod;
public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
super();
this.mapperMethod = mapperMethod;
}
@Override
public Object invoke(
Object proxy, Method method, Object[] args, SqlSession sqlSession)
throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
}
可以看到执行的是MybatisMapperMethod的execute方法:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
// ...
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("...");
}
return result;
}
以上就是mybatis plus的spring boot自动装配过程,mybatis的spring boot自动装配相似。
后续的代码是mybatis和mybatis plus的逻辑,本文就不做介绍了。



