概述
目录
- 1、前言
- 2、@MapperScan注解
- 3、MapperScannerRegistrar
- 4、MapperScannerConfigurer
- 5、ClassPathMapperScanner
1、前言
主要是MapperScannerConfigurer类,这是一个后置处理器,用于后置处理beanDefinition,这个类在bean开始创建之前将扫描到的mapper的beanDefinition的beanClass属性替换为MapperFactoryBean类,beanName还是mapper的name。spring创建类是根据beanDefinition定义的beanClass属性来反射创建对象的。然后以(beanName:根据beanClass创建的对象)为key和value对,放入singletonObjects中。
此时singletonObjects中放的是正常的mapper的beanName(即xxxMapper)和MapperFactoryBean实例
在注入mapper属性时,如果根据mapper的beanDefinition判断是FactoryBean类型,那么调用对应的FactoryBean单例对象的getObject方法,并将结果注入mapper。
MapperFactoryBean间接实现了InitializingBean接口,在接口方法中addMapper
而MapperFactoryBean的getObject方法为
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
如上,最终调用的sqlsessionTemplate.getMapper方法。最终会调用MapperRegistry.getMapper方法。
2、@MapperScan注解
我们在启动类上加@MapperScanner注解,而@MapperScanner注解上方有@Import注解,此注解在ConfigurationClassPostProcessor后置处理器的后置处理方法中被解析,将@Import注解引入的类包装成BeanDefinition注册到spring
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
// ...
}
3、MapperScannerRegistrar
@MapperScanner注解引入了MapperScannerRegistrar类,此类实现了ImportBeanDefinitionRegistrar接口,解析阶段会调用registerBeanDefinitions方法。
registerBeanDefinitions方法会为MapperScannerConfigurer类生成BeanDefintion并注入spring。
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
/**
* {@inheritDoc}
*
* @deprecated Since 2.0.2, this method not used never.
*/
@Override
@Deprecated
public void setResourceLoader(ResourceLoader resourceLoader) {
// NOP
}
/**
* {@inheritDoc}
*/
@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));
}
}
// 生成MapperScannerConfigurer的BeanDefinition并注入spring
void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
// 此属性一般为Mapper注解
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
if (StringUtils.hasText(sqlSessionFactoryRef)) {
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
}
List<String> basePackages = new ArrayList<>();
basePackages.addAll(
Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
// Mapper的位置
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
.collect(Collectors.toList()));
// 以类的形式表达Mapper的位置,比如我们将一个com.demo.mapper.XXXPackage类标注basePackageClasses属性,
// 么会截取com.demo.mapper作为mapper的位置
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
.collect(Collectors.toList()));
// 如果没有上面俩个属性,那么默认拿含有@MapperScanner注解的类所在包作为Mapper位置。
if (basePackages.isEmpty()) {
basePackages.add(getDefaultBasePackage(annoMeta));
}
String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
// ...
}
4、MapperScannerConfigurer
MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,在上面的MapperScannerRegistrar类的registerBeanDefinitions方法执行完以后,MapperScannerConfigurer的BeanDefinition就被注册到了spring,在refresh方法中的invokeBeanFactoryPostProcessors阶段被调用其postProcessBeanDefinitionRegistry方法。
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
// ...
// 在BeanDefinitionRegistryPostProcessor后置方法中扫描所有mapper的beanDefinition,
// 并将其beanClass替换为MapperFactoryBean
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
// ClassPathMapperScanner继承并重写了doScan方法
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(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
scanner.registerFilters();
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
//...
}
5、ClassPathMapperScanner
ClassPathMapperScanner,扫描所有mapper的beanDefinition,并将其beanClass替换为MapperFactoryBean,这样我们在Service中@Autowired我们的mapper时候,其实是将MapperFactoryBean.getObject()方法的返回设置为mapper属性。
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
// ...
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 这里扫描的是所有的Mapper
Set<BeanDefinitionHolder> 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;
}
// 偷天换日,将mapper对应beanDefinition的beanClass属性替换为MapperFactoryBean.class
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
// 将代表Mapper的Class换成MapperFactoryBean.class,这样在我们@Autowired一个Mapper的时候,实际上获取的是
// MapperFactoryBean.getObject()的结果
definition.setBeanClass(this.mapperFactoryBeanClass);
// 为MapperFactoryBean设置addToConfig属性
definition.getPropertyValues().add("addToConfig", this.addToConfig);
// 为MapperFactoryBean设置sqlSessionFactory属性
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory",
new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
// 为MapperFactoryBean设置sqlSessionTemplate属性
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
LOGGER.warn(
() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate",
new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(
() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
// 如果没有sqlSessionTemplate属性或者sqlSessionFactory属性,那么就使用spring的AUTOWIRE_BY_TYPE进行属性注入
// spring注入的时候会遍历属性的set方法,如果有set方法并且不是set基础类型那么就会从容器中获取set方法参数类型的bean进行属性注入
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
// ...
}
最后
以上就是真实柜子为你收集整理的源码-mybatis-spring:2.0.41、前言2、@MapperScan注解3、MapperScannerRegistrar4、MapperScannerConfigurer5、ClassPathMapperScanner的全部内容,希望文章能够帮你解决源码-mybatis-spring:2.0.41、前言2、@MapperScan注解3、MapperScannerRegistrar4、MapperScannerConfigurer5、ClassPathMapperScanner所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复