SpringBoot: MyBatis之MapperScan注解实现原理

SpringBoot: MyBatis之MapperScan注解实现原理

使用Mybatis和spring集成常用2种方式,一种是xml配置。另一种就是注解,这一章我们从注解说起。代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Documented

@Import(MapperScannerRegistrar.class)

public @interface MapperScan {}我们不在xml配置的话,必须通过MapperScan来扫描。扫描注册的类就是MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar并重写registerBeanDefinitions

代码语言:javascript复制public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

private ResourceLoader resourceLoader;

/**

* {@inheritDoc}

*/

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

//拿到MapperScan类里面的属性

AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));

//获得spring的注册器registry

ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

// this check is needed in Spring 3.1

if (resourceLoader != null) {

scanner.setResourceLoader(resourceLoader);

}

Class annotationClass = annoAttrs.getClass("annotationClass");

if (!Annotation.class.equals(annotationClass)) {

scanner.setAnnotationClass(annotationClass);

}

Class markerInterface = annoAttrs.getClass("markerInterface");

if (!Class.class.equals(markerInterface)) {

scanner.setMarkerInterface(markerInterface);

}

Class generatorClass = annoAttrs.getClass("nameGenerator");

if (!BeanNameGenerator.class.equals(generatorClass)) {

scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));

}

Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");

if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {

scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));

}

scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));

scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

List basePackages = new ArrayList();

for (String pkg : annoAttrs.getStringArray("value")) {

if (StringUtils.hasText(pkg)) {

basePackages.add(pkg);

}

}

//如果配置了包路径则将入进去

for (String pkg : annoAttrs.getStringArray("basePackages")) {

if (StringUtils.hasText(pkg)) {

basePackages.add(pkg);

}

}

for (Class clazz : annoAttrs.getClassArray("basePackageClasses")) {

basePackages.add(ClassUtils.getPackageName(clazz));

}

scanner.registerFilters();

//具体执行扫描

scanner.doScan(StringUtils.toStringArray(basePackages));

}

/**

* {@inheritDoc}

*/

@Override

public void setResourceLoader(ResourceLoader resourceLoader) {

this.resourceLoader = resourceLoader;

}

}然后我们进入ClassPathMapperScanner#doScan方法调用父类ClassPathBeanDefinitionScanner#doScan来实现扫描并注册到spring ioc中

代码语言:javascript复制//ClassPathMapperScanner

public Set doScan(String... basePackages) {

Set beanDefinitions = super.doScan(basePackages);

if (beanDefinitions.isEmpty()) {

logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");

} else {

processBeanDefinitions(beanDefinitions);

}

return beanDefinitions;

}

//ClassPathBeanDefinitionScanner

protected Set doScan(String... basePackages) {

Assert.notEmpty(basePackages, "At least one base package must be specified");

Set beanDefinitions = new LinkedHashSet();

//获取配置的路径下面所有的mapper全限定类名

for (String basePackage : basePackages) {

Set candidates = findCandidateComponents(basePackage);

for (BeanDefinition candidate : candidates) {

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);

candidate.setScope(scopeMetadata.getScopeName());

//获取beanName

String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

if (candidate instanceof AbstractBeanDefinition) {

postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);

}

//是否懒加载、是否为主键等

if (candidate instanceof AnnotatedBeanDefinition) {

AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);

}

//是否beanName查看是否存在以及注册过

if (checkCandidate(beanName, candidate)) {

//包装一下

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);

definitionHolder =

AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

//将入到当前列表中

beanDefinitions.add(definitionHolder);

//注册到IOC中

registerBeanDefinition(definitionHolder, this.registry);

}

}

}

return beanDefinitions;

}之前博客中讲到IOC这些东西,相信大家看到这里就大致清楚了。

总结我们使用MapperScan注解时,会将包路径一起设置进入。通过扫描MapperScan注解的类,通过AnnotationConfigUtils.processCommonDefinitionAnnotations来解析。然后包装为BeanDefinitionHolder,然后注册到Spring IOC里面。

相关推荐

绝地求生ep是什么
38365365.com打不开

绝地求生ep是什么

⌛ 07-18 👁️ 3110
hard模式是什么意思?hard模式外还有什么模式?
义乌365人工客服电话多少

hard模式是什么意思?hard模式外还有什么模式?

⌛ 08-23 👁️ 2346
樊於的读音是什么字(樊於期qi还是ji)
义乌365人工客服电话多少

樊於的读音是什么字(樊於期qi还是ji)

⌛ 08-10 👁️ 4428