MybatisPlusAutoConfiguration源码分析

MybatisPlusAutoConfiguration源码分析,第1张

MybatisPlusAutoConfiguration源码分析 入口

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
MybatisPlusAutoConfiguration配置类 创建SqlSessionFactory

此处使用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(Set beanDefinitions) {
  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方法。

public  T getMapper(Class type) {
  return getConfiguration().getMapper(type, this);
}

此处getConfiguration()获取到的是com.baomidou.mybatisplus.core.MybatisConfiguration对象,前文已经提到过了。

所以需要看一下com.baomidou.mybatisplus.core.MybatisConfiguration的getMapper方法。

MybatisConfiguration.getMapper方法
public  T 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方法:

public  T 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的逻辑,本文就不做介绍了。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5075481.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-16
下一篇 2022-11-16

发表评论

登录后才能评论

评论列表(0条)

保存