Spring整合MyBatis实现Mapper代理源码解析

  • Post author:
  • Post category:其他


本文先从Mybatis的角度,分析Mybatis扫描并生成代理Mapper的流程,后面再分析每一步是怎么整合到Spring容器生命周期中的

以AnnotationConfigApplicationContext 为例,在启动类上添加@MapperScan注解指定要扫描的mapper路径

@MapperScan("com.test.mapper")
public class AppConfig {
}
public static void main(String[] args) {
    AnnotationConfigApplicationContext context  = new AnnotationConfigApplicationContext();
    context.register(AppConfig.class);
    context.refresh();
}

MapperScan注解:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {

通过@Import导入了一个类MapperScannerRegistrar,它实现了ImportBeanDefinitionRegistrar接口(这个@Import会在spring容器refresh过程中的invokeBeanFactoryPostProcessors方法被解析并处理,后面再分析)

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

ImportBeanDefinitionRegistrar接口中只有一个方法:

public interface ImportBeanDefinitionRegistrar {

	/**
	 * Register bean definitions as necessary based on the given annotation metadata of
	 * the importing {@code @Configuration} class.
	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
	 * registered here, due to lifecycle constraints related to {@code @Configuration}
	 * class processing.
	 * @param importingClassMetadata annotation metadata of the importing class
	 * @param registry current bean definition registry
	 */
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

看下MapperScannerRegistrar 中对这个方法的实现:

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
        this.registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
    }

}

然后调用了内部同名的重载方法:

void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {  
		
	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
	....
	....
	registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}

主要看这个方法的开头和结尾,生成了一个类型为MapperScannerConfigurer的BeanDefinition,并注册到容器中

这个MapperScannerConfigurer类实现了BeanDefinitionRegistryPostProcessor接口(这个类在spring解析完@Import后就注册到了容器中,然后spring会依次取出并处理,同样后面再分析):

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

BeanDefinitionRegistryPostProcessor接口中有一个方法postProcessBeanDefinitionRegistry

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

看下MapperScannerConfigurer 对这个方法的实现:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();
        }

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

        scanner.registerFilters();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }

新建了一个扫描器,最后调用了扫描器的scan方法,这个方法在父类ClassPathBeanDefinitionScanner中

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
/**
 * Perform a scan within the specified base packages.
 * @param basePackages the packages to check for annotated classes
 * @return number of beans registered
 */
public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	doScan(basePackages);

	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

scan中调用了doScan方法,这个方法在Mybatis自己的ClassPathMapperScanner 中是有实现的:

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

先调用父类的doScan方法,获取了一个BeanDefinition的集合,再调用processBeanDefinitions方法对这个集合做处理

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
	for(Iterator var3 = beanDefinitions.iterator(); var3.hasNext(); definition.setLazyInit(this.lazyInitialization)) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
            ...
            ...
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
            definition.setBeanClass(this.mapperFactoryBeanClass);
     }
 }

其中,将每个BeanDefinition的BeanClass改成了MapperFactoryBeanClass,这是一个FactoryBean的实现,同时将真正的className设置到构造器参数里

private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    private Class<T> mapperInterface;
    private boolean addToConfig = true;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

即真正的className设置到了MapperFactoryBean的属性mapperInterface中,这样后续Spring容器实例化bean的时候,从beanDefinitionMap中获取到的mapper是一个FactoryBean类型,会生成代理对象,代理的类型就是其中的mapperInterface的类型

看MapperFactoryBean的getObject方法:

public T getObject() throws Exception {
    return this.getSqlSession().getMapper(this.mapperInterface);
}

跟进去发现getMapper是SqlSession接口的方法

在这里插入图片描述

上面两个都是ibatis的包,我们看SqlSessionTemplate的实现:

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

继续走,到了ibatis.Configuration.class中

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}

调用MapperRegistry.getMapper方法

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 {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

里面有一行代码new Instance,点进去,来到MapperProxyFactory中:

public T newInstance(SqlSession sqlSession) {
    MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}

调用了this.new Instance:

protected T newInstance(MapperProxy<T> mapperProxy) {
    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

终于见到这行代码了,Proxy.newProxyInstance,mapper的代理类就是这里创建的

到此为止,我们梳理了Mybatis从扫描mapper,到创建mapper代理的大概流程,现在的问题是,这些流程是怎么跟Spring的声明周期结合在一起呢?比如最开始的@Import注解,Spring是什么时候解析这个类,并一步步地调用Myabtis的组件,生成mapper放到容器中呢

接下来看容器的初始化流程,新建容器的时候首先会初始化内部的AnnotatedBeanDefinitionReader,它可以将类注册到容器中,是spring容器初始化过程中的重要组件

public AnnotationConfigApplicationContext() {
   	this.reader = new AnnotatedBeanDefinitionReader(this);
   	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

reader的初始化过程:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
   	this(registry, getOrCreateEnvironment(registry));
}

调用了重载的构造函数,getOrCreateEnvironment是获取环境变量、系统变量信息的,暂时不管,进入重载的构造器

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	Assert.notNull(environment, "Environment must not be null");
	this.registry = registry;
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

重点看最后一行

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}

又是一个重载的构造器,继续跟进

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
	...
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}
	...
}

这段代码,查看容器中是否存在一个名为org.springframework.context.annotation.internalConfigurationAnnotationProcessor

的bean,如果不存在,则新建一个类型为ConfigurationClassPostProcessor

的BeanDefinition,调用registerPostProcessor方法将其注册到容器中,这个类实现了BeanDefinitionRegistryPostProcessor接口和PriorityOrdered接口

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

也就是说,在容器AnnotationConfigApplicationContext初始化的时候,会new出一个AnnotatedBeanDefinitionReader,这个reader初始化完成后,容器内就存在一个实现了BeanDefinitionRegistryPostProcessor

接口的类ConfigurationClassPostProcessor

接下来容器继续初始化流程,调用refresh方法,其中一个步骤invokeBeanFactoryPostProcessors会对上面这个类进行处理

查看refresh中的invokeBeanFactoryPostProcessors方法:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

内部调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
	...
	...
	// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
	String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
			processedBeans.add(ppName);
		}
	}
	sortPostProcessors(currentRegistryProcessors, beanFactory);
	registryProcessors.addAll(currentRegistryProcessors);
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	currentRegistryProcessors.clear();		
	...
	// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
	...
	// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.

分析这段代码,先根据类型,从容器中查出BeanDefinitionRegistryPostProcessor类型的bean,判断其是否实现了PriorityOrdered接口,将符合条件的bean收集到集合中,然后调用invokeBeanDefinitionRegistryPostProcessors方法

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessBeanDefinitionRegistry(registry);
	}
}

在其中依次调用目标bean的postProcessBeanDefinitionRegistry方法

上面注册到容器的ConfigurationClassPostProcessor正是符合条件的类,回过头来看下其postProcessBeanDefinitionRegistry方法的实现:

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
	}

进入最后一行processConfigBeanDefinitions方法

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	...
	...
	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	...
	...
	Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
	...
	...
	this.reader.loadBeanDefinitions(configClasses);
		
	}

这里解析了配置类,加载BeanDefinition

进入loadBeanDefinitions方法

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
	for (ConfigurationClass configClass : configurationModel) {
		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
	}
}

循环调用loadBeanDefinitionsForConfigurationClass,继续跟进

private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
	...
	...
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

解析实现了ImportBeanDefinitionRegistrars接口的@Import,并调用其registerBeanDefinitions

方法

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
	registrars.forEach((registrar, metadata) ->
			registrar.registerBeanDefinitions(metadata, this.registry));
}

到此,就完成了对MyBatis的@MapperScan注解的解析,结果如文章开头部分所述,向容器中注册了一个MapperScannerConfigurer,它同样实现了BeanDefinitionRegistryPostProcessor接口

回到refresh流程中的invokeBeanFactoryPostProcessors,这个方法里反复加载了BeanDefinitionRegistryPostProcessor类型的bean,可以看注释//First就是第一次加载,也就是我们刚才分析的过程,向容器注册了MapperScannerConfigurer

第二次是//next注解标注的,它从容器取出了BeanDefinitionRegistryPostProcessor,并判断是否实现了Ordered接口

	// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
	postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
	for (String ppName : postProcessorNames) {
		if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
			currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
			processedBeans.add(ppName);
		}
	}
	sortPostProcessors(currentRegistryProcessors, beanFactory);
	registryProcessors.addAll(currentRegistryProcessors);
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
	currentRegistryProcessors.clear();

通过Mybatis的@MapperScan注册进来的MapperScannerConfigurer并没有实现Ordered接口,所以我们跳过,看最后一次

	// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
	boolean reiterate = true;
	while (reiterate) {
		reiterate = false;
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (!processedBeans.contains(ppName)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
				reiterate = true;
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();
	}

这次找到的bean中就包含了MapperScannerConfigurer,继续调用其postProcessBeanDefinitionRegistry方法,也就是文章上面,扫描mapper并完成代理的过程



版权声明:本文为m0_37298252原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。