spring整合mybatis-plus

基于 spring-boot-2.3.2.RELEASE 和  mybatis-spring-1.3.2

1、为了让mybatis的mapper接口扫描病注册到spring容器中,有两种方案:使用@MapperScan或者使用@Mapper

2、我们今天查看源码就从@MapperScan开始

3、查看注解@MapperScan发现导入了 MapperScannerRegistrar

@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
    String[] value() default {};

    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;
}

4、MapperScannerRegistrar类实现了ImportBeanDefinitionRegistrar接口,spring启动时会调用MapperScannerRegistrar#registerBeanDefinitions方法

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    //初始化Mapper接口扫描器
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    if (this.resourceLoader != null) {
        scanner.setResourceLoader(this.resourceLoader);
    }
    // 1. 处理注解过滤(默认是 @Mapper 注解),如下:
    /**
     * public interface MyMarkerInterface {
     * }
     * public interface UserMapper extends MyMarkerInterface { ... }
     * @MapperScan(
     *     basePackages = "com.example.mapper",
     *     markerInterface = MyMarkerInterface.class  // 这里指定自定义标记接口
     * )
     */
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
        scanner.setAnnotationClass(annotationClass);
    }
    // 2. 处理标记接口过滤(可选,通过接口继承过滤),如下:
    /**
     * // 自定义一个注解
     * @Target(ElementType.TYPE)
     * @Retention(RetentionPolicy.RUNTIME)
     * public @interface MyCustomMapper {
     * }
     * @MyCustomMapper
     * public interface UserMapper { ... }
     * @MapperScan(
     *     basePackages = "com.example.mapper",
     *     annotationClass = MyCustomMapper.class  // 这里指定自定义注解
     * )
     */
    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
        scanner.setMarkerInterface(markerInterface);
    }
    // 1. 配置 Bean 名称生成器
    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
        scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
    }
    // 2. 配置 Mapper 工厂 Bean(默认是 MapperFactoryBean)
    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
        scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }
    
    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
    List<String> basePackages = new ArrayList();
    String[] var10 = annoAttrs.getStringArray("value");
    ...
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
}

5、继续查看ClassPathMapperScanner#doScan方法

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    //ClassPathMapperScanner#addIncludeFilter实现扫描Mapper接口
    /**
     * this.addIncludeFilter(new TypeFilter() {
     *   public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
     *       return true;
     *   }
     * });
     * protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
     *     return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
     * }    
     */
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    if (beanDefinitions.isEmpty()) {
        this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
    } else {
        //继续查看ClassPathMapperScanner#processBeanDefinitions方法
        this.processBeanDefinitions(beanDefinitions);
    }
    return beanDefinitions;
}

6、继续查看ClassPathMapperScanner#processBeanDefinitions方法,发现Mapper接口的beanDefinition的beanClass属性被注册为mapperFactoryBean

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    Iterator var3 = beanDefinitions.iterator();
    //扫描到的接口注册bean定义信息的beanClass为mapperFactoryBean
    //设置mapperFactoryBean的构造函数为Mapper
    //设置bean定义信息的autowireMode为AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE
    //最后Mapper的代理对象通过MapperFactoryBean#getObject获取
    while(var3.hasNext()) {
        BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
        GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
        ...
        definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
        definition.setBeanClass(this.mapperFactoryBean.getClass());
        definition.getPropertyValues().add("addToConfig", this.addToConfig);
        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)) {
            ...
            definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
            explicitFactoryUsed = true;
        } else if (this.sqlSessionTemplate != null) {
            ...
            definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
            explicitFactoryUsed = true;
        }

        if (!explicitFactoryUsed) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
            }

            definition.setAutowireMode(2);
        }
    }
}

总结:

1、通过@MapperScan导入了MapperScannerRegistrar类 

2、spring启动时会调用MapperScannerRegistrar#registerBeanDefinitions方法

3、在registerBeanDefinitions方法中定义了ClassPathMapperScanner用来扫描Mapper的beanDefinition

4、ClassPathMapperScanner重写isCandidateComponent方法,指定只扫描接口

5、最终把spring扫描得到的beanDefinition#beanClass属性设置为MapperFactoryBean,并把AutowireMode修改为byType

6、最终spring ioc通过MapperFactoryBean#getObject方法生成一个Mapper接口的代理对象,成为spring中的bean

7、一个userMapper.selectById的执行过程

/**
     * sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
     *         new Class[] { SqlSession.class }, new SqlSessionInterceptor());
     */
userMapper#selectById -> sqlSessionTemplate#selectOne -> sqlSessionProxy#selectOne -> defaultSqlSession#selectOne

 8、为什么spring整合mybatis后,一级缓存会失效

mybatis中一级缓存是基于SqlSession来实现的,在执行一个sql时,如果使用的同一个SqlSession对象,那么就能使用到一级缓存。

在spring整合mybatis后,如果方法上没有开启事务(如@Transactional),那么在方法中每执行一个sql就会新创建一个SqlSession对象来执行该sql,这就是我们说的一级缓存失效,而如果开启了事务,那么在同一个事务内就会使用同一个SqlSession对象执行多个sql,因此一级缓存生效。

在spring中一级缓存生效具体代码:

private class SqlSessionInterceptor implements InvocationHandler {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //在spring中,获取SqlSession对象逻辑,会判断是否开启事务,开启事务则返回同一个SqlSession对象
    SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
    try {
      Object result = method.invoke(sqlSession, args);
      if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        sqlSession.commit(true);
      }
      return result;
    } catch (Throwable t) {
      ...
    } finally {
      if (sqlSession != null) {
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
      }
    }
  }
}        
//继续查看SqlSessionUtils#getSqlSession
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {
  ...
  //通过TransactionSynchronizationManager#resources获取上下文中的资源对象 
  SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

  SqlSession session = sessionHolder(executorType, holder);
  if (session != null) {
    return session;
  }

  session = sessionFactory.openSession(executorType);

  registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

  return session;
}
//继续查看TransactionSynchronizationManager#getResource方法
public static Object getResource(Object key) {
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    //最终通过TransactionSynchronizationManager#resources获取包含sqlSession的对象
    Object value = doGetResource(actualKey);
    ...
    return value;
}

 

posted @ 2025-09-12 18:13  西风51668  阅读(28)  评论(0)    收藏  举报