1.spring batch joboperatoråjoblauncherçåºå«
2.Spring boot Batch çå¯å¨åç- Configuration
3.一文搞懂大数据批量处理框架Spring Batch的完美解析方案是什么。
4.springbatchåspringbootçåºå«
5.springbootå¯å¨ç±»åçï¼
spring batch joboperatoråjoblauncherçåºå«
JobExecution æ¥å£ç示ä¾ï¼æä¾jobçâè¿è¡ãç»æã失败âçç¶æçæ¥è¯¢ã
ç±äºJobè¿è¡å¯è½æ¶èé常é¿çæ¶é´ï¼Spring batchåæ¥åå¼æ¥ä¸¤ç§launcherã
å¼æ¥çæ åµï¼ç¨äºç±»ä¼¼äºmit-interval设置read多少条记录后进行一次提交。通过设置commit-interval的间隔值,减少提交频次,降低资源使用率。Step的门户网用什么源码每一次提交作为一个完整的事务存在。默认采用Spring提供的声明式事务管理模式,事务编排非常方便。如下是一个声明事务的示例:
框架对于事务的支持能力包括:
Chunk支持事务管理,通过commit-interval设置每次提交的记录数;支持对每个Tasklet设置细粒度的事务配置:隔离界别、传播行为、超时;支持rollback和norollback,通过skippable-exception-classes和no-rollback-exception-classes进行支撑;支持JMSQueue的事务级别配置;
另外,在框架资深的模型抽象方面,SpringBatch也做了极为精简的抽象。
仅仅使用六张业务表存储了所有的元数据信息(包括Job、Step的实例,上下文,执行器信息,为后续的监控、重启、重试、状态恢复等提供了可能)。
BATCH_JOB_INSTANCE:作业实例表,用于存放Job的java源码分离实例信息BATCH_JOB_EXECUTION_PARAMS:作业参数表,用于存放每个Job执行时候的参数信息,该参数实际对应Job实例的。BATCH_JOB_EXECUTION:作业执行器表,用于存放当前作业的执行信息,比如创建时间,执行开始时间,执行结束时间,执行的那个Job实例,执行状态等。BATCH_JOB_EXECUTION_CONTEXT:作业执行上下文表,用于存放作业执行器上下文的信息。BATCH_STEP_EXECUTION:作业步执行器表,用于存放每个Step执行器的信息,比如作业步开始执行时间,执行完成时间,执行状态,读写次数,跳过次数等信息。BATCH_STEP_EXECUTION_CONTEXT:作业步执行上下文表,用于存放每个作业步上下文的信息。实现作业的健壮性与扩展性
批处理要求Job必须有较强的健壮性,通常Job是批量处理数据、无人值守的,这要求在Job执行期间能够应对各种发生的网络搭建源码异常、错误,并对Job执行进行有效的跟踪。
一个健壮的Job通常需要具备如下的几个特性:
1.容错性
在Job执行期间非致命的异常,Job执行框架应能够进行有效的容错处理,而不是让整个Job执行失败;通常只有致命的、导致业务不正确的异常才可以终止Job的执行。
2.可追踪性
Job执行期间任何发生错误的地方都需要进行有效的记录,方便后期对错误点进行有效的处理。例如在Job执行期间任何被忽略处理的记录行需要被有效的记录下来,应用程序维护人员可以针对被忽略的记录后续做有效的处理。
3.可重启性
Job执行期间如果因为异常导致失败,应该能够在失败的点重新启动Job;而不是从头开始重新执行Job。
框架提供了支持上面所有能力的特性,包括Skip(跳过记录处理)、Retry(重试给定的操作)、Restart(从错误点开始重新启动失败的Job):
Skip,在对数据处理期间,如果数据的某几条的格式不能满足要求,可以通过Skip跳过该行记录的处理,让Processor能够顺利的处理其余的记录行。Retry,将给定的操作进行多次重试,在某些情况下操作因为短暂的异常导致执行失败,如网络连接异常、wad公式源码并发处理异常等,可以通过重试的方式避免单次的失败,下次执行操作时候网络恢复正常,不再有并发的异常,这样通过重试的能力可以有效的避免这类短暂的异常。Restart,在Job执行失败后,可以通过重启功能来继续完成Job的执行。在重启时候,批处理框架允许在上次执行失败的点重新启动Job,而不是从头开始执行,这样可以大幅提高Job执行的效率。
对于扩展性,框架提供的扩展能力包括如下的四种模式:
MultithreadedStep多线程执行一个Step;ParallelStep通过多线程并行执行多个Step;RemoteChunking在远端节点上执行分布式Chunk操作;PartitioningStep对数据进行分区,并分开执行;
我们先来看第一种的实现MultithreadedStep:
批处理框架在Job执行时默认使用单个线程完成任务的执行,同时框架提供了线程池的支持(MultithreadedStep模式),可以在Step执行时候进行并行处理,这里的并行是指同一个Step使用线程池进行执行,同一个Step被并行的执行。使用tasklet的属性task-executor可以非常容易的将普通的Step变成多线程Step。
MultithreadedStep的实现示例:
需要注意的是SpringBatch框架提供的大部分的ItemReader、ItemWriter等操作都是线程不安全的。
可以通过扩展的方式显现线程安全的Step。
下面为大家展示一个扩展的golang源码导读实现:
需求:针对数据表的批量处理,实现线程安全的Step,并且支持重启能力,即在执行失败点可以记录批处理的状态。
对于示例中的数据库读取组件JdbcCursorItemReader,在设计数据库表时,在表中增加一个字段Flag,用于标识当前的记录是否已经读取并处理成功,如果处理成功则标识Flag=true,等下次重新读取的时候,对于已经成功读取且处理成功的记录直接跳过处理。
MultithreadedStep(多线程步)提供了多个线程执行一个Step的能力,但这种场景在实际的业务中使用的并不是非常多。
更多的业务场景是Job中不同的Step没有明确的先后顺序,可以在执行期并行的执行。
ParallelStep:提供单个节点横向扩展的能力
使用场景:StepA、StepB两个作业步由不同的线程执行,两者均执行完毕后,StepC才会被执行。
框架提供了并行Step的能力。可以通过Split元素来定义并行的作业流,并制定使用的线程池。
ParallelStep模式的执行效果如下:
每个作业步并行处理不同的记录,示例中三个作业步,处理同一张表中的不同数据。
并行Step提供了在一个节点上横向处理,但随着作业处理量的增加,有可能一台节点无法满足Job的处理,此时我们可以采用远程Step的方式将多个机器节点组合起来完成一个Job的处理。
RemoteChunking:远程Step技术本质上是将对Item读、写的处理逻辑进行分离;通常情况下读的逻辑放在一个节点进行操作,将写操作分发到另外的节点执行。
远程分块是一个把step进行技术分割的工作,不需要对处理数据的结构有明确了解。
任何输入源能够使用单进程读取并在动态分割后作为块发送给远程的工作进程。
远程进程实现了监听者模式,反馈请求、处理数据最终将处理结果异步返回。请求和返回之间的传输会被确保在发送者和单个消费者之间。
在Master节点,作业步负责读取数据,并将读取的数据通过远程技术发送到指定的远端节点上,进行处理,处理完毕后Master负责回收Remote端执行的情况。
在SpringBatch框架中通过两个核心的接口来完成远程Step的任务,分别是ChunkProvider与ChunkProcessor。
ChunkProvider:根据给定的ItemReader操作产生批量的Chunk操作;
ChunkProcessor:负责获取ChunkProvider产生的Chunk操作,执行具体的写逻辑;
SpringBatch中对远程Step没有默认的实现,但我们可以借助SI或者AMQP实现来实现远程通讯能力。
Step本地节点负责读取数据,并通过MessagingGateway将请求发送到远程Step上;远程Step提供了队列的监听器,当请求队列中有消息时候获取请求信息并交给ChunkHander负责处理。
接下来我们看下最后一种分区模式;PartitioningStep:分区模式需要对数据的结构有一定的了解,如主键的范围、待处理的文件的名字等。
这种模式的优点在于分区中每一个元素的处理器都能够像一个普通SpringBatch任务的单步一样运行,也不必去实现任何特殊的或是新的模式,来让他们能够更容易配置与测试。
通过分区可以实现以下的优点:
分区实现了更细粒度的扩展;基于分区可以实现高性能的数据切分;分区比远程通常具有更高的扩展性;分区后的处理逻辑,支持本地与远程两种模式;分区作业典型的可以分成两个处理阶段,数据分区、分区处理;
数据分区:根据特殊的规则(例如:根据文件名称,数据的唯一性标识,或者哈希算法)将数据进行合理的数据切片,为不同的切片生成数据执行上下文ExecutionContext、作业步执行器StepExecution。可以通过接口Partitioner生成自定义的分区逻辑,SpringBatch批处理框架默认实现了对多文件的实现org.springframework.batch.core.partition.support.MultiResourcePartitioner;也可以自行扩展接口Partitioner来实现自定义的分区逻辑。
分区处理:通过数据分区后,不同的数据已经被分配到不同的作业步执行器中,接下来需要交给分区处理器进行作业,分区处理器可以本地执行也可以远程执行被划分的作业。接口PartitionHandler定义了分区处理的逻辑,SpringBatch批处理框架默认实现了本地多线程的分区处理org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler;也可以自行扩展接口PartitionHandler来实现自定义的分区处理逻辑。
SpringBatch框架提供了对文件分区的支持,实现类org.springframework.batch.core.partition.support.MultiResourcePartitioner提供了对文件分区的默认支持,根据文件名将不同的文件处理进行分区,提升处理的速度和效率,适合有大量小文件需要处理的场景。
示例展示了将不同文件分配到不同的作业步中,使用MultiResourcePartitioner进行分区,意味着每个文件会被分配到一个不同的分区中。如果有其它的分区规则,可以通过实现接口Partitioner来进行自定义的扩展。有兴趣的TX,可以自己实现基于数据库的分区能力哦。
总结一下,批处理框架在扩展性上提供了4中不同能力,每种都是各自的使用场景,我们可以根据实际的业务需要进行选择。
批处理框架的不足与增强
SpringBatch批处理框架虽然提供了4种不同的监控方式,但从目前的使用情况来看,都不是非常的友好。
通过DB直接查看,对于管理人员来讲,真的不忍直视;通过API实现自定义的查询,这是程序员的天堂,确实运维人员的地狱;提供了Web控制台,进行Job的监控和操作,目前提供的功能太,无法直接用于生产;提供JMX查询方式,对于非开发人员太不友好;
但在企业级应用中面对批量数据处理,仅仅提供批处理框架仅能满足批处理作业的快速开发、执行能力。
企业需要统一的批处理平台来处理复杂的企业批处理应用,批处理平台需要解决作业的统一调度、批处理作业的集中管理和管控、批处理作业的统一监控等能力。
那完美的解决方案是什么呢?
关注我:转发私信回复“架构资料”获取Java高级架构资料、源码、笔记、视频
Dubbo、Redis、设计模式、Netty、zookeeper、Springcloud、分布式、微服务
高并发等架构技术
企业级批处理平台需要在SpringBatch批处理框架的基础上,集成调度框架,通过调度框架可以将任务按照企业的需求进行任务的定期执行;
丰富目前SpringBatchAdmin(SpringBatch的管理监控平台,目前能力比较薄弱)框架,提供对Job的统一管理功能,增强Job作业的监控、预警等能力;
通过与企业的组织机构、权限管理、认证系统进行合理的集成,增强平台对Job作业的权限控制、安全管理能力。
由于时间关系,今天的分享就到这里,很多内容未能展开讨论。欢迎大家在实际业务中使用SpringBatch框架。
最后的话
觉得还不错可以转发关注支持一波~私信架构资料获取一些我私人整理的Java进阶资料!
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀。而你是不是还在满足于现状且内心在窃喜?“对于程序员来说,如果哪一天开始他停止了学习,那么他的职业生涯便开始宣告消亡。”所以行动起来,学习起来!
springbatchåspringbootçåºå«
Spring Batchï¼é«æçæ¹å¤çåºç¨ï¼è½å¤æ¯æç®ååå¤æ以ååºå¤§æ°æ®éçæ¹å¤çä½ä¸ï¼
æ大éçå¯éç¨ç»ä»¶ï¼å æ¬æ¥å¿ã追踪ãäºå¡ãä»»å¡ä½ä¸ç»è®¡ãä»»å¡éå¯ãè·³è¿ãéå¤ãèµæºç®¡çï¼
æä¾äºé«çº§åè½åç¹æ§æ¥æ¯æï¼æ¯å¦åºååè½ãè¿ç¨åè½ï¼
Spring Batchæ¡æ¶çç»æé¨å
1ï¼JobRepositoryï¼ç¨æ¥æ³¨åJob容å¨ï¼è®¾ç½®æ°æ®åºç¸å ³å±æ§ã
2ï¼JobLauncherï¼ç¨æ¥å¯å¨Jobçæ¥å£
3ï¼Jobï¼æ们è¦å®é æ§è¡çä»»å¡ï¼å å«ä¸ä¸ªæå¤ä¸ª
4ï¼Stepï¼å³æ¥éª¤ï¼å æ¬ï¼ItemReader->ItemProcessor->ItemWriter
5ï¼ItemReaderï¼ç¨æ¥è¯»åæ°æ®ï¼åå®ä½ç±»ä¸æ°æ®å段ä¹é´çæ å°ãæ¯å¦è¯»åcsvæ件ä¸ç人åæ°æ®ï¼ä¹å对åºå®ä½personçå段åmapper
6ï¼ItemProcessorï¼ç¨æ¥å¤çæ°æ®çæ¥å£ï¼åæ¶å¯ä»¥åæ°æ®æ ¡éªï¼è®¾ç½®æ ¡éªå¨ï¼ä½¿ç¨JSR-(hibernate-validator)注解ï¼ï¼æ¯å¦å°ä¸ææ§å«ç·/女ï¼è½¬ä¸ºM/Fãåæ¶æ ¡éªå¹´é¾å段æ¯å¦ç¬¦åè¦æ±ç
7ï¼ItemWriterï¼ç¨æ¥è¾åºæ°æ®çæ¥å£ï¼è®¾ç½®æ°æ®åºæºãç¼åé¢å¤çSQLæå ¥è¯å¥
Spring Bootï¼
Spring Bootæ¯ç±Pivotalå¢éæä¾çå ¨æ°æ¡æ¶ï¼å ¶è®¾è®¡ç®çæ¯ç¨æ¥ç®åSpringåºç¨çå建ãè¿è¡ãè°è¯ãé¨ç½²çã
Spring Bootæ¯å¼åè åSpring æ¬èº«æ¡æ¶çä¸é´å±ï¼å¸®å©å¼åè ç»ç¹ç®¡çåºç¨çé ç½®ï¼æä¾åºäºå®é å¼åä¸å¸¸è§é ç½®çé»è®¤å¤çã
Spring Batchæ¡æ¶çç»æé¨å
1ï¼JobRepositoryï¼ç¨æ¥æ³¨åJob容å¨ï¼è®¾ç½®æ°æ®åºç¸å ³å±æ§ã
2ï¼JobLauncherï¼ç¨æ¥å¯å¨Jobçæ¥å£
3ï¼Jobï¼æ们è¦å®é æ§è¡çä»»å¡ï¼å å«ä¸ä¸ªæå¤ä¸ª
4ï¼Stepï¼å³æ¥éª¤ï¼å æ¬ï¼ItemReader->ItemProcessor->ItemWriter
5ï¼ItemReaderï¼ç¨æ¥è¯»åæ°æ®ï¼åå®ä½ç±»ä¸æ°æ®å段ä¹é´çæ å°ãæ¯å¦è¯»åcsvæ件ä¸ç人åæ°æ®ï¼ä¹å对åºå®ä½personçå段åmapper
6ï¼ItemProcessorï¼ç¨æ¥å¤çæ°æ®çæ¥å£ï¼åæ¶å¯ä»¥åæ°æ®æ ¡éªï¼è®¾ç½®æ ¡éªå¨ï¼ä½¿ç¨JSR-(hibernate-validator)注解ï¼ï¼æ¯å¦å°ä¸ææ§å«ç·/女ï¼è½¬ä¸ºM/Fãåæ¶æ ¡éªå¹´é¾å段æ¯å¦ç¬¦åè¦æ±ç
7ï¼ItemWriterï¼ç¨æ¥è¾åºæ°æ®çæ¥å£ï¼è®¾ç½®æ°æ®åºæºãç¼åé¢å¤ç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ï¼å ¶å®ç°æ¹å¼å¯èªè¡æ¥é æºç