【淘宝aqq源码】【橘子台服源码】【微擎案例 源码】mapperprovider源码

2024-11-19 05:48:00 来源:甘特图 项目管理 源码 分类:焦点

1.用tk.mybaits实现指定字段更新
2.Fluent mybatis
3.mybatis 源码@SelectProvider 注解, 打赌你没有用过
4.springboot启动类原理?

mapperprovider源码

用tk.mybaits实现指定字段更新

       在使用tk.mybaits框架的系统中实现指定字段的更新,由于tk.mybaits框架本身并不支持此功能,源码导致寻找解决方案的源码过程颇具挑战性。经过一段时间的源码摸索和资料查阅,终于找到了解决方法。源码以下是源码淘宝aqq源码具体实现步骤,以供有相似需求的源码开发者参考。

       若系统使用的源码是Mybatis-Plus框架,实现指定字段更新则相对简便。源码但使用tk.mybaits框架时,源码默认不支持该功能,源码通常的源码解决方法是先查询数据,随后更新所需字段并再次更新整条数据。源码然而,源码这种方法在并发情况下容易引发问题。源码

       通过深入研究tk.mybaits的GitHub源码和相关issue的回答,我找到了实现指定字段更新的关键线索。最终,橘子台服源码通过以下步骤成功实现了功能:

       首先,定义一个名为UpdateAppointColumnMapper的接口,用于实现指定字段的更新。

       其次,定义一个名为UpdateByExampleAppointColumnProvider的Provider,以支持指定字段更新的逻辑。

       然后,创建一个继承自UpdateAppointColumnMapper的Mapper类,如BaseMapper,用于实现数据仓储的基本功能。

       引入LambdaUpdateWrapper,以更灵活地实现指定字段更新。具体实现方式包括:

       使用实体对象更新

       使用MAP更新

       使用LambdaUpdateWrapper更新

       通过上述步骤,解决了tk.mybaits框架中指定字段更新的问题,为相关开发任务提供了有力的技术支持。分享这一解决方法,希望能为遇到相同挑战的微擎案例 源码开发者提供一些灵感和帮助。

Fluent mybatis

       众多框架的诞生与发展,都是为了简化开发过程,提升效率。Spring框架就是一个典型的例子,它逐渐摒弃了XML配置,转而采用代码化配置。然而,iBatis,作为一个相对保守的框架,尽管MyBatis继承了它,并且推出了支持代码执行SQL的注解,但使用注解的方式也存在一些问题,比如代码的可读性和复用性较差。因此,基于MyBatis的ORM框架如mybatis-plus和tk-mybatis应运而生。

       mybatis-plus因其用户基础较广,主要得益于其设计思路和功能的电商 源码交付完善。然而,本文的重点在于Fluent-Mybatis,它在MyBatis的基础上进一步优化,提供了更简洁、直观的API。

       Fluent-Mybatis的实现原理简单高效。引入依赖后,通过实现entity类,系统会自动生成对应的mapper接口类。这种生成机制简化了开发流程,提升了开发效率。具体实现方式,本文将在后续内容中详细展示。

       动态SQL实现是Fluent-Mybatis的一个亮点。以一个典型的业务需求为例,假设我们需要统计特定学科在特定学期的成绩数据,包括最低分、网址拦截检测源码最高分和平均分,同时需要样本数量大于1,且按照学期和学科进行排序。在Fluent-Mybatis中,通过Fluent API,可以轻松实现此功能。

       为了具体展示Fluent-Mybatis的动态SQL实现效果,读者可以参考详细的代码示例。这些代码将在后续内容中提供,有兴趣的读者可直接联系作者获取。

       对比原生MyBatis和mybatis-plus,Fluent-Mybatis在实现相同功能时,代码量更少,更加简洁易读。原生MyBatis需要手动编写SQL语句和对应的Mapper XML文件,而mybatis-plus虽然简化了部分流程,但仍存在一定的代码量和复杂度。相比之下,Fluent-Mybatis通过其强大的API,使得动态SQL的编写更为直观、高效。

       Fluent-Mybatis的动态SQL实现原理基于MyBatis中的SQLProvider功能,通过在Mapper接口上定义Provider,系统在编译时自动生成对应的SQLProvider文件,从而实现动态SQL生成。这种机制不仅简化了开发过程,还提高了代码的可读性和可维护性。

       总结而言,Fluent-Mybatis在MyBatis的基础上提供了更为高效、直观的动态SQL实现方式,使得开发过程更加简洁高效。更多关于Fluent-Mybatis的详细信息和用法,可以参考其官方文档。

mybatis @SelectProvider 注解, 打赌你没有用过

       在探索MyBatis框架时,不期而遇了四个注解,它们分别是@SelectProvider、@InsertProvider、@UpdateProvider以及@DeleteProvider。这四个注解,各自在MyBatis的增删改查操作中扮演着另类角色,将传统的XML配置方式转化为注解驱动,为开发者提供了一种更为灵活、简洁的SQL编写途径。

       深入了解@SelectProvider注解时,发现其包含了两个属性,这两个属性均无默认值,这暗示了使用@SelectProvider时,这两者必须配合使用。尽管未深入探究源码解析,但可以推测,通过反射获取方法的返回值是其核心机制。

       在实战应用中,使用@SelectProvider时,首先需要定义一个Mapper接口,其中会用到@Param注解,以确保参数在调用指定方法时能够被正确映射为Map。然后,创建与类型对应的SQL语句类,并定义生成SQL语句的方法。这一过程中的关键点在于理解,SQL类作为MyBatis提供的工具类,允许开发者在代码中灵活编写SQL语句。

       思考@SelectProvider与@Select注解之间的异同,会发现二者在定义方式上有所区别:@Select直接定义SQL,而@SelectProvider则在外部定义SQL并直接引用。但这两种方式在实际功能上并无本质区别。在MyBatis初始化时,通过不同的逻辑组装SqlSource,分别对应这两种定义方式。

       在编写SQL时,MyBatis提供了多种选择,包括@Select、@SelectProvider和XML文件三种形式,分别针对不同场景提供支持。@Select适合简单场景,提供最简洁的SQL定义方式,省去了编写XML文件的繁琐步骤。@SelectProvider则适用于编写中等长度、简单查询场景,借助SQL工具类提供了便捷的API语法。若不使用工具类,开发者亦可手动编写SQL字符串。XML文件形式则功能全面,支持计算函数、动态SQL和各种关键字,适合需要高度定制化SQL的复杂场景。

       总结而言,MyBatis通过提供丰富的注解和配置选项,使得SQL编写更为灵活和高效。通过良好的变量和方法命名,增强代码的可读性和维护性。对于源码阅读的习惯,欢迎分享和讨论,共同探索更好的学习路径。

springboot启动类原理?

       SpringbootBatch的启动原理-Configuration

       Springboot整合了web和batch,但是他们肯定不是同一条路,在springboot中,会推断当前的运行环境。this.webApplicationType=WebApplicationType.deduceFromClasspath();

       ä»Žä¸Šæ–‡å¯ä»¥çœ‹å‡ºï¼ŒSpring尝试从classpath里找到特征类,来判断当前app是什么类型。当然这种判断是有局限性的,有可能是transitive带进来一个带有servlet的类被当成了WebApplicationType.SERVLET,实际上是个WebApplicationType.NONE;。如果不想以web运行就是想运行batch可以在application.properties强行指定WebApplicationType

       å…·ä½“发生作用的请看下面的stacktrace

       å½“一个batchapplication需要启动,需要配置JobRepository,Datasource等等,所有的开始都来自一个annotation@EnableBatchProcessing

       å½“加入@EnableBatchProcessing时,BatchConfigurationSelector开始启动,怎么启动的大家可以参考下面的stacktrace。

       import类主要是由ConfigurationClassPostProcessor来实现的。当BatchConfigurationSelector被调用的时候,我们可以看到他有两条支路。

       é‚£ä¹ˆè¿™ä¸¤æ¡è·¯æœ‰å•¥ä¸åŒå‘¢ã€‚主要是job定义的方式不同。

       modular=true的情况下,下面是一个例子

       å¯ä»¥æœ‰å¤šä¸ªå­ApplicationContextFactory,这样好处是在除了job大家不可以重复,因为是在不同的context里,其他的step,reader,writer,processor,mapper,以及所有的bean等等都可以重名。

       é‚£ä¸ºä»€ä¹ˆJob不可以重复,是因为虽然可以重复,但是如果job也重复,对用户来讲太不友好了。用户可能不知道自己配的是哪个context的job。具体为什么可以重名要看看GenericApplicationContextFactory的实现。

       å½“GenericApplicationContextFactory::createApplicationContext,会触发ApplicationContextHelper的构造函数从而调用loadConfiguration(config)把定义的bean加入到context里。那么有个问题,parent在哪里设置,createApplicationContext是什么时候调用的。

       æˆ‘们继续看ModularConfiguration

       ä»ŽModular的角度来看首先他可以外部注入一个Configurer,如果没有就选择DefaultBatchConfigurer,如果有多个选择则会抛出。

       å½“然Datasource也可以选择外部注入,或者由DefaultBatchConfigurer::initialize方法SimpleJobLauncher,JobRepository和JobExplorer都是由FactoryBean的方式实现的。

       åœ¨è¿™ä¸ªDefaultBatchConfigurer中可以看到JobLauncher的类型是

       initialize里MapJobRepositoryFactoryBean这个可以重点读一下。首先用FactoryBean的模式实现了一个ProxyBean,如果想了解FactoryBean的用法,这是个典型的例子。但是这个FactoryBean是以api行为直接调用的,并没有注册到Spring的context中。

       é…ç½®å¥½job需要的jobRepository,jobLauncher等那么重点来了,下面的AutomaticJobRegistrar就是来处理ApplicationContextFactory

       è¿™ä¸ªé€»è¾‘是把所有的ApplicationContextFactory的beaninstance放入到AutomaticJobRegistrar里去。这就回到了第一个问题,parentcontext是什么时候放进去的。就是在

       context.getBeansOfType(ApplicationContextFactory.class)请看下面的调用栈,在ApplicationContextAwareProcessor里会自动把parentcontext注入。

       ä½†æ˜¯æ”¾è¿›åŽ»å•¥æ—¶å€™ç”¨å‘¢ï¼Ÿæˆ‘们看一下AutomaticJobRegistrar

       åŽŸæ¥AutomaticJobRegistrar是个Smartlifecycle,从Smartlifecycle的细节可以从SpringbootSmartlifecycle来得知。它就是在所有bean都初始化结束后开始进行的一个阶段。在这个start方法中,开始遍历所有的ApplicationContextFactory,来进行加载。从上文这个jobLoader是DefaultJobLoader。

       é‚£ä¹ˆå¯ä»¥çœ‹çœ‹DefaultJobLoader::doLoad方法

       è¿™é‡Œæœ‰å‡ ä¸ªå…³é”®è°ƒç”¨ç¬¬ä¸€ä¸ªæ˜¯createApplicationContext,把context里定义的全部加载到Springcontext里去,这就满足了GenericApplicationContextFactory工作的两个条件。第二个是doRegister(context,job)里jobRegistry.register(jobFactory);

       æˆ‘们看一下JobRepository的实现MapJobRegistry::register方法,在这里就把jobname和jobFactory的键值对存储起来了。

       è¿™æ ·å°±å¯ä»¥é€šè¿‡JobRepository这个bean拿到所有注册的job了。

       å’±ä»¬å†å›žæ¥çœ‹@EnableBatchProcessing这个annotation,当没有设定modular的时候是比较简单的,只是实现了一个proxybased的Job的bean。

       åŒæ ·ä¹Ÿåªæœ‰BatchConfigurer来配置。这个逻辑和Modular是一样的。从这两个配置知道,Modular注册了在子context的配置,并且加载。但是当以正常bean的方式存在的,是怎么读进来的呢。这时候就要看JobRegistryBeanPostProcessor

       è¿™ä¸ªpostProcessAfterInitialization方法里,对每个job类型的bean,jobRegistry加入了ReferenceJobFactory。这样所有的以bean的方式定义的都可以通过jobRegistry获得。

SpringBootStater原理

       ä¸€.SpringBoot的好处

1.依赖管理:可插拔式的组件管理,当需要某个组件时,只需要引入相关stater即可,不需要再手动引入各个jar包,避免了包遗漏、包冲突等不必要的问题。开发人员可以专注于业务开发,

2.自动配置:遵从"约定优于配置"的原则,开发人员可以在少量配置或者不配置的情况下,使用某组件。

大大降低项目搭建及组件引入的成本,开发人员可以专注于业务开发,避免繁杂的配置和大量的jar包管理。

       äºŒ.实现原理

要引入某组件,无非要做两件事。一是引入jar包即pom文件引入stater;二就是编写配置文件,使用Java配置的情况下就是编写一系列@Configuration注解标注的类。那么SpringBoot是怎么来引入这些配置类的呢?就需要我们深入SpringBoot启动类一探究竟。

SpringBoot启动类上面会有@SpringBootApplication注解,这是SpringBoot中最重要的一个注解,是实现自动配置的关键。@SpringBootApplication是一个租合注解,主要由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三部分组成。

       @SpringBootConfiguration表明该类是一个配置类。

       @EnableAutoConfiguration由@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)组成。@AutoConfigurationPackage由@Import(AutoconfigurationPackages.Registrar.class)组成,向Bean容器中注册一个AutoConfigurationPackages类,该类持有basePackage,目前我发现的作用是在MyBatis扫描注册Mapper时作为包扫描路径。

       @AutoConfigurationPackage的执行流程如下图:

       @Import(AutoConfigurationImportSelector.class)是启动自动配置的核心。这里还有一个小插曲,一直在看AutoConfigurationImportSelector的selectImports方法,却发现没有被调用,以为是demo项目问题,去真实项目中debug断点,发现也没有进入,瞬间懵逼。。。继续跟踪发现执行流程如下:

       SpringBoot启动原理分析

       è‡ªåŠ¨é…ç½®æ ¸å¿ƒç±»SpringFactoriesLoader

       ä¸Šé¢åœ¨è¯´@EnableAutoConfiguration的时候有说META-INF下的spring.factories文件,那么这个文件是怎么被spring加载到的呢,其实就是SpringFactoriesLoader类。

       SpringFactoriesLoader是一个供Spring内部使用的通用工厂装载器,SpringFactoriesLoader里有两个方法,

       åœ¨è¿™ä¸ªSpringBoot应用启动过程中,SpringFactoriesLoader做了以下几件事:

       åŠ è½½æ‰€æœ‰META-INF/spring.factories中的Initializer

       åŠ è½½æ‰€æœ‰META-INF/spring.factories中的Listener

       åŠ è½½EnvironmentPostProcessor(允许在Spring应用构建之前定制环境配置)

       æŽ¥ä¸‹æ¥åŠ è½½Properties和YAML的PropertySourceLoader(针对SpringBoot的两种配置文件的加载器)

       å„种异常情况的FailureAnalyzer(异常解释器)

       åŠ è½½SpringBoot内部实现的各种AutoConfiguration

       æ¨¡æ¿å¼•æ“ŽTemplateAvailabilityProvider(如Freemarker、Thymeleaf、Jsp、Velocity等)

       æ€»å¾—来说,SpringFactoriesLoader和@EnableAutoConfiguration配合起来,整体功能就是查找spring.factories文件,加载自动配置类。

       æ•´ä½“启动流程

       åœ¨æˆ‘们执行入口类的main方法之后,运行SpringApplication.run,后面new了一个SpringApplication对象,然后执行它的run方法。

       åˆå§‹åŒ–SpringApplicationç±»

       åˆ›å»ºä¸€ä¸ªSpringApplication对象时,会调用它自己的initialize方法

       æ‰§è¡Œæ ¸å¿ƒrun方法

       åˆå§‹åŒ–initialize方法执行完之后,会调用run方法,开始启动SpringBoot。

       é¦–先遍历执行所有通过SpringFactoriesLoader,在当前classpath下的META-INF/spring.factories中查找所有可用的SpringApplicationRunListeners并实例化。调用它们的starting()方法,通知这些监听器SpringBoot应用启动。

       åˆ›å»ºå¹¶é…ç½®å½“前SpringBoot应用将要使用的Environment,包括当前有效的PropertySource以及Profile。

       éåŽ†è°ƒç”¨æ‰€æœ‰çš„SpringApplicationRunListeners的environmentPrepared()的方法,通知这些监听器SpringBoot应用的Environment已经完成初始化。

       æ‰“印SpringBoot应用的banner,SpringApplication的showBanner属性为true时,如果classpath下存在banner.txt文件,则打印其内容,否则打印默认banner。

       æ ¹æ®å¯åŠ¨æ—¶è®¾ç½®çš„applicationContextClass和在initialize方法设置的webEnvironment,创建对应的applicationContext。

       åˆ›å»ºå¼‚常解析器,用在启动中发生异常的时候进行异常处理(包括记录日志、释放资源等)。

       è®¾ç½®SpringBoot的Environment,注册SpringBean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader,通过SpringFactoriesLoader加载ApplicationContextInitializer初始化器,调用initialize方法,对创建的ApplicationContext进一步初始化。

       è°ƒç”¨æ‰€æœ‰çš„SpringApplicationRunListeners的contextPrepared方法,通知这些Listener当前ApplicationContext已经创建完毕。

       æœ€æ ¸å¿ƒçš„一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

       è°ƒç”¨æ‰€æœ‰çš„SpringApplicationRunListener的contextLoaded方法,加载准备完毕的ApplicationContext。

       è°ƒç”¨refreshContext,注册一个关闭Spring容器的钩子ShutdownHook,当程序在停止的时候释放资源(包括:销毁Bean,关闭SpringBean的创建工厂等)

       æ³¨ï¼šé’©å­å¯ä»¥åœ¨ä»¥ä¸‹å‡ ç§åœºæ™¯ä¸­è¢«è°ƒç”¨ï¼š

       1)程序正常退出

       2)使用System.exit()

       3)终端使用Ctrl+C触发的中断

       4)系统关闭

       5)使用Killpid命令杀死进程

       èŽ·å–当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法

       éåŽ†æ‰€æœ‰çš„SpringApplicationRunListener的finished()方法,完成SpringBoot的启动。

SpringBoot应用启动原理(二)扩展URLClassLoader实现嵌套jar加载

       åœ¨ä¸Šç¯‡æ–‡ç« ã€ŠSpringBoot应用启动原理(一)将启动脚本嵌入jar》中介绍了SpringBoot如何将启动脚本与RunnableJar整合为ExecutableJar的原理,使得生成的jar/war文件可以直接启动

       æœ¬ç¯‡å°†ä»‹ç»SpringBoot如何扩展URLClassLoader实现嵌套jar的类(资源)加载,以启动我们的应用。

       é¦–先,从一个简单的示例开始

       build.gradle

       WebApp.java

       æ‰§è¡Œgradlebuild构建jar包,里面包含应用程序、第三方依赖以及SpringBoot启动程序,其目录结构如下

       æŸ¥çœ‹MANIFEST.MF的内容(MANIFEST.MF文件的作用请自行GOOGLE)

       å¯ä»¥çœ‹åˆ°ï¼Œjar的启动类为org.springframework.boot.loader.JarLauncher,而并不是我们的com.manerfan.SpringBoot.theory.WebApp,应用程序入口类被标记为了Start-Class

       jar启动并不是通过应用程序入口类,而是通过JarLauncher代理启动。其实SpringBoot拥有3中不同的Launcher:JarLauncher、WarLauncher、PropertiesLauncher

       SpringBoot使用Launcher代理启动,其最重要的一点便是可以自定义ClassLoader,以实现对jar文件内(jarinjar)或其他路径下jar、class或资源文件的加载

       å…³äºŽClassLoader的更多介绍可参考《深入理解JVM之ClassLoader》

       SpringBoot抽象了Archive的概念,一个Archive可以是jar(JarFileArchive),可以是一个文件目录(ExplodedArchive),可以抽象为统一访问资源的逻辑层。

       ä¸Šä¾‹ä¸­ï¼Œspring-boot-theory-1.0.0.jar既为一个JarFileArchive,spring-boot-theory-1.0.0.jar!/BOOT-INF/lib下的每一个jar包也是一个JarFileArchive

       å°†spring-boot-theory-1.0.0.jar解压到目录spring-boot-theory-1.0.0,则目录spring-boot-theory-1.0.0为一个ExplodedArchive

       æŒ‰ç…§å®šä¹‰ï¼ŒJarLauncher可以加载内部/BOOT-INF/lib下的jar及/BOOT-INF/classes下的应用class

       å…¶å®žJarLauncher实现很简单

       å…¶ä¸»å…¥å£æ–°å»ºäº†JarLauncher并调用父类Launcher中的launch方法启动程序

       å†åˆ›å»ºJarLauncher时,父类ExecutableArchiveLauncher找到自己所在的jar,并创建archive

       åœ¨Launcher的launch方法中,通过以上archive的getNestedArchives方法找到/BOOT-INF/lib下所有jar及/BOOT-INF/classes目录所对应的archive,通过这些archives的url生成LaunchedURLClassLoader,并将其设置为线程上下文类加载器,启动应用

       è‡³æ­¤ï¼Œæ‰æ‰§è¡Œæˆ‘们应用程序主入口类的main方法,所有应用程序类文件均可通过/BOOT-INF/classes加载,所有依赖的第三方jar均可通过/BOOT-INF/lib加载

       åœ¨åˆ†æžLaunchedURLClassLoader前,首先了解一下URLStreamHandler

       java中定义了URL的概念,并实现多种URL协议(见URL)*http**file**ftp**jar*等,结合对应的URLConnection可以灵活地获取各种协议下的资源

       å¯¹äºŽjar,每个jar都会对应一个url,如

       jar:file:/data/spring-boot-theory/BOOT-INF/lib/spring-aop-5.0.4.RELEASE.jar!/

       jar中的资源,也会对应一个url,并以'!/'分割,如

       jar:file:/data/spring-boot-theory/BOOT-INF/lib/spring-aop-5.0.4.RELEASE.jar!/org/springframework/aop/SpringProxy.class

       å¯¹äºŽåŽŸå§‹çš„JarFileURL,只支持一个'!/',SpringBoot扩展了此协议,使其支持多个'!/',以实现jarinjar的资源,如

       jar:file:/data/spring-boot-theory.jar!/BOOT-INF/lib/spring-aop-5.0.4.RELEASE.jar!/org/springframework/aop/SpringProxy.class

       è‡ªå®šä¹‰URL的类格式为[pkgs].[protocol].Handler,在运行Launcher的launch方法时调用了JarFile.registerUrlProtocolHandler()以注册自定义的Handler

       åœ¨å¤„理如下URL时,会循环处理'!/'分隔符,从最上层出发,先构造spring-boot-theory.jar的JarFile,再构造spring-aop-5.0.4.RELEASE.jar的JarFile,最后构造指向SpringProxy.class的

       JarURLConnection,通过JarURLConnection的getInputStream方法获取SpringProxy.class内容

       ä»Žä¸€ä¸ªURL,到读取其中的内容,整个过程为

       URLClassLoader可以通过原始的jar协议,加载jar中从class文件

       LaunchedURLClassLoader通过扩展的jar协议,以实现jarinjar这种情况下的class文件加载

       æž„建war包很简单

       æž„建出的war包,其目录机构为

       MANIFEST.MF内容为

       æ­¤æ—¶ï¼Œå¯åŠ¨ç±»å˜ä¸ºäº†org.springframework.boot.loader.WarLauncher,查看WarLauncher实现,其实与JarLauncher并无太大差别

       å·®åˆ«ä»…在于,JarLauncher在构建LauncherURLClassLoader时,会搜索BOOT-INF/classes目录及BOOT-INF/lib目录下jar,WarLauncher在构建LauncherURLClassLoader时,则会搜索WEB-INFO/classes目录及WEB-INFO/lib和WEB-INFO/lib-provided两个目录下的jar

       å¦‚此依赖,构建出的war便支持两种启动方式

       PropretiesLauncher的实现与JarLauncherWarLauncher的实现极为相似,通过PropretiesLauncher可以实现更为轻量的thinjar,其实现方式可自行查阅源码

本文地址:http://04.net.cn/news/63f488695050.html 欢迎转发