本文先从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并完成代理的过程