IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot集成mybatis原理分析 -> 正文阅读

[Java知识库]springboot集成mybatis原理分析

一.集成原理步骤

1.maven引入mybatis-spring-boot-starter

2.mybatis-spring-boot-starter引入了mybatis-spring-boot-autoconfigure

3.mybatis-spring-boot-autoconfigure的spring.factories自动注入自动装配类org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

4.自动装配类MybatisAutoConfiguration里面初始化SqlSessionFactory,SqlSessionTemplate等bean

5.下面为启动扫描,初始化bean,执行调用的整个mybatis源码,总是报mapper接口扫描不到,可以看下下面的逻辑

二.源代码分析

1.在启动类上增加@Mapperscan注解,扫描配置包下所有注解了@Mapper的接口,并生成spring的bean

@SpringBootApplication
@MapperScan(basePackages={com.test.mapper},annotationClass=Mapper.class)
public class OauthApplication {

    public static void main(String[] args) {
        SpringApplication.run(OauthApplication.class, args);
    }
}

2.@Mapperscan引入mapperscan注册配置,@Import类MapperScannerRegistrar

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<? extends BeanNameGenerator> nameGenerator() 
default BeanNameGenerator.class;
    Class<? extends Annotation> annotationClass() 
default Annotation.class;
    Class<?> markerInterface() default Class.class;
    String sqlSessionTemplateRef() default "";
    String sqlSessionFactoryRef() default "";
    Class<? extends MapperFactoryBean> factoryBean() 
default MapperFactoryBean.class;
    String lazyInitialization() default "";
    String defaultScope() default "";
}

3.通过MapperScannerRegistrar,初始化MapperScannerConfigurer

public class MapperScannerRegistrar implements
 ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    void registerBeanDefinitions(AnnotationMetadata annoMeta
, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry
, String beanName) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(MapperScannerConfigurer.class);
        registry.registerBeanDefinition(beanName
, builder.getBeanDefinition());
    }

4.如果在启动类上没有加?@Mapperscan,则解析MybatisAutoConfiguration类中MapperScannerRegistrarNotFoundConfiguration,@importAutoConfiguredMapperScannerRegistrar


public class MybatisAutoConfiguration 
implements InitializingBean {

  @org.springframework.context.annotation.Configuration
  @Import(AutoConfiguredMapperScannerRegistrar.class)
  @ConditionalOnMissingBean({ MapperFactoryBean.class
, MapperScannerConfigurer.class })
  public static class MapperScannerRegistrarNotFoundConfiguration
 implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
      logger.debug(
          "Not found configuration for registering
 mapper bean using @MapperScan, MapperFactoryBean 
and MapperScannerConfigurer.");
    }

  }

}

5.AutoConfiguredMapperScannerRegistrar初始化?MapperScannerConfigurer

public static class AutoConfiguredMapperScannerRegistrar implements 
BeanFactoryAware, EnvironmentAware
, ImportBeanDefinitionRegistrar {

    private BeanFactory beanFactory;
    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata
 importingClassMetadata, BeanDefinitionRegistry registry) {

      if (!AutoConfigurationPackages.has(this.beanFactory)) {
        logger.debug("Could not determine auto-configuration package
, automatic mapper scanning disabled.");
        return;
      }

      logger.debug("Searching for mappers annotated with @Mapper");

      List<String> packages = AutoConfigurationPackages
.get(this.beanFactory);
      if (logger.isDebugEnabled()) {
        packages.forEach(pkg -> logger
.debug("Using auto-configuration base package '{}'", pkg));
      }

      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 = Stream.of(beanWrapper.getPropertyDescriptors())
.map(PropertyDescriptor::getName)
          .collect(Collectors.toSet());
      if (propertyNames.contains("lazyInitialization")) {
        // Need to mybatis-spring 2.0.2+
        builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
      }
      if (propertyNames.contains("defaultScope")) {
        // Need to mybatis-spring 2.0.6+
        builder.addPropertyValue("defaultScope"
, "${mybatis.mapper-default-scope:}");
      }

      // for spring-native
      boolean injectSqlSession = environment
.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class,
          Boolean.TRUE);
      if (injectSqlSession 
&& this.beanFactory instanceof ListableBeanFactory) {
        ListableBeanFactory listableBeanFactory = (ListableBeanFactory)
 this.beanFactory;
        Optional<String> sqlSessionTemplateBeanName = Optional
            .ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));
        Optional<String> sqlSessionFactoryBeanName = Optional
            .ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));
        if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {
          builder.addPropertyValue("sqlSessionTemplateBeanName",
              sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));
        } else {
          builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());
        }
      }
      builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

      registry.registerBeanDefinition(MapperScannerConfigurer
.class.getName(), builder.getBeanDefinition());
    }

6.MapperScannerConfigurer扫描包下面所有的mapper并且初始化成动态bean,MapperFactoryBean

public class MapperScannerConfigurer implements 
BeanDefinitionRegistryPostProcessor, InitializingBean
, ApplicationContextAware, BeanNameAware {
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { 
        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);
        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();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }

7.ClassPathMapperScanner扫描注册MapperFactoryBean,放入了mapperInterface此为mapper接口类

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        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 {
            this.processBeanDefinitions(beanDefinitions);
        }
        return beanDefinitions;
    }


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();
            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();
            try {
                definition.getPropertyValues().add("mapperInterface", Resources.classForName(beanClassName));
            } catch (ClassNotFoundException var10) {
            }
            definition.setBeanClass(this.mapperFactoryBeanClass);
            definition.getPropertyValues().add("addToConfig", this.addToConfig);
            registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
                }
            }
        }

    }

}

8.mapper注入到service使用,由于Mapper接口都是通过FactoryBean生成对象,所以调用getObject获取bean对象,最终由MapperProxyFactory通过jdk动态代理生成mapper的代理对象MapperProxy,在MapperProxy中通过MapperMethod,再调用sqlSession执行数据库操作

public class MapperFactoryBean<T> extends SqlSessionDaoSupport
 implements FactoryBean<T> {
    private Class<T> mapperInterface;
    public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }
}
public class DefaultSqlSession implements SqlSession {
   public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }
}
public class Configuration {  
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
】
public class MapperRegistry {
 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory 
= (MapperProxyFactory)this.knownMappers.get(type);
                return mapperProxyFactory
.newInstance(sqlSession);
           
    }
public class MapperProxyFactory<T> {
    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface
.getClassLoader()
, new Class[]{this.mapperInterface}, mapperProxy);
    }
   }
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);
        }
    }

    interface MapperMethodInvoker {
        Object invoke(Object var1, Method var2, Object[] var3, SqlSession var4) throws Throwable;
    }

    private static class DefaultMethodInvoker implements MapperProxy.MapperMethodInvoker {
        private final MethodHandle methodHandle;

        public DefaultMethodInvoker(MethodHandle methodHandle) {
            this.methodHandle = methodHandle;
        }

        public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
            return this.methodHandle.bindTo(proxy).invokeWithArguments(args);
        }
    }

    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);
        }
    }
}
public class MapperMethod {
    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;
        }
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-25 23:07:16  更:2022-09-25 23:07:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:17:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码