Springboot integra el análisis del código fuente de mybatis

objetivo

En el último blog hablé de dos formas de integración, una de las palabras clave es

 1. 在mapper接口(dao接口)中,使用@Mapper注解,这种方式,无需使用配置类,无需使用@MapperScan注解,即可整合
 2. 在mapper接口中,使用@Repository注解或者不添加任务注解,在全配置类上添加@MapperScan注解,并指定要扫描的包
这篇博客, 我说下这两种整合方式的原理

Análisis de principios

En la integración,
si se usa la anotación @MapperScan, entonces: en la anotación, se introducirá la clase MapperScannerRegistrar a través de la anotación @Import, que implementa ImportBeanDefinitionRegistrar, por lo que escaneará cuando Spring escanee el paquete
Vaya a este método y ejecute el correspondiente método registerBeanDefinitions. En este método, el escaneo de la interfaz del mapeador se completa; si se usa el segundo método, la anotación @Mapper es completada por una clase interna de MybatisAutoConfiguration

Hay otra diferencia entre estos dos métodos: el primer método se realiza en las clases del paquete spring-mybatis.jar; el segundo método se realiza en el paquete mybatis-spring-boot-autoconfigure.jar

Qué es la integración, creo que es solo una oración, entregue la interfaz del mapeador de mybatis a la gestión de Spring.
A continuación, se muestran las cadenas de procesamiento correspondientes al primer y segundo método mencionados ayer.

# 这是第一种方式:通过@MapperScan注解
org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.annotation.AnnotationAttributes, org.springframework.beans.factory.support.BeanDefinitionRegistry)
	org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
		org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
			org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents


# 第二种方式  通过@Mapper注解
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar
	org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
		org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
			org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents

Primero hablemos de la segunda forma:
esta es la clase interna de MybatisAutoConfiguration, que se usa para determinar si es necesario inyectar anotaciones @Mapper y escanear la clase de procesamiento de la interfaz del mapeador.

下面这个内部类的其中一个注解是比较巧妙的
@Configuration
@Import({
    
    MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean({
    
    MapperFactoryBean.class})
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
    
    
    public MapperScannerRegistrarNotFoundConfiguration() {
    
    
    }
    public void afterPropertiesSet() {
    
    
        MybatisAutoConfiguration.logger.debug("No {} found.", MapperFactoryBean.class.getName());
    }
}

@ConditionalOnMissingBean ({MapperFactoryBean.class})
Esta anotación significa: si hay un MapperFactoryBean en el contenedor de primavera, esta clase no tendrá efecto y las anotaciones correspondientes no tendrán efecto. (
Eso es lo que significa) ¿ Cuándo lo hará el objeto MapperFactoryvBean? existen en el contenedor de primavera? Es muy simple, simplemente agregue una anotación @MapperScan a la clase de configuración, porque esta anotación obtendrá todas las interfaces de mapeador (interfaces dao) bajo el paquete actual al escanear las clases bajo el paquete, y establecerá la clase de frijol del beanDefinition de la interfaz de mapeador. el objeto se establece en MapperFactoryBean;

org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions方法中

definition.setBeanClass(this.mapperFactoryBean.getClass());

Aquí se explica cómo escanear, no entremos en detalles, escribiré un blog separado para describir los detalles del escaneo de mybatis, aquí solo necesitamos saber, si se agrega la anotación @MapperScan, la interfaz del mapeador escaneado está en primavera. todos los objetos MapperFactoryBean; la razón por la que beanClass de la interfaz del mapeador se establece en MapperFactoryBean es para generar el objeto proxy de la interfaz. Cuando el servicio inyecta la interfaz dao, el objeto proxy de dao se inyectará en el servicio. El objeto proxy está en MapperFactoryBean. Generado en el método getObject ()

Aquí sabemos que si escaneamos la interfaz del mapeador a través de la anotación @MapperScan, la clase interna AutoConfiguredMapperScannerRegistrar de MybatisAutoConfiguration no tendrá efecto y no escaneará

Entonces, ¿por qué dice que si no agrega la anotación @MapperScan, debe usar la anotación @Mapper para decorar la interfaz del mapeador? Porque hay tal línea de código en AutoConfiguredMapperScannerRegistrar

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");
        List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
        if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
    
    
            Iterator var4 = packages.iterator();

            while(var4.hasNext()) {
    
    
                String pkg = (String)var4.next();
                MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
            }
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        if (this.resourceLoader != null) {
    
    
            scanner.setResourceLoader(this.resourceLoader);
        }

				# 这里这行代码
        scanner.setAnnotationClass(Mapper.class);
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(packages));
    }
}

La línea de código anterior establecerá mapper.class en annotationClass, y luego agregará annotationClass para includeFilters en el método
sacnner.registerFilters ( ). AddIncludeFilter (new AnnotationTypeFilter (this.annotationClass));
acerca de includeFilters y excludeFilters, en el blog anterior El principio de escaneo de beans se menciona en el artículo . El significado general es: Después de que
Spring escanea todas las clases del paquete, es necesario filtrarlo. No es necesario inyectar todas las clases en el contenedor de resorte. Al filtrar, hay dos capas de filtrado, la
primera capa: filtrado según includeFilters y excludeFilters, los que cumplen includeFilters se pueden inyectar, y los que cumplen excludeFilters son la
segunda capa que no necesita inyectarse : porque spring y mybatis son clases e interfaces de escaneo respectivamente, por lo que , Es juzgado por diferentes condiciones

一、spring是调用的org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent(org.springframework.beans.factory.annotation.AnnotatedBeanDefinition)

		protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    
    
			AnnotationMetadata metadata = beanDefinition.getMetadata();
			/**
			 * spring在扫描普通bean,是用的这个方法,mybatis对该方法进行了扩展,mybatis判断一个beanDefinition是否要放到beanDefinitionMap中,是判断当前是否是接口,是否是顶级类(org.mybatis.spring.mapper.ClassPathMapperScanner#isCandidateComponent)
			 *
			 * isIndependent:当前类是否独立(顶级类或者嵌套类)
			 * isConcrete: 不是接口,不是抽象类,就返回true
			 * 如果bean是抽象类,且添加了@LookUp注解,也可以注入
			 * 使用抽象类+@LookUp注解,可以解决单实例bean依赖原型bean的问题,这里在spring官方文档中应该也有说明
			 */
			return (metadata.isIndependent() && (metadata.isConcrete() ||
					(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
		}


		ClassPathMapperScanner继承了ClassPathBeanDefinitionScanner
		ClassPathBeanDefinitionScanner继承了ClassPathScanningCandidateComponentProvider

二、mybatis是通过org.mybatis.spring.mapper.ClassPathMapperScanner#isCandidateComponent
		@Override
		protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    
    
		  // 判断beanDefinition是否是接口,或者是否是顶级类
		  return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
		}

Aquí está la relación de herencia de ClassPathMapperScanner, es decir, al escanear beans, el ClassPathMapperScanner de mybatis hereda el ClassPathMapperScanner de spring.
Inserte la descripción de la imagen aquí
Entonces, para resumir:
si no usamos la anotación MapperScan, debemos usar la anotación @Mapper para modificar la interfaz del mapeador. , porque si no se usa la anotación @MapperScan, el escaneo lo realiza AutoConfiguredMapperScannerRegistrar. Al escanear esta clase, se especifica includeFilters, que es Mapper.class; si nuestra interfaz de mapeador no está anotada con @Mapper, entonces todas las clases del paquete se escaneará Después de eso, cuando se filtre la primera capa, se filtrará

Si estamos usando la anotación @MapperScan, entonces no es necesario agregar la anotación @Mapper, porque la anotación @MapperScan introducirá MapperScannerRegistrar a través de la anotación de importación, y luego en la clase MapperScannerRegistrar, se escaneará la interfaz. no está en includeFilters Especifique que se deben usar las anotaciones @Mapper; por lo tanto, las anotaciones @Mapper no se pueden agregar

Supongo que te gusta

Origin blog.csdn.net/CPLASF_/article/details/107536970
Recomendado
Clasificación