欢迎来到皮皮网网首页

【wordpress小说源码】【公益平台软件源码】【屠龙定乾坤源码】mapperscanner源码

来源:php源码解密源码 时间:2024-11-27 01:00:48

1.mybatis spring介绍、使用、实现原理
2.Mybatis-Spring原理分析 -- @MapperScan注解
3.org.mybatis.spring.mapper.mapperscannerconfigurer在哪个jar包
4.MyBatis 原理:扫描 Mapper 接口

mapperscanner源码

mybatis spring介绍、使用、实现原理

       maven依赖<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency>使用

       SqlSessionFactoryBean 可以创建sqlSessionFactory,dataSource是自己的数据源的bean @MapperScan注解可以帮助我们把MyBatis的Mapper类注册为bean,这样我们就可以在使用的地方通过@Autowired/@Resource引用来使用。

@MapperScan("com.github.liuzhengyang")@ConfigurationpublicclassMyBatisConfig{ @Autowired@BeanpublicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){ SqlSessionFactoryBeansqlSessionFactoryBean=newSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);returnsqlSessionFactoryBean;}}实现原理

       mybatis-spring帮助我们简化的工作、带来的价值是

       SqlSessionFactory创建的工作,使用原生的mybatis需要用配置文件配置mybatis,mybais-spring可以用@Bean代码创建。(虽然mybatis也能用代码构建,不过SqlSessionFactory被spring管理了,在使用的时候只需要@Autowire会更方便)

       ä¸å†éœ€è¦æ¯æ¬¡openSession、close,这些工作在mybatis-spring内部实现了,mybatis-spring帮助我们判断是否要openSession

       Mapper类变成了bean,需要使用的时候直接@Autowired就可以

       æä¾›çº¿ç¨‹å®‰å…¨çš„SqlSessionTemplate

SqlSessionFactory如何创建

       SqlSessionFactory通过SqlSessionFactoryBean#buildSqlSessionFactory构建,调用时机是SqlSessionFactoryBean.afterPropertiesSet。 SqlSessionFactory有大量可配置项,这些配置项最终转变为SqlSessionFactory的构建参数(Configuration)

@OverridepublicvoidafterPropertiesSet()throwsException{ notNull(dataSource,"Property'dataSource'isrequired");notNull(sqlSessionFactoryBuilder,"Property'sqlSessionFactoryBuilder'isrequired");state((configuration==null&&configLocation==null)||!(configuration!=null&&configLocation!=null),"Property'configuration'and'configLocation'cannotspecifiedwithtogether");this.sqlSessionFactory=buildSqlSessionFactory();}protectedSqlSessionFactorybuildSqlSessionFactory()throwsException{ finalConfigurationtargetConfiguration;...XMLConfigBuilderxmlConfigBuilder=null;if(this.configuration!=null){ targetConfiguration=this.configuration;if(targetConfiguration.getVariables()==null){ targetConfiguration.setVariables(this.configurationProperties);}elseif(this.configurationProperties!=null){ targetConfiguration.getVariables().putAll(this.configurationProperties);}}elseif(this.configLocation!=null){ xmlConfigBuilder=newXMLConfigBuilder(this.configLocation.getInputStream(),null,this.configurationProperties);targetConfiguration=xmlConfigBuilder.getConfiguration();}else{ LOGGER.debug(()->"Property'configuration'or'configLocation'notspecified,usingdefaultMyBatisConfiguration");targetConfiguration=newConfiguration();Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);}...returnthis.sqlSessionFactoryBuilder.build(targetConfiguration);}Mapper类如何注册成bean到BeanFactory中的

       ä½¿ç”¨äº†mybatis-spring,会扫描特定的Mapper类(@MapperScan注解控制,控制标注了任意注解的接口可以被注册上,还可以配置接口的parent判断),然后作为Bean注册到beanFactory中,从而能被其他的bean依赖使用。

@MapperpublicinterfaceUserMapper{ UsergetUserById(longid);}

       è¦å®žçŽ°è¿™æ ·çš„scan机制,就需要一个scan mapper的BeanPostProcessor,这个processor中,scan当前classpath下满足MapperScan配置的package要求的类(接口),并且判断是否有@Mapper注解,如果符合,创建BeanDefinition注册到BeanFactory中。在getBean的时候,调用MapperFactoryBean.getObject拿到的Mapper代理,实现是Configuration.getMapper(Class type, SqlSession sqlSession), SqlSession是SqlSessionTemplate自身。最后在afterPropertiesSet,会拿到SqlSessionFactory.getConfiguration(),调用addMapper(Class type)添加到mybatis中

       ä¸ºä»€ä¹ˆå¢žåŠ äº†@MapperScan注解,就能扫描注册Mapper了呢。从MapperScan类可以看到,上面有一个@Import注解,import了MapperScannerRegistrar

@Import(MapperScannerRegistrar.class)@Repeatable(MapperScans.class)public@interfaceMapperScan{ ...}

       spring的@Import注解一般用来引用其他的Configuration,还可以引用 ImportSelector和ImportBeanDefinitionRegistrar 实现或其他的Component类。

       Provides functionality equivalent to the element in Spring XML. Allows for importing @Configuration classes, ImportSelector and ImportBeanDefinitionRegistrar implementations, as well as regular component classes (as of 4.2; analogous to AnnotationConfigApplicationContext.register).

       æ€»ä¹‹ï¼Œç­‰ä»·äºŽå£°æ˜Žäº†ä¸€ä¸ªMapperScannerRegistrar Bean。我们看一下MapperScannerRegistrar的实现,MapperScannerRegistrat实现了ImportBeanDefinitionRegistrar和ResourceLoaderAware接口。

       ImportBeanDefinitionRegistrar接口,用来在处理@Configuration类的时候,创建bean definition级别的bean。

       Interface to be implemented by types that register additional bean definitions when processing @Configuration classes. Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.

       åœ¨spring的refresh阶段,有一步是invokeBeanFactoryPostProcessors,会调用到ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry,最终会调用到loadBeanDefinitionsFromRegistrars,调用到MapperScannerRegistrar.registerBeanDefinitions

@OverridepublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){ intregistryId=System.identityHashCode(registry);if(this.registriesPostProcessed.contains(registryId)){ thrownewIllegalStateException("postProcessBeanDefinitionRegistryalreadycalledonthispost-processoragainst"+registry);}if(this.factoriesPostProcessed.contains(registryId)){ thrownewIllegalStateException("postProcessBeanFactoryalreadycalledonthispost-processoragainst"+registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);}privatevoidloadBeanDefinitionsForConfigurationClass(ConfigurationClassconfigClass,TrackedConditionEvaluatortrackedConditionEvaluator){ if(trackedConditionEvaluator.shouldSkip(configClass)){ StringbeanName=configClass.getBeanName();if(StringUtils.hasLength(beanName)&&this.registry.containsBeanDefinition(beanName)){ this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if(configClass.isImported()){ registerBeanDefinitionForImportedConfigurationClass(configClass);}for(BeanMethodbeanMethod:configClass.getBeanMethods()){ loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}privatevoidloadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar,AnnotationMetadata>registrars){ registrars.forEach((registrar,metadata)->registrar.registerBeanDefinitions(metadata,this.registry));}

       å†çœ‹ä¸€ä¸‹MapperScannerRegistrar的实现。registerBeanDefinitions创建了一个BeanDefinition,bean是MapperScannerConfigurer,配置了MapperScannerConfigurer需要的属性配置(配置来源于@MapperScan注解),例如annotationClass, factoryBean等。

publicclassMapperScannerRegistrarimplementsImportBeanDefinitionRegistrar,ResourceLoaderAware{ @OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){ AnnotationAttributesmapperScanAttrs=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));if(mapperScanAttrs!=null){ registerBeanDefinitions(importingClassMetadata,mapperScanAttrs,registry,generateBaseBeanName(importingClassMetadata,0));}}voidregisterBeanDefinitions(AnnotationMetadataannoMeta,AnnotationAttributesannoAttrs,BeanDefinitionRegistryregistry,StringbeanName){ 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()));if(basePackages.isEmpty()){ basePackages.add(getDefaultBasePackage(annoMeta));}StringlazyInitialization=annoAttrs.getString("lazyInitialization");if(StringUtils.hasText(lazyInitialization)){ builder.addPropertyValue("lazyInitialization",lazyInitialization);}StringdefaultScope=annoAttrs.getString("defaultScope");if(!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)){ builder.addPropertyValue("defaultScope",defaultScope);}builder.addPropertyValue("basePackage",StringUtils.collectionToCommaDelimitedString(basePackages));registry.registerBeanDefinition(beanName,builder.getBeanDefinition());}privatestaticStringgenerateBaseBeanName(AnnotationMetadataimportingClassMetadata,intindex){ returnimportingClassMetadata.getClassName()+"#"+MapperScannerRegistrar.class.g

Mybatis-Spring原理分析 -- @MapperScan注解

       根据@MapperScan注解配置的包路径,扫描所有mapper接口,创建BeanDefinition对象,修改beanClass属性值为MapperFactoryBean,注册到Spring容器中,为后续Bean初始化做准备。wordpress小说源码

       在启动流程中,Spring扩展点ImportBeanDefinitionRegistrar被触发,其注册BeanDefinition到容器。同时,BeanDefinitionRegistryPostProcessor也被激活,创建ClassPathMapperScanner对象,对@MapperScacn中的包路径进行扫描,创建并修改BeanDefinition。

       ImportBeanDefinitionRegistrar是公益平台软件源码Spring扩展点之一,其在启动时回调registerBeanDefinitions方法,将MapperScannerConfigurer的BeanDefinition注册到容器中。

       而BeanDefinitionRegistryPostProcessor也是Spring的扩展点之一,在启动时回调postProcessBeanDefinitionRegistry方法,创建ClassPathMapperScanner对象,对@MapperScacn定义的包路径进行扫描,创建、屠龙定乾坤源码修改BeanDefinition。

       ClassPathMapperScanner负责扫描mapper层的所有接口,创建Bean定义,并设置beanClass和autoWireMode。

       最后,创建MapperFactoryBean,其属性根据扫描到的美食点餐源码mapper接口自动配置,完成初始化。

org.mybatis.spring.mapper.mapperscannerconfigurer在哪个jar包

       org.mybatis.spring.mapper.MapperScannerConfigurer 来自 mybatis-spring

       

如果你使用 maven的话, 你可以这么配置

       

<dependency>

       <groupId>org.mybatis</groupId>

       <artifactId>mybatis-spring</artifactId>

       <version>1.3.0</version>

       </dependency>

MyBatis 原理:扫描 Mapper 接口

       在MyBatis中,Mapper接口的扫描依赖MyBatis和Spring项目。实现Mapper接口的自动扫描主要有两种方式:@Mapper和@MapperScan注解。

       @Mapper注解通常用于Mapper接口上,若仅需扫描带有该注解的接口,需引入mybatis/spring-boot-starter项目。旅游预售系统源码在Spring未找到MapperScannerConfigurer和MapperFactoryBean的Bean时,AutoConfiguredMapperScannerRegistrar会自动扫描并注入Mapper接口的实现类。这个过程可通过MybatisAutoConfiguration的源码来理解。

       相比之下,@MapperScan注解是Mybatis的常见扫描方式。它通过@Import(MapperScannerRegistrar.class)导入MapperScannerRegistrar,进行Mapper扫描逻辑。MapperScannerRegistrar通过实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法完成Mapper的扫描。

       核心组件MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,其主要在registerBeanDefinitions方法中处理Mapper的自动注入。具体来说,它会创建ClassPathMapperScanner,扫描指定包中的Mapper,生成BeanDefinition,这些BeanDefinition最终会在Spring的Bean创建过程中被转换为Mapper的实例。

       MapperFactoryBean是MyBatis/Spring用来表示Mapper的Bean,它基于SqlSessionDaoSupport,提供了FactoryBean接口的实现。获取Mapper时,会通过FactoryBean的getObject方法返回Mapper的代理类,如SqlSessionTemplate,它与Spring事务紧密关联并支持线程安全。

       Configuration和MapperRegistry是MyBatis的核心配置,前者管理Mapper的信息,后者存储Mapper实例。在使用MapperRegistry获取Mapper时,会优先尝试从缓存中获取,只有当缓存中不存在时,才会创建新的MapperProxy实例。