spring-batch JobRegistryBackgroundJobRunner 源码
spring-batch JobRegistryBackgroundJobRunner 代码
文件路径:/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
/*
* Copyright 2006-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.launch.support;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.DuplicateJobException;
import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory;
import org.springframework.batch.core.configuration.support.JobLoader;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
* <p>
* Command line launcher for registering jobs with a {@link JobRegistry}. Normally this
* will be used in conjunction with an external trigger for the jobs registered, e.g. a
* JMX MBean wrapper for a {@link JobLauncher}, or a Quartz trigger.
* </p>
*
* <p>
* With any launch of a batch job within Spring Batch, a Spring context containing the
* {@link Job} has to be created. Using this launcher, the jobs are all registered with a
* {@link JobRegistry} defined in a parent application context. The jobs are then set up
* in child contexts. All dependencies of the runner will then be satisfied by autowiring
* by type from the parent application context. Default values are provided for all fields
* except the {@link JobRegistry}. Therefore, if autowiring fails to set it then an
* exception will be thrown.
* </p>
*
* @author Dave Syer
*
*/
public class JobRegistryBackgroundJobRunner {
/**
* System property key that switches the runner to "embedded" mode (returning
* immediately from the main method). Useful for testing purposes.
*/
public static final String EMBEDDED = JobRegistryBackgroundJobRunner.class.getSimpleName() + ".EMBEDDED";
private static Log logger = LogFactory.getLog(JobRegistryBackgroundJobRunner.class);
private JobLoader jobLoader;
private ApplicationContext parentContext = null;
public static boolean testing = false;
final private String parentContextPath;
private JobRegistry jobRegistry;
private static List<Exception> errors = Collections.synchronizedList(new ArrayList<>());
/**
* @param parentContextPath the parentContextPath to be used by the
* JobRegistryBackgroundJobRunner.
*/
public JobRegistryBackgroundJobRunner(String parentContextPath) {
super();
this.parentContextPath = parentContextPath;
}
/**
* A loader for the jobs that are going to be registered.
* @param jobLoader the {@link JobLoader} to set
*/
public void setJobLoader(JobLoader jobLoader) {
this.jobLoader = jobLoader;
}
/**
* A job registry that can be used to create a job loader (if none is provided).
* @param jobRegistry the {@link JobRegistry} to set
*/
public void setJobRegistry(JobRegistry jobRegistry) {
this.jobRegistry = jobRegistry;
}
/**
* Public getter for the startup errors encountered during parent context creation.
* @return the errors
*/
public static List<Exception> getErrors() {
synchronized (errors) {
return new ArrayList<>(errors);
}
}
private void register(String[] paths) throws DuplicateJobException, IOException {
maybeCreateJobLoader();
for (int i = 0; i < paths.length; i++) {
Resource[] resources = parentContext.getResources(paths[i]);
for (int j = 0; j < resources.length; j++) {
Resource path = resources[j];
if (logger.isInfoEnabled()) {
logger.info("Registering Job definitions from " + Arrays.toString(resources));
}
GenericApplicationContextFactory factory = new GenericApplicationContextFactory(path);
factory.setApplicationContext(parentContext);
jobLoader.load(factory);
}
}
}
/**
* If there is no {@link JobLoader} then try and create one from existing bean
* definitions.
*/
private void maybeCreateJobLoader() {
if (jobLoader != null) {
return;
}
String[] names = parentContext.getBeanNamesForType(JobLoader.class);
if (names.length == 0) {
if (parentContext.containsBean("jobLoader")) {
jobLoader = parentContext.getBean("jobLoader", JobLoader.class);
return;
}
if (jobRegistry != null) {
jobLoader = new DefaultJobLoader(jobRegistry);
return;
}
}
jobLoader = parentContext.getBean(names[0], JobLoader.class);
return;
}
/**
* Supply a list of application context locations, starting with the parent context,
* and followed by the children. The parent must contain a {@link JobRegistry} and the
* child contexts are expected to contain {@link Job} definitions, each of which will
* be registered wit the registry.
*
* Example usage:
*
* <pre>
* $ java -classpath ... JobRegistryBackgroundJobRunner job-registry-context.xml job1.xml job2.xml ...
* </pre>
*
* The child contexts are created only when needed though the {@link JobFactory}
* interface (but the XML is validated on startup by using it to create a
* {@link BeanFactory} which is then discarded).
*
* The parent context is created in a separate thread, and the program will pause for
* input in an infinite loop until the user hits any key.
* @param args the context locations to use (first one is for parent)
* @throws Exception if anything goes wrong with the context creation
*/
public static void main(String... args) throws Exception {
Assert.state(args.length >= 1, "At least one argument (the parent context path) must be provided.");
final JobRegistryBackgroundJobRunner launcher = new JobRegistryBackgroundJobRunner(args[0]);
errors.clear();
if (logger.isInfoEnabled()) {
logger.info("Starting job registry in parent context from XML at: [" + args[0] + "]");
}
new Thread(new Runnable() {
@Override
public void run() {
try {
launcher.run();
}
catch (RuntimeException e) {
errors.add(e);
throw e;
}
}
}).start();
logger.info("Waiting for parent context to start.");
while (launcher.parentContext == null && errors.isEmpty()) {
Thread.sleep(100L);
}
synchronized (errors) {
if (!errors.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info(errors.size() + " errors detected on startup of parent context. Rethrowing.");
}
throw errors.get(0);
}
}
errors.clear();
// Paths to individual job configurations.
final String[] paths = new String[args.length - 1];
System.arraycopy(args, 1, paths, 0, paths.length);
if (logger.isInfoEnabled()) {
logger.info("Parent context started. Registering jobs from paths: " + Arrays.asList(paths));
}
launcher.register(paths);
if (System.getProperty(EMBEDDED) != null) {
launcher.destroy();
return;
}
synchronized (JobRegistryBackgroundJobRunner.class) {
System.out.println(
"Started application. Interrupt (CTRL-C) or call JobRegistryBackgroundJobRunner.stop() to exit.");
JobRegistryBackgroundJobRunner.class.wait();
}
launcher.destroy();
}
/**
* Unregister all the {@link Job} instances that were registered by this post
* processor.
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
private void destroy() throws Exception {
jobLoader.clear();
}
private void run() {
final ApplicationContext parent = new ClassPathXmlApplicationContext(parentContextPath);
parent.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,
false);
parent.getAutowireCapableBeanFactory().initializeBean(this, getClass().getSimpleName());
this.parentContext = parent;
}
/**
* If embedded in a JVM, call this method to terminate the main method.
*/
public static void stop() {
synchronized (JobRegistryBackgroundJobRunner.class) {
JobRegistryBackgroundJobRunner.class.notify();
}
}
}
相关信息
相关文章
spring-batch CommandLineJobRunner 源码
spring-batch DataFieldMaxValueJobParametersIncrementer 源码
spring-batch ExitCodeMapper 源码
spring-batch JvmSystemExiter 源码
spring-batch RunIdIncrementer 源码
spring-batch RuntimeExceptionTranslator 源码
spring-batch SimpleJobLauncher 源码
spring-batch SimpleJobOperator 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦