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 MybatisMapperProxymapperProxy = 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的逻辑,本文就不做介绍了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)