【溯源码燕窝宣传】【dpplayer源码】【openquant源码】springmybatis源码详解

2024-12-26 04:45:26 来源:电呼源码 分类:娱乐

1.Mybatis-Spring原理分析 -- @MapperScan注解
2.口语化讲解Spring、码详Mybatis
3.mybatis 码详spring介绍、使用、实现原理
4.Springboot之 Mybatis 多数据源实现
5.mybatis-spring注解MapperScan的原理
6.Spring Boot 3 集成 MyBatis详解

springmybatis源码详解

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

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

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

       ImportBeanDefinitionRegistrar是Spring扩展点之一,其在启动时回调registerBeanDefinitions方法,将MapperScannerConfigurer的BeanDefinition注册到容器中。

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

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

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

口语化讲解Spring、Mybatis

       本文以口语化的风格,总结了Spring和Mybatis的关键知识点,旨在帮助读者快速回顾和理解Spring框架的IOC、DI、Bean、AOP以及Mybatis的运行原理、组件等核心内容。以下是对相关知识点的详细解析。

       **Spring的IOC和DI**:IOC,即控制反转,意味着将Bean的创建、配置和销毁责任交给Spring容器管理,通过依赖注入(DI)将外部资源注入到程序对象中,实现了对象间依赖的松耦合。

       **BeanFactory、FactoryBean、ApplicationContext的区别**:BeanFactory是Spring容器的基础接口,提供基本的Bean管理功能;ApplicationContext则在其基础上增加了预加载功能,更适合作为应用上下文使用;FactoryBean用于生成复杂对象,openquant源码配合Aware接口实现更复杂的操作。

       **@Component和@Bean的区别**:@Component用于标记类为组件,而@Bean则用于在容器中注册Bean实例,二者结合使得组件的管理更加灵活。

       **Spring支持的五种Bean作用域**:Spring支持单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)和全局(Global)作用域,分别对应不同的生命周期管理。

       **Bean生命周期**:从Bean容器加载到实例化,再到属性赋值和初始化,最后销毁,涉及多个关键步骤。实现Aware接口和BeanPostProcessor接口可在此过程中执行自定义逻辑。

       **Spring为何需要三级缓存解决循环依赖**:Spring的三级缓存(一级缓存、二级缓存、三级缓存)分别用于存储不同状态的Bean实例,通过预加载和循环依赖处理策略,确保Bean的正确创建和初始化。

       **Spring设计模式**:工厂设计模式用于创建Bean,代理设计模式在AOP中实现动态代理,单例设计模式确保Bean的唯一性,模板方法模式在操作类中实现通用逻辑,包装器设计模式动态切换数据源,观察者模式用于事件驱动模型,myqcms源码适配器模式用于增强接口。

       **AOP原理**:Spring通过动态代理(JDK代理或Cglib代理)实现AOP,动态代理分为静态和动态两种,通过代理模式增强对象的功能。

       **事务管理**:Spring支持编程式和声明式事务管理,声明式事务通过注解实现,更加灵活,而编程式事务则提供更细粒度的控制。Spring事务的传播行为包括:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED_TRANSACTION。

       **隔离级别**:Spring默认使用数据库的隔离级别,提供READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE等选项,确保事务的正确执行。

       **Spring MVC请求处理流程**:Spring MVC包括HandlerMapping、HandlerAdapter、HandlerExceptionResolver、ViewResolver等组件,从请求匹配Handler、andorat源码处理请求、解析视图、渲染视图等流程,实现了请求的高效处理。

       **MyBatis主要成员**:MyBatis由SqlSessionFactory、SqlSession、StatementHandler、ParameterHandler、ResultSetHandler等核心组件组成,提供SQL映射、动态SQL生成和缓存机制。

       **MyBatis工作原理**:#{ }预编译处理,${ }字符串替换,前者防止SQL注入,提高安全性。count(1)、count(*)和count(列名)分别用于统计行数,考虑NULL值的不同处理。

       **MyBatis的执行器**:有SimpleExecutor、ReuseExecutor和BatchExecutor三种执行器,分别适用于不同的执行场景,提供优化的SQL执行效率。

       **分页插件的原理**:通过自定义插件实现分页功能,重写SQL以实现分页查询,如通过LIMIT或OFFSET实现分页结果的获取。

       **MyBatis动态SQL**:使用标签实现动态SQL生成,根据条件动态拼接SQL语句,提高SQL的灵活性和适应性。

       **缓存机制**:MyBatis提供一级缓存和二级缓存,分别针对Session和命名空间,通过缓存减少数据库查询,提高系统性能。

       **MyBatis与全自动ORM的区别**:MyBatis需要手动编写SQL,实现对象关系映射,而Hibernate等工具能够自动完成映射,提供更自动化和便捷的开发体验。

       **延迟加载**:MyBatis支持关联对象的延迟加载,通过CGLIB创建代理对象,根据实际需要加载关联数据,实现高效的数据访问。

       通过以上详细解析,读者能够对Spring和Mybatis的核心概念、设计模式和关键机制有更深入的理解,为实际项目开发提供有力的理论支持。

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

Springboot之 Mybatis 多数据源实现

       本篇内容将解析如何在Spring Boot项目中实现Mybatis多数据源功能。主要方式是将不同数据库的Mapper接口存入不同的包中,利用Spring的扫描机制注入不同的数据源,实现多数据源处理。此方法与JPA多数据源的实现原理相似。

       为了演示,我们创建名为mybatis-multip-datasource的项目。项目中需要配置两个数据源:主数据源(primary)与第二数据源(second),具体的配置方式如下:

       在DataSourceConfig中进行配置。

       针对主数据源(PrimaryConfig)进行配置。

       针对第二数据源(SecondConfig)进行配置。

       接着,我们创建学生与老师的实体类:

       定义Student实体类。

       定义Teacher实体类。

       为了实现持久化,我们需要创建数据库持久类:

       定义StudentMapper类。

       定义TeacherMapper类。

       在Mybatis的xml映射文件中,我们需要编写如下代码:

       定义StudentMapper.xml文件。

       定义TeacherMapper.xml文件。

       需要注意的是,这两个xml文件需存放在不同的目录。具体路径如下图所示:

       最后,创建SpringBoot引导类进行测试,以验证多数据源功能是否实现。

mybatis-spring注解MapperScan的原理

       使用Mybatis和Spring框架开发时,@MapperScan注解能简化Mapper接口的注入过程。这一注解允许开发者指定一个包,将该包下所有接口自动注册到Spring容器中,无需为每个接口单独添加@Mapper注解,从而提高开发效率。这一功能主要得益于mybatis-spring提供的强大扩展能力,通过使用@Import和MapperScannerRegistrar类,实现了自动扫描指定包内的Mapper接口。MapperScannerRegistrar类通过注入MapperScannerConfigurer类型的BeanDefinition,进而触发BeanDefinitionRegistryPostProcessor接口的实现,参与到Spring启动周期的执行流程中。

       当项目启动时,Spring框架会调用AbstractApplicationContext类中的refresh方法,这是Spring中核心功能实现的关键步骤。在refresh方法的回调中,MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法被调用,实现了自动扫描并初始化接口的功能。具体而言,扫描过程由scan方法执行,该方法首先调用findCandidateComponents方法,找出所有符合规范的组件进行后续处理。

       在扫描过程中,会通过do...方法进行实际操作,找到并封装BeanDefinition,然后将这些定义放入Spring的Bean生命周期中,最终提供给开发者使用。此过程实现了将接口转换为实际对象的功能,如MapperFactoryBean类的使用。MapperFactoryBean是一个FactoryBean,用于创建MapperProxy代理对象,最终返回给开发者使用。Mybatis通过MapperProxy实现了接口的代理,而MybatisPlus进一步封装,形成了MybatisMapperProxy。

       在理解了MapperScan的原理后,我们还提及了FactoryBean与BeanFactory的区别。FactoryBean是一个Spring提供的扩展点,用于创建复杂Bean。而BeanFactory是Spring IOC容器的顶级接口,用于管理Bean。FactoryBean创建的Bean具有getObject()方法用于获取具体Bean,而BeanFactory提供了一套通用的接口规范。

       最后,还分享了一个提高Spring生成UUID性能的工具类——AlternativeJdkIdGenerator。该工具类使用SecureRandom作为种子,提供了比JDK原生UUID生成方式更高的性能表现。通过对比,可以发现AlternativeJdkIdGenerator在生成万次UUID时,性能显著优于JDK原生算法。尽管需要new对象才能使用,但其高性能特性值得在项目中采用,尤其是对于高并发场景下的性能优化。

Spring Boot 3 集成 MyBatis详解

       MyBatis是简化数据库交互流程的开源框架,相比ORM框架如Hibernate,其灵活性更高,直接使用SQL语句操作数据库。Spring Boot与MyBatis集成,大幅简化数据访问层开发,提高效率。

       集成步骤包括添加依赖和配置文件。Spring Boot 3后,mybatis-spring-boot-starter版本为3.x。配置文件中包含参数定义。

       创建实体类和Mapper接口。实体类对应数据库表,Mapper接口定义数据库操作方法。使用@MapperScan注解批量扫描Mapper接口包,自动注册映射器,实现接口与方法的映射。

       创建Mapper XML文件用于实现SQL语句。确保Spring Boot应用启动无误,访问测试端点验证数据库操作。

       整合后,Spring Boot + MyBatis提供高效、维护便捷的数据访问方案,快速搭建健壮数据访问层,为应用开发奠定基础。

本文地址:http://581.net.cn/news/01f261997379.html 欢迎转发