1.用tk.mybaits实现指定字段更新
2.Fluent mybatis
3.mybatis 源码@SelectProvider 注解, 打赌你没有用过
4.springbootå¯å¨ç±»åçï¼
用tk.mybaits实现指定字段更新
在使用tk.mybaits框架的系统中实现指定字段的更新,由于tk.mybaits框架本身并不支持此功能,源码导致寻找解决方案的源码过程颇具挑战性。经过一段时间的源码摸索和资料查阅,终于找到了解决方法。源码以下是源码涨停炸板变色指标公式源码具体实现步骤,以供有相似需求的源码开发者参考。 若系统使用的源码是Mybatis-Plus框架,实现指定字段更新则相对简便。源码但使用tk.mybaits框架时,源码默认不支持该功能,源码通常的源码解决方法是先查询数据,随后更新所需字段并再次更新整条数据。源码然而,源码这种方法在并发情况下容易引发问题。源码 通过深入研究tk.mybaits的GitHub源码和相关issue的回答,我找到了实现指定字段更新的关键线索。最终,rocketmq源码解析通过以下步骤成功实现了功能: 首先,定义一个名为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ï¼å ¶å®ç°æ¹å¼å¯èªè¡æ¥é æºç