美文网首页
spring boot mybatis 加载过程

spring boot mybatis 加载过程

作者: 草祭木初 | 来源:发表于2021-03-22 17:25 被阅读0次

    其实最简单的使用mybatis是这样
    创建spring boot 项目
    maven加载mabatis
    创建数据源配置
    建个文件夹
    建个接口文件用@Mapper注解
    ok了

    @Mapper
    public interface UserDao {
        @Select("select * from t_user limit 1")
        public List<Map> getUserList();
    }
    

    然后就可以在其他类里注入这个Dao并调用了

    是不是 很简单
    那spring boot 和 mabatis 是怎么实现的,让这个接口可以用呢?

    1,先看下我们用maven都引入哪些关于mybatis的包

    maven配置

            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
    

    共引入的4个包

    • org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.1.4
    • org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4
    • org.mybatis:mybatis:3.5.6
    • org.mybatis:mybatis-spring:2.0.6

    光看名字就知道了
    org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.1.4
    这个就是自动配置的包,符合spring-boot自动配置约定

    看下spring.fatories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
    org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
    

    两个自动配置类,会被spring-boot在启动时扫描到

    • MybatisLanguageDriverAutoConfiguration:这个是加载不同语言脚本用的例如php脚本,我们这篇文章不关心
    • MybatisAutoConfiguration:主要看这个

    2,MybatisAutoConfiguration

    @Configuration
    @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
    @ConditionalOnSingleCandidate(DataSource.class)
    @EnableConfigurationProperties({MybatisProperties.class})
    @AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
    public class MybatisAutoConfiguration implements InitializingBean {
        private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
        private final MybatisProperties properties;
        private final Interceptor[] interceptors;
        private final TypeHandler[] typeHandlers;
        private final LanguageDriver[] languageDrivers;
        private final ResourceLoader resourceLoader;
        private final DatabaseIdProvider databaseIdProvider;
        private final List<ConfigurationCustomizer> configurationCustomizers;
    
        public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
            this.properties = properties;
            this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable();
            this.typeHandlers = (TypeHandler[])typeHandlersProvider.getIfAvailable();
            this.languageDrivers = (LanguageDriver[])languageDriversProvider.getIfAvailable();
            this.resourceLoader = resourceLoader;
            this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable();
            this.configurationCustomizers = (List)configurationCustomizersProvider.getIfAvailable();
        }
        。。。
    }
    

    @Configuration 和 InitializingBean 接口
    请参照:spring 生命周期 扩展点

    请他注解请自己去查
    但 看名字也知道了,主要是要在DataSource加载完后,才会加载这个类

    不过这个类有点特别,它的属性没有用注解的方式注入
    而是用构造函数,但我们又没有用显示的@Bean注解才构造它
    是怎么实现的呢?
    是因为在
    spring 4.3之后,引入了一个新特性:当构造方法的参数为单个构造参数时,可以不使用@Autowired进行注解
    同样是在Spring 4.3版本中,不仅隐式的注入了单构造参数的属性。还引入了ObjectProvider接口。
    具体请参照# ObjectProvider使用说明

    到目前为止好像没有发生什么

    再看看它还有什么方法

        // afterPropertiesSet 是实现的 InitializingBean 接口 会在属性加载完调用
        // 去检查 mybatis.config-location 指定的配置文件,我们没用上(什么配置都没有)
        public void afterPropertiesSet() {        this.checkConfigFileExists();    }
        private void checkConfigFileExists() {。。。}
    
        // 初始化SqlSessionFactory
        @Bean
        @ConditionalOnMissingBean
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
            。。。
            this.applyConfiguration(factory);
            。。。
        }
        // 根据配置文件 初始化一些配置,我们没用上(什么配置都没有)
        private void applyConfiguration(SqlSessionFactoryBean factory) {。。。}
    
        // 初始化 SqlSessionTemplate,你可以手动调用这个类执行sql
        // 但它并没有做别的
        @Bean
        @ConditionalOnMissingBean
        public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {。。。}
    
        // 重点来了 这也是一个配置类
        // 看名字也知道了,MapperScanner
        // 但这个类其实没干啥,只不过在MapperFactoryBean.class, MapperScannerConfigurer.class 不存在时,记录log
        // 真正做事的是AutoConfiguredMapperScannerRegistrar
        @Configuration
        @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
        @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
        public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
            public MapperScannerRegistrarNotFoundConfiguration() {
            }
    
            public void afterPropertiesSet() {
                MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
            }
        }
    
        public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {。。。}
    
    

    先不管@Configuration为何嵌套
    @Configuration可以参照:@Configuration 详解

    3,AutoConfiguredMapperScannerRegistrar

    首先要注意一件事
    MapperFactoryBean.class, MapperScannerConfigurer.class 他们很重要,
    故名思意啊

    • MapperFactoryBean.class:生产Mapper实例,我们只定义了接口
    • MapperScannerConfigurer.class:扫描Mapper定义

    看下源码

        public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
            private BeanFactory beanFactory;
            public AutoConfiguredMapperScannerRegistrar() {
            }
    
            // 主要是这个方法,实现至ImportBeanDefinitionRegistrar 
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {。。。}
    
            public void setBeanFactory(BeanFactory beanFactory) {
                this.beanFactory = beanFactory;
            }
        }
    

    实现了两个接口

    • BeanFactoryAware:用来注入BeanFactory
    • ImportBeanDefinitionRegistrar:@Import注解用,可以先于@Configuration加载

    registerBeanDefinitions方法

            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                if (!AutoConfigurationPackages.has(this.beanFactory)) {
                    MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
                } else {
                    MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                    // spring-boot扫描的包
                    List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                    if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                        packages.forEach((pkg) -> {
                            MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                        });
                    }
    
                    // 构建MapperScannerConfigurer定义,并加入spring容器
                    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                    builder.addPropertyValue("processPropertyPlaceHolders", true);
                    builder.addPropertyValue("annotationClass", Mapper.class);
                    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
                    BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
                    Set<String> propertyNames = (Set)Stream.of(beanWrapper.getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
                    if (propertyNames.contains("lazyInitialization")) {
                        builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
                    }
    
                    if (propertyNames.contains("defaultScope")) {
                        builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
                    }
    
                    registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
                }
            }
    

    这个方法其实就做了一件事
    构建MapperScannerConfigurer定义并加入到spring容器中,并注入了一些属性
    这样在spring容器加载类的时候就可以实例化它了

    为什么要这么做,而不是@Component注解来加载MapperScannerConfigurer
    个人理解
    主要是为了,注入一些特别的属性

    4,MapperScannerConfigurer

    定义

    public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
      。。。
    }
    

    实现了4个接口
    请参照:spring 生命周期 扩展点

    其他函数不介绍了
    主要是这个

        // spring 生命周期函数 实现至BeanDefinitionRegistryPostProcessor
        // 会在spring容器扫描完@Component后执行
        // 请注意@Mapper是Mybatis的注解,并没有组合@Component,所以不会被spring容器加载
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
            // 这个依然是给 mapperScannerBean 注入属性,看名字也知道
            if (this.processPropertyPlaceHolders) {
                this.processPropertyPlaceHolders();
            }
            
            // 看名字 就知道要开始 扫描mapper了
            ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
            scanner.setAddToConfig(this.addToConfig);
            // 扫描@Mapper标注的类
            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);
            // 其他的属性 不一一介绍,关键是这个看使用的的FactoryBean
            scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
            if (StringUtils.hasText(this.lazyInitialization)) {
                scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
            }
    
            if (StringUtils.hasText(this.defaultScope)) {
                scanner.setDefaultScope(this.defaultScope);
            }
    
            scanner.registerFilters();
            // 扫描指定包,如果不指定就是 main函数所在包 与 spring 扫描的一样
            scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
        }    
    

    5,ClassPathMapperScanner

    继承自:ClassPathBeanDefinitionScanner
    重写了:doScan

    public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
      // 上面提到的,事实上我们没有传入mapperFactoryBeanClass,所以这里用的是MapperFactoryBean
      public void setMapperFactoryBeanClass(Class<? extends MapperFactoryBean> mapperFactoryBeanClass) {
            this.mapperFactoryBeanClass = mapperFactoryBeanClass == null ? MapperFactoryBean.class : mapperFactoryBeanClass;
        }
    
        public Set<BeanDefinitionHolder> doScan(String... basePackages) {
            // 调用父类spring的扫描器
            Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
            if (beanDefinitions.isEmpty()) {
                LOGGER.warn(() -> {
                    return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
                });
            } else {
                // 如果有Mapper,这个时候Mapper已经在spring容器中了
                this.processBeanDefinitions(beanDefinitions);
            }
    
            return beanDefinitions;
        }
    
        // 修改Mapper定义
        private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
            BeanDefinitionRegistry registry = this.getRegistry();
            Iterator var4 = beanDefinitions.iterator();
    
            while(var4.hasNext()) {
                BeanDefinitionHolder holder = (BeanDefinitionHolder)var4.next();
                AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition();
                // 我们的Mapper通常都是单例的,所以这个是 false
                boolean scopedProxy = false;
                if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
                    definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> {
                        return new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]");
                    });
                    scopedProxy = true;
                }
    
                String beanClassName = definition.getBeanClassName();
                LOGGER.debug(() -> {
                    return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
                });
                definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
                // 指定Mapper的class为MapperFactoryBean。为生成实例做准备
                // 因为我们Mapper是接口,不能生成实例
                definition.setBeanClass(this.mapperFactoryBeanClass);
                definition.getPropertyValues().add("addToConfig", this.addToConfig);
                definition.setAttribute("factoryBeanObjectType", beanClassName);
                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(() -> {
                            return "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(() -> {
                            return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
                        });
                    }
    
                    definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
                    explicitFactoryUsed = true;
                }
    
                if (!explicitFactoryUsed) {
                    LOGGER.debug(() -> {
                        return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.";
                    });
                    definition.setAutowireMode(2);
                }
    
                definition.setLazyInit(this.lazyInitialization);
                if (!scopedProxy) {
                    if ("singleton".equals(definition.getScope()) && this.defaultScope != null) {
                        definition.setScope(this.defaultScope);
                    }
    
                    if (!definition.isSingleton()) {
                        BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
                        if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
                            registry.removeBeanDefinition(proxyHolder.getBeanName());
                        }
                        // 如果不是单例模式的时候 重新注册
                        registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
                    }
                }
            }
    
        }
    }
    

    6,MapperFactoryBean

    上面的步骤是吧我们的Mapper注册到spring容器了
    还没有实例化
    但是,我们的Mapper是接口,没有办法直接实例化
    这个时候MapperFactoryBean 就上场了

    MapperFactoryBean
    继承自:SqlSessionDaoSupport 这个辅助类先不看
    实现了:FactoryBean,这个接口的作用是,当spring创建实现了FactoryBean接口的Bean时,当你将这个类型注入到其他对象时,实际上返回的是getObject方法返回的对象,返回的类型是getObjectType返回的类型

    public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
        // 实现自 FactoryBean
        // 这个方法是真正生成 Mapper实例的
        public T getObject() throws Exception {
            // 这个 this.getSqlSession() 是SqlSessionDaoSupport  的方法,返回的sqlSessionTemplate
            // sqlSessionTemplate在最初的MybatisAutoConfiguration 实例化过
            return this.getSqlSession().getMapper(this.mapperInterface);
        }
        // 实现自 FactoryBean
        public Class<T> getObjectType() {
            return this.mapperInterface;
        }
    }
    

    看下
    SqlSessionTemplate

    public class SqlSessionTemplate implements SqlSession, DisposableBean {
        public <T> T getMapper(Class<T> type) {
            return this.getConfiguration().getMapper(type, this);
        }
    
        public Configuration getConfiguration() {
            // sqlSessionFactory 在最初的MybatisAutoConfiguration 实例化过
            return this.sqlSessionFactory.getConfiguration();
        }
    }
    

    然后 Configuration

    public class Configuration {
        protected final MapperRegistry mapperRegistry;
        public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            return this.mapperRegistry.getMapper(type, sqlSession);
        }
    }
    

    然后 MapperRegistry

    public class MapperRegistry {
        public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
            if (mapperProxyFactory == null) {
                throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
            } else {
                try {
                    // 终于new对象了
                    return mapperProxyFactory.newInstance(sqlSession);
                } catch (Exception var5) {
                    throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
                }
            }
        }
    }
    

    然后MapperProxyFactory

    public class MapperProxyFactory<T> {
        private final Class<T> mapperInterface;
        private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap();
    
        public MapperProxyFactory(Class<T> mapperInterface) {
            this.mapperInterface = mapperInterface;
        }
    
        public Class<T> getMapperInterface() {
            return this.mapperInterface;
        }
    
        public Map<Method, MapperMethodInvoker> getMethodCache() {
            return this.methodCache;
        }
    
        protected T newInstance(MapperProxy<T> mapperProxy) {
            // 通过java的动态代理 创建Mappe对象
            // 动态代理就不讲了
            return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
        }
    
        public T newInstance(SqlSession sqlSession) {
            MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
            return this.newInstance(mapperProxy);
        }
    }
    

    到上面为止,Mapper类的实例化已经完成了

    7,接口调用

    MapperProxy
    实现了InvocationHandler:java动态代理的Handler

    public class MapperProxy<T> implements InvocationHandler, Serializable { 
        // 真正执行方法是这个代理方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            try {
                // 这个判断没弄明白,不知道 什么情况可以直接调用原类的方法,这边走的是后者
                return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        }
    
        private MapperProxy.MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
            try {
                MapperProxy.MapperMethodInvoker invoker = (MapperProxy.MapperMethodInvoker)this.methodCache.get(method);
                // 如果执行过就缓存起来
                return invoker != null ? invoker : (MapperProxy.MapperMethodInvoker)this.methodCache.computeIfAbsent(method, (m) -> {
                    // 判断是否是默认方法,我们的都不是
                    if (m.isDefault()) {
                        try {
                            return privateLookupInMethod == null ? new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava8(method)) : new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava9(method));
                        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException var4) {
                            throw new RuntimeException(var4);
                        }
                    } else {
                        // PlainMethodInvoker是个内部类 很简单
                        return new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration()));
                    }
                });
            } catch (RuntimeException var4) {
                Throwable cause = var4.getCause();
                throw (Throwable)(cause == null ? var4 : cause);
            }
        }
    
        private static class PlainMethodInvoker implements MapperProxy.MapperMethodInvoker {
            private final MapperMethod mapperMethod;
    
            public PlainMethodInvoker(MapperMethod mapperMethod) {
                this.mapperMethod = mapperMethod;
            }
    
            public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
                return this.mapperMethod.execute(sqlSession, args);
            }
        }
    
        interface MapperMethodInvoker {
            Object invoke(Object var1, Method var2, Object[] var3, SqlSession var4) throws Throwable;
        }
    }
    

    MapperMethod

    public class MapperMethod {
        private final MapperMethod.SqlCommand command;
        private final MapperMethod.MethodSignature method;
    
        public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
            // 生成sql 对象
            this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
            // 方法签名
            this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
        }
    
        // 最终调用的是sqlSession 的方法,也就是
        // 最初在MybatisAutoConfiguration里生成的 sqlSessionTemplate
        public Object execute(SqlSession sqlSession, Object[] args) {
            Object result;
            Object param;
            switch(this.command.getType()) {
            case INSERT:
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
                break;
            case UPDATE:
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
                break;
            case DELETE:
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
                break;
            case SELECT:
                if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                    this.executeWithResultHandler(sqlSession, args);
                    result = null;
                } else if (this.method.returnsMany()) {
                    result = this.executeForMany(sqlSession, args);
                } else if (this.method.returnsMap()) {
                    result = this.executeForMap(sqlSession, args);
                } else if (this.method.returnsCursor()) {
                    result = this.executeForCursor(sqlSession, args);
                } else {
                    param = this.method.convertArgsToSqlCommandParam(args);
                    result = sqlSession.selectOne(this.command.getName(), param);
                    if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                        result = Optional.ofNullable(result);
                    }
                }
                break;
            case FLUSH:
                result = sqlSession.flushStatements();
                break;
            default:
                throw new BindingException("Unknown execution method for: " + this.command.getName());
            }
    
            if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
                throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
            } else {
                return result;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:spring boot mybatis 加载过程

          本文链接:https://www.haomeiwen.com/subject/zywhcltx.html