1.Python接口自动化-requests模块之post请求
2.在线程中怎么实现精确定时
3.SpringBoot动态定时任务的定时定实现
4.工作笔记(五十六)— xxl-job
5.WAVM源码解析 —— WASI接口定义、内部实例初始化及实例链接
6.浅说gocron:基于cron二次开发的请求请求定时任务集中调度平台
Python接口自动化-requests模块之post请求
在探讨Python接口自动化时,requests模块在处理HTTP请求方面扮演了重要角色。接口接口在上篇文章中,源码源码我们详细介绍了requests模块及其get请求的定时定使用。本文将聚焦于requests模块中的请求请求彩虹频道手机直播源码post请求。 一、接口接口源码解析 在处理post请求时,源码源码我们首先需要理解其参数解析机制。定时定post请求允许我们向服务器发送数据,请求请求常见于表单提交、接口接口发送JSON数据等场景。源码源码 二、定时定data与json的请求请求区别 小伙伴们在面对如何选择使用data还是json参数时,可能会感到困惑。接口接口其实,选择的关键在于请求头中的content-type类型。 举例说明,若使用data参数,通常意味着请求数据以表单形式(application/x-www-form-urlencoded)发送。反之,若content-type为application/json,则应使用json参数,以确保数据以JSON格式传输。 三、手机编码扫雷源码form形式发送post请求 假设当前接口接受类型为application/x-www-form-urlencoded的数据,我们通过正确的参数格式发送post请求,如上文所示。 四、json形式发送post请求 同样,当接口要求应用类型为application/json时,我们需确保数据以JSON格式传递。若选择使用data参数而未转换为JSON字符串,可能会导致请求失败。 总结,本文阐述了post请求的源码解析、data与json参数的应用场景及实战操作。为了提升实践能力,读者可以利用公司项目或在线资源进行实际操作。 未来,我们将深入探讨接口自动化中cookie、session的原理与应用。对于感兴趣的读者,欢迎关注微信公众号:ITester软件测试小栈,获取更多测试相关资讯。在线程中怎么实现精确定时
问题一:定时器一般是以线程的方式运行的,如果能得到该线程的引用,就可以像查看Thread一样查看定时器的运行状态。
如果可以修改源代码最好给他提供一个方法返回线程引用
问题二:TimerTask实现了接口Runnable,集成短信宝源码如果是以newThread(TimerTask)。
start()方式启动就是做为一个单独的线程运行的,如果是timeTask.run()那就是方法调用,虽然占据一个线程,但这个线程就是主线程,并没有启动新的线程;
既然实现线程,自然可以通过Thread的isAlive方法获取其live状态;
一般情况下(不发生异常),定时器会一直运行,如果JVM停止,那么线程必然已经终止,如果JVM中只有这一个线程在运行,那么JVM不停,这个定时器就是一定在运行中,如果JVM中还有其他线程在运行,那么JVM不停,这个定时器有可能已经终止
PS:无论用不用线程池,线程启动方式只有两种(不包含mainThread):一种是继承Thread类,然后直接同构引用调用start方法,第二种就是继承Runnable接口,通过newThread(newMyRunnableClass())。
start()方式启动。
无论如何,都会有一个Thread类的引用
补充:
一个tomcat只启动一个进程,而JVM的无锡培训系统源码垃圾处理器也只有一个,所以在一个工程里运行System.gc也会影响到其他工程。
SpringBoot动态定时任务的实现
1. Spring 定时任务的简单实现
在Spring Boot中使用定时任务,只需要@EnableScheduling开启定时任务支持,在需要调度的方法上添加@Scheduled注解。这样就能够在项目中开启定时调度功能了,支持通过cron、fixedRate、fixedDelay等灵活的控制执行周期和频率。
1.1 缺点周期一旦指定,想要更改必须要重启应用
1.2 需求热更新定时任务的执行周期,基于cron表达式并支持外部存储,如数据库,nacos等
最小改造兼容现有的定时任务(仅需添加一个注解)
动态增加定时任务
2.Spring 定时任务源码分析2.1 @EnableScheduling 引入了配置类 SchedulingConfiguration
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Import(SchedulingConfiguration.class)@Documentedpublic@interfaceEnableScheduling{ }2.2 SchedulingConfiguration只配置了一个bean,ScheduledAnnotationBeanPostProcessor从名字就知道该类实现BeanPostProcessor接口
@Configuration@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicclassSchedulingConfiguration{ @Bean(name=TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicScheduledAnnotationBeanPostProcessorscheduledAnnotationProcessor(){ returnnewScheduledAnnotationBeanPostProcessor();}}2.3 ScheduledAnnotationBeanPostProcessor的postProcessAfterInitialization实现,可见具体处理@Scheduled实现定时任务的是processScheduled方法
@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){ if(beaninstanceofAopInfrastructureBean||beaninstanceofTaskScheduler||beaninstanceofScheduledExecutorService){ //IgnoreAOPinfrastructuresuchasscopedproxies.returnbean;}Class<?>targetClass=AopProxyUtils.ultimateTargetClass(bean);if(!this.nonAnnotatedClasses.contains(targetClass)&&AnnotationUtils.isCandidateClass(targetClass,Arrays.asList(Scheduled.class,Schedules.class))){ //获取bean的方法及@Scheduled映射关系Map<Method,Set<Scheduled>>annotatedMethods=MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>)method->{ Set<Scheduled>scheduledMethods=AnnotatedElementUtils.getMergedRepeatableAnnotations(method,Scheduled.class,Schedules.class);return(!scheduledMethods.isEmpty()?scheduledMethods:null);});if(annotatedMethods.isEmpty()){ this.nonAnnotatedClasses.add(targetClass);if(logger.isTraceEnabled()){ logger.trace("No@Scheduledannotationsfoundonbeanclass:"+targetClass);}}else{ //Non-emptysetofmethodsannotatedMethods.forEach((method,scheduledMethods)->//处理@Scheduled注解scheduledMethods.forEach(scheduled->processScheduled(scheduled,method,bean)));if(logger.isTraceEnabled()){ logger.trace(annotatedMethods.size()+"@Scheduledmethodsprocessedonbean'"+beanName+"':"+annotatedMethods);}}}returnbean;}2.4 以下仅贴出ScheduledAnnotationBeanPostProcessor.processScheduled处理cron表达式的关键实现,
privatefinalScheduledTaskRegistrarregistrar;publicScheduledAnnotationBeanPostProcessor(){ this.registrar=newScheduledTaskRegistrar();}protectedvoidprocessScheduled(Scheduledscheduled,Methodmethod,Objectbean){ try{ //将定时任务方法,转为RunnableRunnablerunnable=createRunnable(bean,method);booleanprocessedSchedule=false;Set<ScheduledTask>tasks=newLinkedHashSet<>(4);//Determineinitialdelay//处理scheduled.initialDelay()的值,略过...//CheckcronexpressionStringcron=scheduled.cron();if(StringUtils.hasText(cron)){ Stringzone=scheduled.zone();if(this.embeddedValueResolver!=null){ //${ }变量值表达式的转换cron=this.embeddedValueResolver.resolveStringValue(cron);zone=this.embeddedValueResolver.resolveStringValue(zone);}if(StringUtils.hasLength(cron)){ Assert.isTrue(initialDelay==-1,"'initialDelay'notsupportedforcrontriggers");processedSchedule=true;if(!Scheduled.CRON_DISABLED.equals(cron)){ TimeZonetimeZone;if(StringUtils.hasText(zone)){ timeZone=StringUtils.parseTimeZoneString(zone);}else{ timeZone=TimeZone.getDefault();}//创建cron触发器CronTrigger对象,并注册CronTasktasks.add(this.registrar.scheduleCronTask(newCronTask(runnable,newCronTrigger(cron,timeZone))));}}}//处理fixedDelay和fixedRate,及ScheduledTask保存用于销毁,略过...}//略过catchException...}以上通过this.registrar.scheduleCronTask实现cron定时任务注册或初始化
3.动态定时任务的实现实现思路: 重写ScheduledAnnotationBeanPostProcessor.processScheduled方法,修改处理cron的部分代码,使用this.registrar.scheduleTriggerTask注册或初始化定时任务
3.1 相关类图classDiagramDisposableBean<|--DynamicCronScheduleTaskManagerEnvironmentAware<|--EnvironmentDynamicCronHandlerAbstractDynamicCronHandler<|--EnvironmentDynamicCronHandlerTrigger<|--DynamicCronTriggerEnvironmentAware:+setEnvironment()DisposableBean:+destroy()voidTrigger:+nextExecutionTime(TriggerContexttriggerContext)DateclassDynamicCronScheduleTaskManager{ +Map<String,ScheduledTask>dynamicScheduledTaskMap-ScheduledTaskRegistrarregistrar+addTriggerTask(StringcronName,TriggerTasktask)ScheduledTask+contains(StringcronName)boolean+updateTriggerTask(StringcronName)void+removeTriggerTask(StringcronName)void}classAbstractDynamicCronHandler{ -DynamicCronScheduleTaskManagerdynamicCronScheduleTaskManager;+getCronExpression(StringcronName)String+updateTriggerTash(StringcronName)void}classEnvironmentDynamicCronHandler{ +Environmentenvironment+environmentChangeEvent(EnvironmentChangeEventevent)void}classDynamicCronTrigger{ -StringcronName-AbstractDynamicCronHandlerdynamicCronHandler-StringcronExpression-CronSequenceGeneratorsequenceGenerator}classScheduledDynamicCron{ +value()String+cronName()String+handler()Class<?extendsAbstractDynamicCronHandler>}3.2 DynamicCronScheduleTaskManagerimportorg.springframework.beans.factory.DisposableBean;importorg.springframework.scheduling.config.ScheduledTask;importorg.springframework.scheduling.config.ScheduledTaskRegistrar;importorg.springframework.scheduling.config.TriggerTask;importjava.util.HashMap;importjava.util.Map;/***@authorHuangJS*@date--:下午*/publicclassDynamicCronScheduleTaskManagerimplementsDisposableBean{ privateMap<String,ScheduledTask>dynamicScheduledTaskMap=newHashMap<>();ScheduledTaskRegistrarregistrar;//添加定时任务publicScheduledTaskaddTriggerTask(StringcronName,TriggerTasktask){ ScheduledTaskscheduledTask=dynamicScheduledTaskMap.get(cronName);if(scheduledTask!=null){ scheduledTask.cancel();}scheduledTask=this.registrar.scheduleTriggerTask(task);dynamicScheduledTaskMap.put(cronName,scheduledTask);returnscheduledTask;}publicbooleancontains(StringcronName){ returnthis.dynamicScheduledTaskMap.containsKey(cronName);}//更新定时任务的触发时机publicvoidupdateTriggerTask(StringcronName){ ScheduledTaskscheduledTask=dynamicScheduledTaskMap.get(cronName);if(scheduledTask==null){ thrownewIllegalStateException("InvalidcronName""+cronName+"",nofundScheduledTask");}scheduledTask.cancel();scheduledTask=this.registrar.scheduleTriggerTask((TriggerTask)scheduledTask.getTask());dynamicScheduledTaskMap.put(cronName,scheduledTask);}//移除定时任务publicvoidremoveTriggerTask(StringcronName){ ScheduledTaskscheduledTask=dynamicScheduledTaskMap.remove(cronName);if(scheduledTask!=null){ scheduledTask.cancel();}}@Overridepublicvoiddestroy()throwsException{ for(ScheduledTaskvalue:dynamicScheduledTaskMap.values()){ value.cancel();}this.dynamicScheduledTaskMap.clear();}}3.3 AbstractDynamicCronHandlerpublicabstractclassAbstractDynamicCronHandler{ @AutowiredprivateDynamicCronScheduleTaskManagerdynamicCronScheduleTaskManager;/***获取cron表达式*@return*/publicabstractStringgetCronExpression(StringcronName);/***更新cronName对应的定时任务的触发时机*@paramcronName*/publicvoidupdateTriggerTask(StringcronName){ dynamicCronScheduleTaskManager.updateTriggerTask(cronName);}}3.4 EnvironmentDynamicCronHandler基于Environment,在刷新配置时,自动刷新定时任务的触发时机,支持分布式多节点集群部署。源码搭建培训课
如,cron表达式配置在nacos,更新nacos上的配置时由于监听了EnvironmentChangeEvent事件实现了定时任务的触发时机的更新
importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.cloud.context.environment.EnvironmentChangeEvent;importorg.springframework.context.EnvironmentAware;importorg.springframework.context.event.EventListener;importorg.springframework.core.env.Environment;/***@authorHuangJS*@date--:上午*/publicclassEnvironmentDynamicCronHandlerextendsAbstractDynamicCronHandlerimplementsEnvironmentAware{ privatefinalLoggerlogger=LoggerFactory.getLogger(EnvironmentDynamicCronHandler.class);privateEnvironmentenvironment;@OverridepublicStringgetCronExpression(StringcronName){ try{ returnenvironment.getProperty(cronName);}catch(Exceptione){ logger.error(e.getMessage(),e);}returnnull;}@OverridepublicvoidsetEnvironment(Environmentenvironment){ this.environment=environment;}@EventListenerpublicvoidenvironmentChangeEvent(EnvironmentChangeEventevent){ for(Stringkey:event.getKeys()){ if(this.dynamicCronScheduleTaskManager.contains(key)){ this.dynamicCronScheduleTaskManager.updateTriggerTask(key);}}}}3.5 DynamicCronTriggerpublicclassDynamicCronTriggerimplementsTrigger{ privatefinalstaticLoggerLOGGER=LoggerFactory.getLogger(DynamicCronTrigger.class);privateStringcronName;privateAbstractDynamicCronHandlerdynamicCronHandler;privateStringcronExpression;privateCronSequenceGeneratorsequenceGenerator;publicDynamicCronTrigger(StringcronName,AbstractDynamicCronHandlerdynamicCronHandler){ this.cronName=cronName;this.dynamicCronHandler=dynamicCronHandler;}@OverridepublicDatenextExecutionTime(TriggerContexttriggerContext){ StringcronExpression=dynamicCronHandler.getCronExpression(cronName);if(cronExpression==null){ returnnull;}if(this.sequenceGenerator==null||!cronExpression.equals(this.cronExpression)){ try{ this.sequenceGenerator=newCronSequenceGenerator(cronExpression);this.cronExpression=cronExpression;}catch(Exceptione){ LOGGER.error(e.getMessage(),e);}}Datedate=triggerContext.lastCompletionTime();if(date!=null){ Datescheduled=triggerContext.lastScheduledExecutionTime();if(scheduled!=null&&date.before(scheduled)){ //Previoustaskapparentlyexecutedtooearly...//Let'ssimplyusethelastcalculatedexecutiontimethen,//inordertopreventaccidentalre-firesinthesamesecond.date=scheduled;}}else{ date=newDate();}returnthis.sequenceGenerator.next(date);}}3.6 注解类ScheduledDynamicCron@Target({ ElementType.METHOD,ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceScheduledDynamicCron{ /***动态cron名称*@return*/@AliasFor("cronName")Stringvalue()default"";/***动态cr工作笔记(五十六)— xxl-job
xxl-job是一个专门用于处理分布式定时任务的高效任务调度框架,它由调度中心和执行器两个核心组件构成。调度中心作为可视化管理平台,负责管理和发出调度请求,管理调度信息;而执行器则负责接收这些请求并执行相应的任务逻辑。
要使用xxl-job,首先进行安装和配置。从源码开始,解压后初始化数据库,并运行提供的SQL脚本创建相关表。调度中心配置主要包括配置文件设置,它是一个基于springBoot的项目,通过jar包启动。部署时,保持数据库配置一致性以及机器时钟同步至关重要。访问调度中心的默认地址是http://localhost:/xxl-job-admin,登录名为“admin/”。
执行器配置涉及将xxl-job jar包引入业务模块的pom.xml中。执行器通过XxlJobConfig根据配置生成XxlJobSpringExecutor,并允许用户以两种模式创建任务:一是通过实现IJobHandler接口,自定义execute()方法;二是使用方式模式,通过注解在Job方法上指定初始化和销毁方法,并在调度中心配置执行策略。调度中心支持自动注册执行器实例并添加任务,确保任务执行的唯一性。
为了保证分布式集群环境中的任务执行一致性,xxl-job采用并发加锁策略。调度中心通过获取数据库中的xxl_job_lock悲观锁,防止同一时刻多个实例并发执行。执行器通过任务队列进一步确保任务只执行一次,确保任务的正确调度和执行。
WAVM源码解析 —— WASI接口定义、内部实例初始化及实例链接
从前面文章中,我们知道WAVM执行WASM程序的流程。本文着重解析第三、四、五部分:生成内部实例、调用接口与实例链接。
生成内部实例的关键在于调用接口,接口参数是Intrinsics::Module类型的列表。内部实例不基于WASM程序,仅关注导入导出段内容,因此Intrinsics::Module类仅包含Function、Global、Table、Memory等元素。宏定义WAVM_INTRINSIC_MODULE_REF(wasi)生成一个Intrinsics::Module对象,其实际实现对应WASI标准接口。
初始化Intrinsics::Module对象通过宏函数WAVM_DEFINE_INTRINSIC_FUNCTION完成,这个宏定义接口并将其赋值给Intrinsics::Module对象。以sched_yield为例,宏定义后生成一个静态的Intrinsics::Function对象,通过构造函数自动赋值到Intrinsics::Module中。
Intrinsics::instantiateModule()函数执行步骤包括:将moduleRefs转化为IR::Module,编译生成的IR::Module,调用实例化接口函数生成内部实例。关键步骤为将外部接口函数转化为WASM格式的thunks函数,并将thunks导出。最终,通过实例化创建出内部实例,与普通实例的主要区别在于导入段内容的获取方式。
链接器实现实例化的一大功能,即提供查询导出项的接口。核心逻辑简单,具体实现则较为复杂,本文不展开解析。关于实例化细节,后续文章将深入探讨。
浅说gocron:基于cron二次开发的定时任务集中调度平台
gocron项目基于cron进行二次开发,旨在提供一个定时任务集中调度平台。核心代码位于service/task.go文件中。此项目在实习期间被应用于二次开发,但由于gocron相关资料稀缺,本文旨在概述作者对cron和gocron代码的理解,并自行绘制流程图。
首先,了解cron表达式,它由六部分组成:秒、分、时、日、月、周,具体细节请参考相关资料。
gocron框架由cron架构衍生而来,由于网络资源有限,作者制作了流程图来辅助理解。
阅读源码的起点是gocron对cron的封装,使用cron实现定时任务。在service/task.go中,声明了*cron.Cron类型的serviceCron,初始化时实例化cron对象,从数据库获取任务并添加到定时任务列表中,同时调用task.Add()封装cron中的AddFunc。
深入研究gocron的核心代码,cron使用的是robfig/cron库,而非官方文档中提及的版本。源码阅读可以从cron.go开始,重点关注run()方法,该方法使用select多路复用实现任务执行流程。
任务执行步骤涉及监听定时器触发、运行过程中的添加作业、快照、停止信号以及移除作业的信号。cron在run()中运行时,通过内部for循环嵌套监听上述五种信号,按照任务下次执行时间排序,每次监听到信号,执行相应的任务并更新状态。
与gocron类似,jakecoffman/cron项目也采用类似流程,但触发信号有所不同,同时将原有延时任务独立为延迟队列项目。
gocron提供了shell和http两种任务执行方式,二次开发时,可参考其Run()方法,添加自定义回调功能,如微服务回调、springcloud回调。
在gocron中,通过Handler接口实现了http和rpc任务处理,其中HttpHandler直接进行请求和响应,而RPCHandler将任务通过rpc分发至多个host,每次开启一个go程,使用容量为host数量的resultChan进行通信。
每个任务开始执行前,在tasklog表中新增一条日志,记录开始执行任务和createjob过程。在执行过程中,任务更新其下次执行的时间,并监听特定信号进行操作。任务结束后,更新日志状态,完成任务执行记录。
整体而言,gocron项目基于cron框架,通过二次开发提供了一套灵活、高效的定时任务管理平台,适用于多种应用场景。通过深入了解其核心代码,开发者可以更高效地进行二次开发和定制化需求满足。