Mybatis源码之XXMapper.java的扫描,然后注册IOC容器

xxMapper的扫描,然后注册IOC容器
注解中@Import的类获取

先看注解中@Import的类是如何获取。首先启动类中有@SpringBootApplication、@MapperScan注解,其中在ConfigurationClassParser#doProcessConfigurationClass()中会进行对@Import的处理,去调用processImports方法。

在看processImports之前,先看下启动类@MapperScan有什么作用,MapperScan上面的注解@Import又怎么import

protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
		throws IOException {

	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		processMemberClasses(configClass, sourceClass, filter);
	}

	// Process any @PropertySource annotations
	...

	// Process any @ComponentScan annotations
    ...

	// Process any @Import annotations
	processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
	
	// Process individual @Bean methods
	...
	// Process default methods on interfaces
	...
	// Process superclass, if any
	...
}

其中第三个入参为getImports(sourceClass),所以调用ConfigurationClassParser#getImports()

/**
 * Returns {@code @Import} class, considering all meta-annotations.
 */
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	Set<SourceClass> imports = new LinkedHashSet<>();
	Set<SourceClass> visited = new LinkedHashSet<>();
	collectImports(sourceClass, imports, visited);
	return imports;
}

再调用ConfigurationClassParser#collectImports()。所以先sourceClass为启动类,先对sourceClass.getAnnotations()获得的MapperScan进行判断,发现注解名字不是Import,继续把MapperScan作为sourceClass,从而此次获取注解中属性值MapperScannerRegistrar

private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
		throws IOException {

	if (visited.add(sourceClass)) {
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			String annName = annotation.getMetadata().getClassName();
			if (!annName.equals(Import.class.getName())) {
				collectImports(annotation, imports, visited);
			}
		}
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}

@MapperScan的源码

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

  /**
   * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
   * {@code @MapperScan("org.my.pkg")} instead of {@code @MapperScan(basePackages = "org.my.pkg"})}.
   *
   * @return base package names
   */
  String[] value() default {};
}
将@Import注解的类先在ConfigurationClass.importBeanDefinitionRegistrars中进行存储

接下来可以继续processImports分析。从上面分析可知,因为importCandidates会传入MapperScannerRegistrar,而它实现了ImportBeanDefinitionRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
}

所以会在ConfigurationClass.importBeanDefinitionRegistrars中进行缓存

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {

	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		......
	}
	else {
		this.importStack.push(configClass);
		try {
			for (SourceClass candidate : importCandidates) {
				......
				
				}
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
					// Candidate class is an ImportBeanDefinitionRegistrar ->
					// delegate to it to register additional bean definitions
					Class<?> candidateClass = candidate.loadClass();
					ImportBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
			}
		}
	}
}

下面是ConfigurationClass类源码

private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
		new LinkedHashMap<>();

public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
	this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
loadBeanDefinitionsFromRegistrars处理MapperScannerRegistrar

上面将MapperScannerRegistrar 在ConfigurationClass.importBeanDefinitionRegistrars中进行存储,所以在对BeanDefinition加载注册时,会进行loadBeanDefinitionsFromRegistrars处理

先贴下调用到此步的代码:

ConfigurationClassParser类中:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		...
		//上面分析都是通过此入口调用的,将自动配置一些类都放到ConfigurationClassParser.configurationClasses中
        parser.parse(candidates);
        ...
        //进行BeanDefinition的解析注册入口
        this.reader.loadBeanDefinitions(configClasses);
}

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

ConfigurationClassBeanDefinitionReader类中:
private void loadBeanDefinitionsForConfigurationClass(
		ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    ......
	loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
			

下面开始分析loadBeanDefinitionsFromRegistrars中过程。
遍历获取registrar,然后去调用MapperScannerRegistrar#registerBeanDefinitions()

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

在MapperScannerRegistrar#registerBeanDefinitions()将添加此BeanDefinition中basePackage属性值。

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
          generateBaseBeanName(importingClassMetadata, 0));
    }
  }
  
  void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
    //Bean类型为MapperScannerConfigurer.class
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    ......

    List<String> basePackages = new ArrayList<>();
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
        .collect(Collectors.toList()));

    if (basePackages.isEmpty()) {
      basePackages.add(getDefaultBasePackage(annoMeta));
    }

    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
    //将  启动类全路径#MapperScannerRegistrar#0
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }
}

最后将beanName为 启动类全路径#MapperScannerRegistrar#0在IOC容器中进行注册,Bean类型为MapperScannerConfigurer.class
名字生成逻辑是:

private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
    return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
}
@MapperScan注解中package下文件扫描并注册IOC容器

回到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(). 此次再去通过type(BeanDefinitionRegistryPostProcessor.class)能获取到上面存储的BeanDefinitionRegistryPostProcessor,此时再去invokeBeanDefinitionRegistryPostProcessors

// 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, beanFactory.getApplicationStartup());
	currentRegistryProcessors.clear();
}

此时postProcessor类型为上一步分析的MapperScannerConfigurer

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		
		postProcessor.postProcessBeanDefinitionRegistry(registry);
		
	}
}

调用MapperScannerConfigurer#postProcessBeanDefinitionRegistry(),对package中类进行扫描

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

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    ......
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

此时仍然调用spring的ClassPathBeanDefinitionScanner#scan()

public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	doScan(basePackages);
    ......
}

实际工作的是doscan,调用ClassPathMapperScanner#doScan(),再调用ClassPathBeanDefinitionScanner#doScan()

  @Override
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    ......
  }

将@MapperScan注解package下类注册到IOC容器

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
			    //package下的mapper注册到IOC容器
			    registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}
xxMapper代理类的生成

调用链:

AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#getObjectForBeanInstance() --> AbstractBeanFactory#getObjectForBeanInstance() --> FactoryBeanRegistrySupport#getObjectFromFactoryBean() --> FactoryBeanRegistrySupport#doGetObjectFromFactoryBean() --> MapperFactoryBean#getObject() --> SqlSessionTemplate#getMapper() --> Configuration#getMapper() --> MapperRegistry#getMapper() --> MapperProxyFactory#newInstance()

在AbstractBeanFactory#doGetBean() 创建bean 对象后,调用getObjectForBeanInstance,由于xxMapper是非&开头的FactoryBean,所以执行getObjectFromFactoryBean逻辑代码

// Create bean instance.
if (mbd.isSingleton()) {
	sharedInstance = getSingleton(beanName, () -> {
		try {
			return createBean(beanName, mbd, args);
		}
		...
	});
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

AbstractBeanFactory#getObjectForBeanInstance()

protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	//name为 & 开头的FactoryBean
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		......
		return beanInstance;
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	if (!(beanInstance instanceof FactoryBean)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd != null) {
		mbd.isFactoryBean = true;
	}
	else {
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

最后再看下MapperProxyFactory#newInstance(), 调用JDK Proxy.newProxyInstance()生成代理类,其中是由MapperProxy实现InvocationHandler,构造器中将SqlSession和被代理的mapperInterface传入

protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public class MapperProxy<T> implements InvocationHandler, Serializable {

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
}
springboot是一种基于Java的开发框架,用于快速构建和部署应用程序。MyBatis是一个持久化框架,用于在Java应用程序中访问数据库。 当在使用Springboot集成MyBatis过程中,出现java.lang.IllegalArgumentException: Property 'sqlSessionFactory'的异常时,一般是由以下几种原因引起的: 1. 配置文件错误:首先要检查application.properties或application.yml等配置文件中的MyBatis配置是否正确。可能是配置文件中的属性名拼写错误或者配置值类型不匹配导致的异常。 2. 依赖版本不匹配:MyBatis依赖的版本和Springboot整合的版本可能不兼容。需要确保所使用的MyBatis和Springboot版本是兼容的,并且存在正确的依赖关系。 3. 配置类缺失或错误:在Springboot中,我们可以使用@Configuration注解创建一个配置类,并使用@Bean注解创建SqlSessionFactoryBean。如果配置类缺失或者配置不正确,也可能导致此异常的出现。 4. 依赖缺失:在Maven或Gradle构建的项目中,如果没有正确定义MyBatis或Springboot相关的依赖,也有可能出现此异常。检查项目的依赖配置,确保相关依赖项已正确添加。 综上所述,发生java.lang.IllegalArgumentException: Property 'sqlSessionFactory'的异常时,需要检查配置文件、依赖版本、配置类以及依赖缺失等方面的问题,以确定引发异常的具体原因,并对相应的部分行排查和修改,从而解决该异常。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值