作用
根据@MapperScan注解配置的包路径,扫描所有mapper接口,创建BeanDefinition对象,修改beanClass属性值为MapperFactoryBean,注册到Spring容器中,为后续Bean初始化做准备。
流程
@MapperScan注解通过@Import方法导入MapperScannerRegistrar类,MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,覆写了registerBeanDefinitions方法,作用为手动注册某个Bean的BeanDefinition到容器中【DefaultListableBeanFactory=>beanDefinitionMap】。
ImportBeanDefinitionRegistrar接口是Spring的扩展点之一,Spring容器启动时会回调所有实现了ImportBeanDefinitionRegistrar接口的实现类中的registerBeanDefinitions方法,完成自定义BeanDefinition注册。
MapperScannerRegistrar的registerBeanDefinitions方法手动将MapperScannerConfigurer类通过这种方式将自己的BeanDefinition实例注册到了容器中,为下一步Bean初始化做准备。
MapperScannerConfigurer类实现了BeanDefinitionRegistryPostProcessor接口,该接口也是Spring的扩展点之一,Spring容器启动时会回调所有实现了BeanDefinitionRegistryPostProcessor接口的实现类中的postProcessBeanDefinitionRegistry方法,进行BeanDefinition注册的后置处理,可以修改BeanDefinition对象。
在MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法中创建了ClassPathMapperScanner对象,该对象对@MapperScan注解中配置的包路径进行了扫描,为每个mapper接口创建对应的BeanDefinition实例,并修改所有实例中的beanClass属性值为MapperFactoryBean,autoWireMode为byType。
将所有mapper接口的BeanDefinition实例注册到Spring的容器中,为下一步实例化mapper接口做准备。
MapperFactoryBean是一个很关键的类,MapperFactryBean集成了SqlSessionDaoSupport类,实现了FactoryBean接口,覆写了getObject()方法。
FactoryBean类型的Bean,在进行Bean初始化时,会通过调用自己的getObject()方法,获取对象;而MapperFactoryBean覆写后的getObject()方法,实际执行的是getSqlSession().getMapper(this.mapperInterface),通过此方法衔接到Mybaits,以JDK动态代理的方式,创建了一个代理对象,最后将代理对象注册到了Spring容器中。
时序图
Spring扩展点ImportBeanDefinitionRegistrar
publicinterfaceImportBeanDefinitionRegistrar{/***Registerbeandefinitionsasnecessarybasedonthegivenannotationmetadataof*theimporting{@code@Configuration}class.*<p>Notethat{@linkBeanDefinitionRegistryPostProcessor}typesmay<em>not</em>be*registeredhere,duetolifecycleconstraintsrelatedto{@code@Configuration}*classprocessing.*@paramimportingClassMetadataannotationmetadataoftheimportingclass*@paramregistrycurrentbeandefinitionregistry*///通过@Import的方式注册Bean定义publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry);}
Spring扩展点BeanDefinitionRegistryPostProcessor
publicinterfaceBeanDefinitionRegistryPostProcessorextendsBeanFactoryPostProcessor{/***Modifytheapplicationcontext'sinternalbeandefinitionregistryafterits*standardinitialization.Allregularbeandefinitionswillhavebeenloaded,*butnobeanswillhavebeeninstantiatedyet.Thisallowsforaddingfurther*beandefinitionsbeforethenextpost-processingphasekicksin.*@paramregistrythebeandefinitionregistryusedbytheapplicationcontext*@throwsorg.springframework.beans.BeansExceptionincaseoferrors*///Bean定义注册完毕之后,进行后置处理voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry)throwsBeansException;}
注解@MapperScacn定义
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(MapperScannerRegistrar.class)@Repeatable(MapperScans.class)public@interfaceMapperScan{String[]value()default{};String[]basePackages()default{};Class<?>[]basePackageClasses()default{};Class<?extendsBeanNameGenerator>nameGenerator()defaultBeanNameGenerator.class;Class<?extendsAnnotation>annotationClass()defaultAnnotation.class;Class<?>markerInterface()defaultClass.class;StringsqlSessionTemplateRef()default"";StringsqlSessionFactoryRef()default"";Class<?extendsMapperFactoryBean>factoryBean()defaultMapperFactoryBean.class;StringlazyInitialization()default"";}
通过@Import注解,导入了MapperScannerRegistrar类
value、basePackages作用一致,用于声明待扫描的mapper层包路径,支持多组。
basePackageClasses用于指定扫描某个类所在包下的所有组件。(@SpringBootApplication标识的启动类)
factoryBean:指定FactoryBean实现类,用于生成接口代理类,默认为MapperFactoryBean.class, 支持自定义。
MapperScannerRegistrar相关
该类实现了ImportBeanDefinitionRegistrar接口,在启动时回调registerBeanDefinitions方法注册MapperScannerConfigurer.class的BeanDefinition到容器中。
关于ImportBeanDefinitionRegistrar:Spring扩展点之一,启动时会回调被覆盖的registerBeanDefinitions方法,注册BeanDefinition到容器。
@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){AnnotationAttributesmapperScanAttrs=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));if(mapperScanAttrs!=null){registerBeanDefinitions(mapperScanAttrs,registry,generateBaseBeanName(importingClassMetadata,0));}}voidregisterBeanDefinitions(AnnotationAttributesannoAttrs,BeanDefinitionRegistryregistry,StringbeanName){//建造者模式创建MapperScannerConfigurerBean定义对象BeanDefinitionBuilderbuilder=BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders",true);Class<?extendsAnnotation>annotationClass=annoAttrs.getClass("annotationClass");if(!Annotation.class.equals(annotationClass)){builder.addPropertyValue("annotationClass",annotationClass);}Class<?>markerInterface=annoAttrs.getClass("markerInterface");if(!Class.class.equals(markerInterface)){builder.addPropertyValue("markerInterface",markerInterface);}Class<?extendsBeanNameGenerator>generatorClass=annoAttrs.getClass("nameGenerator");if(!BeanNameGenerator.class.equals(generatorClass)){builder.addPropertyValue("nameGenerator",BeanUtils.instantiateClass(generatorClass));}Class<?extendsMapperFactoryBean>mapperFactoryBeanClass=annoAttrs.getClass("factoryBean");if(!MapperFactoryBean.class.equals(mapperFactoryBeanClass)){builder.addPropertyValue("mapperFactoryBeanClass",mapperFactoryBeanClass);}StringsqlSessionTemplateRef=annoAttrs.getString("sqlSessionTemplateRef");if(StringUtils.hasText(sqlSessionTemplateRef)){builder.addPropertyValue("sqlSessionTemplateBeanName",annoAttrs.getString("sqlSessionTemplateRef"));}StringsqlSessionFactoryRef=annoAttrs.getString("sqlSessionFactoryRef");if(StringUtils.hasText(sqlSessionFactoryRef)){builder.addPropertyValue("sqlSessionFactoryBeanName",annoAttrs.getString("sqlSessionFactoryRef"));}List<String>basePackages=newArrayList<>();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()));StringlazyInitialization=annoAttrs.getString("lazyInitialization");if(StringUtils.hasText(lazyInitialization)){builder.addPropertyValue("lazyInitialization",lazyInitialization);}builder.addPropertyValue("basePackage",StringUtils.collectionToCommaDelimitedString(basePackages));registry.registerBeanDefinition(beanName,builder.getBeanDefinition());}
MapperScannerConfigurer相关
该类实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor也是Spring的扩展点之一,启动时回调被覆盖的postProcessBeanDefinitionRegistry方法。在回调方法中创建了ClassPathMapperScanner对象,并调用doScan(basePackages)方法对@MapperScacn中的包路径进行扫描创建、并修改BeanDefinition。
ClassPathMapperScanner相关
publicintscan(String...basePackages){intbeanCountAtScanStart=this.registry.getBeanDefinitionCount();doScan(basePackages);//Registerannotationconfigprocessors,ifnecessary.if(this.includeAnnotationConfig){AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return(this.registry.getBeanDefinitionCount()-beanCountAtScanStart);}@OverridepublicSet<BeanDefinitionHolder>doScan(String...basePackages){Set<BeanDefinitionHolder>beanDefinitions=super.doScan(basePackages);if(beanDefinitions.isEmpty()){LOGGER.warn(()->"NoMyBatismapperwasfoundin'"+Arrays.toString(basePackages)+"'package.Pleasecheckyourconfiguration.");}else{processBeanDefinitions(beanDefinitions);}returnbeanDefinitions;}
扫描mapper层所有接口的Bean定义,设置beanClass和autoWireMode。
privatevoidprocessBeanDefinitions(Set<BeanDefinitionHolder>beanDefinitions){GenericBeanDefinitiondefinition;for(BeanDefinitionHolderholder:beanDefinitions){definition=(GenericBeanDefinition)holder.getBeanDefinition();StringbeanClassName=definition.getBeanClassName();LOGGER.debug(()->"CreatingMapperFactoryBeanwithname'"+holder.getBeanName()+"'and'"+beanClassName+"'mapperInterface");//themapperinterfaceistheoriginalclassofthebean//but,theactualclassofthebeanisMapperFactoryBeandefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);//issue#59//1.设置beanClass为MapperFactoryBeandefinition.setBeanClass(this.mapperFactoryBeanClass);definition.getPropertyValues().add("addToConfig",this.addToConfig);booleanexplicitFactoryUsed=false;if(StringUtils.hasText(this.sqlSessionFactoryBeanName)){definition.getPropertyValues().add("sqlSessionFactory",newRuntimeBeanReference(this.sqlSessionFactoryBeanName));explicitFactoryUsed=true;}elseif(this.sqlSessionFactory!=null){definition.getPropertyValues().add("sqlSessionFactory",this.sqlSessionFactory);explicitFactoryUsed=true;}if(StringUtils.hasText(this.sqlSessionTemplateBeanName)){if(explicitFactoryUsed){LOGGER.warn(()->"Cannotuseboth:sqlSessionTemplateandsqlSessionFactorytogether.sqlSessionFactoryisignored.");}definition.getPropertyValues().add("sqlSessionTemplate",newRuntimeBeanReference(this.sqlSessionTemplateBeanName));explicitFactoryUsed=true;}elseif(this.sqlSessionTemplate!=null){if(explicitFactoryUsed){LOGGER.warn(()->"Cannotuseboth:sqlSessionTemplateandsqlSessionFactorytogether.sqlSessionFactoryisignored.");}definition.getPropertyValues().add("sqlSessionTemplate",this.sqlSessionTemplate);explicitFactoryUsed=true;}if(!explicitFactoryUsed){LOGGER.debug(()->"EnablingautowirebytypeforMapperFactoryBeanwithname'"+holder.getBeanName()+"'.");//2.设置autoWireMode=byTypedefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);}definition.setLazyInit(lazyInitialization);}}
设置beanClass为MapperFactryBean
设置autoWireMode=byType
No:即不启用自动装配。Autowire默认的值。
byName:通过属性的名字的方式查找JavaBean依赖的对象并为其注入。比如说类Computer有个属性printer,指定其autowire属性为byName后,Spring IoC容器会在配置文件中查找id/name属性为printer的bean,然后使用Seter方法为其注入。
byType:通过属性的类型查找JavaBean依赖的对象并为其注入。比如类Computer有个属性printer,类型为Printer,那么,指定其autowire属性为byType后,Spring IoC容器会查找Class属性为Printer的bean,使用set方法为其注入。
constructor:通byType一样,也是通过类型查找依赖对象。与byType的区别在于它不是使用set方法注入,而是使用构造子注入。
publicstaticfinalintAUTOWIRE_NO=0;publicstaticfinalintAUTOWIRE_BY_NAME=1;publicstaticfinalintAUTOWIRE_BY_TYPE=2;publicstaticfinalintAUTOWIRE_CONSTRUCTOR=3;
MapperFactoryBean相关
实现了FactoryBean接口,覆写了getObject( )方法,容器初始化时通过getObject()返回实际对象。
继承了SqlSessionDaoSupport类,有成员变量sqlSessionTemplate,通过autoWire=byType属性调用setSqlSessionFactory(sqlSessionFactory)初始化时,给sqlSessionTemplate赋值。
getObject()方法通过Configuration对象获以JDK动态代理的方式获取代理类的实例。
Configuration对象的mapperRegistry变量在Mybatis配置解析时赋值,mapperRegistry内部的knownMappers存储所有mapper接口的map信息,key为mapper接口的Class对象,value为持有对应Class对象的MapperProxyFactory实例,
MapperProxyFactory是代理类工厂,用于生成代理对象MapperProxy的代理类,即为mapper接口的实际代理对象。
//MapperFactoryBean.java@OverridepublicTgetObject()throwsException{returngetSqlSession().getMapper(this.mapperInterface);}//SqlSessionDaoSupport.javapublicSqlSessiongetSqlSession(){returnthis.sqlSessionTemplate;}//SqlSessionTemplate.java@Overridepublic<T>TgetMapper(Class<T>type){returngetConfiguration().getMapper(type,this);}//Configuration.javapublic<T>TgetMapper(Class<T>type,SqlSessionsqlSession){returnthis.mapperRegistry.getMapper(type,sqlSession);}//MapperRegistry.javapublic<T>TgetMapper(Class<T>type,SqlSessionsqlSession){MapperProxyFactory<T>mapperProxyFactory=(MapperProxyFactory)this.knownMappers.get(type);if(mapperProxyFactory==null){thrownewBindingException("Type"+type+"isnotknowntotheMapperRegistry.");}else{try{returnmapperProxyFactory.newInstance(sqlSession);}catch(Exceptionvar5){thrownewBindingException("Errorgettingmapperinstance.Cause:"+var5,var5);}}}//MapperProxyFactory.javaprotectedTnewInstance(MapperProxy<T>mapperProxy){returnProxy.newProxyInstance(this.mapperInterface.getClassLoader(),newClass[]{this.mapperInterface},mapperProxy);}//MapperProxyFactory.javapublicTnewInstance(SqlSessionsqlSession){MapperProxy<T>mapperProxy=newMapperProxy(sqlSession,this.mapperInterface,this.methodCache);returnthis.newInstance(mapperProxy);}