From cdea9d9b4d089bedfe66e8cdc618128cde3a4e8b Mon Sep 17 00:00:00 2001 From: youngLake <35251372+youngLake@users.noreply.github.com> Date: Mon, 22 Jul 2019 18:21:37 +0800 Subject: [PATCH 1/2] #89 Run a Spring Batch Job With Quartz.md --- .../#89 Run a Spring Batch Job With Quartz.md | 466 ++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 translation/#89 Run a Spring Batch Job With Quartz.md diff --git a/translation/#89 Run a Spring Batch Job With Quartz.md b/translation/#89 Run a Spring Batch Job With Quartz.md new file mode 100644 index 0000000..3208402 --- /dev/null +++ b/translation/#89 Run a Spring Batch Job With Quartz.md @@ -0,0 +1,466 @@ +# Run a Spring Batch Job With Quartz + +# 通过Quatrz来运行Spring批量任务 + +## Want to learn how to run a Spring Batch job with Quartz? Check out this tutorial to learn how to with the Quartz scheduler and sample code! + +## 想知道如何用Quartz来运行一个Spring的批量任务?看看这篇教程来学习如何用Quartz调度程序来运行Spring批量任务,此外还有示例代码! + +--- + +Hey, folks. In this tutorial, we will see how a Spring Batch job runs using a Quartz scheduler. +If you are not sure about the basics of Spring Batch, you can visit my tutorial [here](https://dzone.com/articles/spring-batch). + +在这篇教程中,我们将会理解如何用Quartz调度程序来运行Spring批量任务。 +如果你对Spring Batch的基础不是很好的话可以访问我的[这篇教程](https://dzone.com/articles/spring-batch) + +Now, as we know, Spring Batch jobs are used whenever we want to run any business-specific code or run/generate any reports +at any particular time/day. There are two ways to implement jobs: `tasklet` and `chunks` . +In this tutorial, I will create a simple job using a `tasklet`, which will print a `logger`. + +正如我们现在所了解的,无论何时我们想运行任何处理特定事情的代码或者在任何特定的时间来处理或者生成任何报告都会用到Spring Batch任务。 +这有两种途径实现任务: `tasklet` 和 `chunks` 。在这篇教程中我将会使用 `tasklet` 来创建一个简单的任务,这个任务将用来输出 `logger` + +The basic idea here is what all configurations are required to make this job run. +We will use Spring Boot to bootstrap our application. + +第一步就是配置可以使这个任务可以运行的所有的所需的配置,我们将使用Spring Boot来独立创建我们的应用。 + +#### We require below two dependencies in pom.xml for having Spring Batch and Quartz in our application. + +#### 在我们的应用中需要在 pom.xml 文件中添加下面的两项依赖来添加 Spring Batch 和 Quartz + + +```xml + + + org.springframework.batch + spring-batch-core + 4.0.1.RELEASE + + + + org.quartz-scheduler + quartz + 2.3.0 + +``` + +#### Now, let's see what all configurations we require in our code to run the job. + +#### 现在我们来看看在我们的代码中所需的所有配置来运行这个任务 + +##### 1. BatchConfiguration.java: + +```java +package com.category.batch.configurations; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.support.ApplicationContextFactory; +import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar; +import org.springframework.batch.core.configuration.support.DefaultJobLoader; +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.batch.core.configuration.support.MapJobRegistry; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +@Configuration +@EnableBatchProcessing +@Import({ + BatchJobsDetailedConfiguration.class +}) +public class BatchConfiguration { + @Bean + public JobRegistry jobRegistry() { + return new MapJobRegistry(); + } + @Bean + public ResourcelessTransactionManager transactionManager() { + return new ResourcelessTransactionManager(); + } + @Bean + public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception { + MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager); + mapJobRepositoryFactoryBean.setTransactionManager(transactionManager); + return mapJobRepositoryFactoryBean.getObject(); + } + @Bean + public JobLauncher jobLauncher(JobRepository jobRepository) throws Exception { + SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher(); + simpleJobLauncher.setJobRepository(jobRepository); + simpleJobLauncher.afterPropertiesSet(); + return simpleJobLauncher; + } + @Bean + public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) { + JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor(); + jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry()); + return jobRegistryBeanPostProcessor; + } +} +``` + +Let's go one-by-one: + ++ `@Configuration`: This specifies that this class will contain beans and will be instantiated at load time. + ++ `@EnableBatchProcessing`: This enables the Spring Batch features and provides a base configuration for setting up batch jobs. + ++ `@Import({BatchJobsDetailedConfiguration.class})`: This will import some other configurations required, +which we will see later. + ++ `JobRegistry`: This interface is used to register the jobs. + ++ `ResourcelessTransactionManager`: This class is used when you want to run the job using any database persistence. + ++ `JobRepository`: This contains all the metadata of the job, which returns a `MapJobRepositoryFactoryBean` used for non-persistent DAO implementations. + ++ `JobLauncher`: This is used to launch a job, requires jobRepository as a dependency. + ++ `JobRegistryBeanPostProcessor`: This is used to register a job in the `jobRegistry`, which returns the `jobRegistry`. + +我们一步一步的看: + ++ `@Configuration`: 这说明这个被它标注的类将会包含 beans 而且会在加载时初始化。 + ++ `@EnableBatchProcessing`:这使得 Spring Batch 的特性得以启用并且为设置批量任务提供了一个基础的配置。 + ++ `@Import({BatchJobsDetailedConfiguration.class})`: 这将会导入一些其他的所需配置,我们将会在稍后看到他。 + ++ `JobRegistry`: 用来注册任务的接口。 + ++ `ResourcelessTransactionManager`:这个类在你想用任何数据库持久性来运行任务时使用 + ++ `JobRepository`:这包含了任务的元数据,这将会返回一个 `MapJobRepositoryFactoryBean` ,这个bean用来实现非持久性的DAO + ++ `JobLauncher`:这个被用来加载一个任务,需要依赖 jobRepository + ++ `JobRegistryBeanPostProcessor`: 这个用来在 `jobRegistry` 里注册任务的,并返回 `jobRegistry`。 + +Let's go to the imported class now. + +我们现在来看看导入的类 + +##### 2. BatchJobsDetailedConfiguration.java: + +```java +package com.category.batch.configurations; +import java.util.HashMap; +import java.util.Map; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.support.ApplicationContextFactory; +import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.NoSuchJobException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.CronTriggerFactoryBean; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import com.category.batch.job.JobLauncherDetails; +import com.category.batch.reports.config.ReportsConfig; +@Configuration +public class BatchJobsDetailedConfiguration { + @Autowired + private JobLauncher jobLauncher; + @Bean(name = "reportsDetailContext") + public ApplicationContextFactory getApplicationContext() { + return new GenericApplicationContextFactory(ReportsConfig.class); + } + @Bean(name = "reportsDetailJob") + public JobDetailFactoryBean jobDetailFactoryBean() { + JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean(); + jobDetailFactoryBean.setJobClass(JobLauncherDetails.class); + jobDetailFactoryBean.setDurability(true); + Map < String, Object > map = new HashMap < > (); + map.put("jobLauncher", jobLauncher); + map.put("jobName", ReportsConfig.jobName); + jobDetailFactoryBean.setJobDataAsMap(map); + return jobDetailFactoryBean; + } + @Bean(name = "reportsCronJob") + public CronTriggerFactoryBean cronTriggerFactoryBean() { + CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); + cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean().getObject()); + cronTriggerFactoryBean.setCronExpression("0 0/1 * 1/1 * ? *"); + return cronTriggerFactoryBean; + } + @Bean + public SchedulerFactoryBean schedulerFactoryBean(JobRegistry jobRegistry) throws NoSuchJobException { + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); + schedulerFactoryBean.setTriggers(cronTriggerFactoryBean().getObject()); + schedulerFactoryBean.setAutoStartup(true); + Map < String, Object > map = new HashMap < > (); + map.put("jobLauncher", jobLauncher); + map.put("jobLocator", jobRegistry); + schedulerFactoryBean.setSchedulerContextAsMap(map); + return schedulerFactoryBean; + } +} +``` + +Let's dig into this: + ++ `ApplicationContextFactory`: This interface is primarily useful when creating a new `ApplicationContext` per execution of +a job. It's better to create a sepearte `applicationContext` for each job. + ++ `JobDetailFactoryBean`: This is used to create a Quartz job detail instance. This class will set a job class, +which we will see later. It creates a map that will define and set the job name using a class and `joblauncher`. + ++ `CronTriggerFactoryBean`: This is used to create a `Quartz` cron trigger instance. +This will set the `jobDetail` created earlier and then the `cron` expression when this job will run +You can set the `cron` expressions as per your need. Cron expressions can be calculated from http://cronmaker.com. + ++ `SchedulerFactoryBean`: This is used to create a Quartz scheduler instance and allows for the registration of `JobDetails` , +`Calendars` , and `Triggers`, automatically starting the scheduler on initialization and shutting it down on destruction. + +让我们详细了解一下这些: + ++ `ApplicationContextFactory`:当每个执行任务创建一个新的 `ApplicationContext` 时通常都用这个接口。 + ++ `JobDetailFactoryBean`:这个被用来创建一个 `Quartz` 任务的具体实例,这个类将用于设置一个任务类。 + ++ `CronTriggerFactoryBean`:这个被用来创建一个 `Quartz` 定时触发器实例,它将使 `jobDetail` 提前创建好,然后你可以自己 +设置`cron` 表达式来使你的任务得以运行。 定时任务表达式可以在这里 http://cronmaker.com 计算 + ++ `SchedulerFactoryBean`:这个被用来创建一个 Quartz 调度程序实例,考虑到 `JobDetails` ,`Calendars` , 和 `Triggers` 的注册,以及在初始化时 +自动开启调度程序和销毁时自动关闭,也需要用到它 + +Let's check out the `JobLauncherDetails` class: + +我们来看看 `JobLauncherDetails` 这个类: + +##### 3. JobLauncherDetails.java: + +```java +package com.category.batch.job; +import java.util.Map; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersInvalidException; +import org.springframework.batch.core.configuration.JobLocator; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.NoSuchJobException; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.QuartzJobBean; +public class JobLauncherDetails extends QuartzJobBean { + static final String JOB_NAME = "jobName"; + public void setJobLocator(JobLocator jobLocator) { + this.jobLocator = jobLocator; + } + public void setJobLauncher(JobLauncher jobLauncher) { + this.jobLauncher = jobLauncher; + } + private JobLocator jobLocator; + private JobLauncher jobLauncher; + @Override + protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters(); + try { + Map < String, Object > jobDataMap = jobExecutionContext.getMergedJobDataMap(); + String jobName = (String) jobDataMap.get(JOB_NAME); + jobLauncher.run(jobLocator.getJob(jobName), jobParameters); + } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException + | + JobParametersInvalidException e) { + e.printStackTrace(); + } catch (NoSuchJobException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} +``` + +This class has an overridden `executeInternal` method of the `QuartzJobBean` class, +which takes the `jobdetails` from the map, which were already set before some of the `jobParameters` , +and then executes the `jobLauncher.run()` to run the job as seen in the code. + +这个类重写了 `QuartzJobBean` 类的 `executeInternal` 方法。从一个 map 里获取早已在 `jobParameters` 里设置好了的 `jobdetials` , +然后正如代码中看到的,执行 `jobLauncher.run()` 来运行任务 + +Lets visit the ReportsConfig class. + +我们来看看 ReportsConfig class。 + +##### 4.ReportsConfig.java: + +```java +package com.category.batch.reports.config; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.DuplicateJobException; +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.configuration.support.ReferenceJobFactory; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.category.batch.reports.tasklet.ReportTasklet; +@Configuration +public class ReportsConfig { + @Autowired + private JobRegistry jobRegistry; + public final static String jobName = "ReportsJob1"; + public JobBuilderFactory getJobBuilderFactory() { + return jobBuilderFactory; + } + public void setJobBuilderFactory(JobBuilderFactory jobBuilderFactory) { + this.jobBuilderFactory = jobBuilderFactory; + } + @Autowired + private Tasklet taskletstep; + @Autowired + private JobBuilderFactory jobBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; + @Bean + public ReportTasklet reportTasklet() { + return new ReportTasklet(); + } + @Bean + public Job job() throws DuplicateJobException { + Job job = getJobBuilderFactory().get(jobName).start(getStep()).build(); + return job; + } + @Bean + public Step getStep() { + return stepBuilderFactory.get("step").tasklet(reportTasklet()).build(); + } +} +``` + +The main purpose of the class is having configurations related to each job. +You will have a separate config for each job as this. As you can see, +we create the `tasklet` here, which we will see later. Also, we define and return the Job, +step using a `JobBuilderFactory`, and `StepBuilderFactory`. +These factories will automatically set the `JobRepository` for you. + +这个类的主要目的是把配置关联到每个任务。在这个类里每个任务都有各自的配置。正如你看到的,此处我们创建了 `tasklet`,我们稍后会看到它。 +我们也定义并返回了一个任务,接着用 `JobBuilderFactory`, 和 `StepBuilderFactory` ,这些工厂类会自动为你设置 `jobRepository`。 + +Let's go to the ReportTasklet, which is our job to be run. + +来看看我们将要运行的任务 `ReportTasklet`。 + +##### 5. ReportTasklet.java: + +```java +package com.category.batch.reports.tasklet; +import java.util.logging.Logger; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.context.annotation.Configuration; +@Configuration +public class ReportTasklet implements Tasklet { + private static final Logger logger = Logger.getLogger(ReportTasklet.class.getName()); + @Override + public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) { + try { + logger.info("Report's Job is running. Add your business logic here........."); + } catch (Exception e) { + e.printStackTrace(); + } + return RepeatStatus.FINISHED; + } +} +``` + +This class has a execute method that will be ran when the job is ran through the `jobLauncher.run()` from the `JobLauncherDetails` class. +You can define your business logic that needs to be executed here. + +当任务执行到 `JobLauncherDetails` 的 `jobLauncher.run()` 方法,上面的这个类的方法将被执行。 + +We will need some configuration in application.properties as below: + +我们需要在 application.properties 做如下配置: + +##### 6. application.properties + +``` +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration +spring.batch.job.enabled=false +``` + +The first property is required to disable the datasource— only for testing purposes and is not required in production. + +第一个属性被用来禁用数据源——只有使用于测试环境不用于生产环境 + +The second property is when before the server starts, the job is run. To avoaid this, we require this property. + +当服务开始时,任务会运行,为了避免此种情况,我们设置第二个属性 + +Now, finally, let's go to the application class. This should be self-explanatory. + +最终,我们来看看应用类,这应该不用多说了。 + +##### 7. BatchApplication.java: + +```java +package com.category.batch; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) +public class BatchApplication { + public static void main(String[] args) { + SpringApplication.run(BatchApplication.class, args); + } +} +``` + +Enough Configurations! Let's run this application and see the output. +We have set the cron to 1 minute. After 1 minute, the job will be run. + +足够的配置可以运行任务了,让我们看看输出。我们设置了一分钟的定时任务。1分钟之后任务将会运行。 + + +``` +2018-09-14 11:04:18.648 INFO 7008 --- [ost-startStop-1] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance. +2018-09-14 11:04:18.648 INFO 7008 --- [ost-startStop-1] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.0 +2018-09-14 11:04:18.653 INFO 7008 --- [ost-startStop-1] org.quartz.core.QuartzScheduler : JobFactory set to: org.springframework.scheduling.quartz.AdaptableJobFactory@b29e7d6 +2018-09-14 11:04:19.578 INFO 7008 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-14 11:04:20.986 INFO 7008 --- [ost-startStop-1] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@74a6e16d: startup date [Fri Sep 14 11:04:12 IST 2018]; root of context hierarchy +2018-09-14 11:04:21.264 INFO 7008 --- [ost-startStop-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) +2018-09-14 11:04:21.268 INFO 7008 --- [ost-startStop-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) +2018-09-14 11:04:21.356 INFO 7008 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-14 11:04:21.356 INFO 7008 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] +2018-09-14 11:04:22.526 INFO 7008 --- [ost-startStop-1] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup +2018-09-14 11:04:22.555 INFO 7008 --- [ost-startStop-1] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647 +2018-09-14 11:04:22.556 INFO 7008 --- [ost-startStop-1] o.s.s.quartz.SchedulerFactoryBean : Starting Quartz Scheduler now +2018-09-14 11:04:22.556 INFO 7008 --- [ost-startStop-1] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED started. +2018-09-14 11:04:22.578 INFO 7008 --- [ost-startStop-1] com.category.batch.ServletInitializer : Started ServletInitializer in 17.386 seconds (JVM running for 26.206) +2018-09-14 11:04:23.395 INFO 7008 --- [ main] org.apache.coyote.ajp.AjpNioProtocol : Starting ProtocolHandler ["ajp-nio-8009"] +2018-09-14 11:04:23.399 INFO 7008 --- [ main] org.apache.catalina.startup.Catalina : Server startup in 24866 ms +2018-09-14 11:05:02.889 INFO 7008 --- [ryBean_Worker-1] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=ReportsJob1]] launched with the following parameters: [{time=1536903301155}] +2018-09-14 11:05:03.262 INFO 7008 --- [ryBean_Worker-1] o.s.batch.core.job.SimpleStepHandler : Executing step: [step] +2018-09-14 11:05:03.503 INFO 7008 --- [ryBean_Worker-1] c.c.batch.reports.tasklet.ReportTasklet : Report's Job is running. Add your business logic here......... +2018-09-14 11:05:03.524 INFO 7008 --- [ryBean_Worker-1] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=ReportsJob1]] completed with the following parameters: [{time=1536903301155}] and the following status: [COMPLETED] +``` + +The bold lines indicate your job ran and completed successfully. That's all for this tutorial. +Please comment if you would like to add anything. Happy learning! + +加粗线表明你的任务已经成功地运行并完成。这就是此篇教程的全部内容了。如果你想加些其他的请在下方评论,欢迎学习! From 664356a9c509f13f6d6a6a2fde6f350f5db04ae4 Mon Sep 17 00:00:00 2001 From: youngLake <35251372+youngLake@users.noreply.github.com> Date: Mon, 22 Jul 2019 20:41:04 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=B8=8D=E5=A4=AA=E9=80=9A=E9=A1=BA=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translation/#89 Run a Spring Batch Job With Quartz.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translation/#89 Run a Spring Batch Job With Quartz.md b/translation/#89 Run a Spring Batch Job With Quartz.md index 3208402..b756292 100644 --- a/translation/#89 Run a Spring Batch Job With Quartz.md +++ b/translation/#89 Run a Spring Batch Job With Quartz.md @@ -18,7 +18,7 @@ Now, as we know, Spring Batch jobs are used whenever we want to run any business at any particular time/day. There are two ways to implement jobs: `tasklet` and `chunks` . In this tutorial, I will create a simple job using a `tasklet`, which will print a `logger`. -正如我们现在所了解的,无论何时我们想运行任何处理特定事情的代码或者在任何特定的时间来处理或者生成任何报告都会用到Spring Batch任务。 +正如我们现在所了解的,无论何时我们想运行任何处理特定事情的代码,或者在任何特定的时间来处理或生成任何报告都会用到Spring Batch任务。 这有两种途径实现任务: `tasklet` 和 `chunks` 。在这篇教程中我将会使用 `tasklet` 来创建一个简单的任务,这个任务将用来输出 `logger` The basic idea here is what all configurations are required to make this job run. @@ -463,4 +463,4 @@ We have set the cron to 1 minute. After 1 minute, the job will be run. The bold lines indicate your job ran and completed successfully. That's all for this tutorial. Please comment if you would like to add anything. Happy learning! -加粗线表明你的任务已经成功地运行并完成。这就是此篇教程的全部内容了。如果你想加些其他的请在下方评论,欢迎学习! +加粗线部分的输出表明你的任务已经成功地完成了运行。这就是此篇教程的全部内容了。如果你想加些其他的请在下方评论,欢迎学习!