Update TaskLifecycleListener to use SmartLifecycle

This commit changes the starting point of a task from the point when the
ApplicationContext issues the ContextRefreshedEvent to
SmartLifecycle#start.  This is a more accurate point of start for a task
in that all beans should now be available.  It also allows us to clean
up many ApplicationContext hacks that were present to get around the
fact that many beans were not ready when a Task was attempting to begin.

Resolves spring-cloud/spring-cloud-task#107
This commit is contained in:
Michael Minella
2016-03-11 14:17:02 -06:00
committed by Glenn Renfro
parent 7c8fc5f50e
commit f35f8ef52d
17 changed files with 384 additions and 310 deletions

View File

@@ -15,14 +15,19 @@
*/
package org.springframework.cloud.task.batch.configuration;
import java.util.Collection;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.task.batch.listener.TaskBatchExecutionListener;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;
/**
* Provides auto configuration for the {@link TaskBatchExecutionListener}.
@@ -39,9 +44,24 @@ public class TaskBatchAutoConfiguration {
return new TaskBatchExecutionListenerBeanPostProcessor();
}
@Bean
@ConditionalOnMissingBean
public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(ConfigurableApplicationContext context) {
return new TaskBatchExecutionListenerFactoryBean(context);
@Configuration
@ConditionalOnMissingBean(name = "taskBatchExecutionListener")
public static class TaskBatchExecutionListenerAutoconfiguration {
@Autowired(required = false)
private Collection<DataSource> dataSources;
@Bean
public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(TaskExplorer taskExplorer) {
if(!CollectionUtils.isEmpty(dataSources) && dataSources.size() == 1) {
return new TaskBatchExecutionListenerFactoryBean(dataSources.iterator().next(), taskExplorer);
}
else if(CollectionUtils.isEmpty(dataSources)) {
return new TaskBatchExecutionListenerFactoryBean(null, taskExplorer);
}
else {
throw new IllegalStateException("Expected one datasource and found " + dataSources.size());
}
}
}
}

View File

@@ -27,10 +27,7 @@ import org.springframework.cloud.task.batch.listener.support.MapTaskBatchDao;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link FactoryBean} for a {@link TaskBatchExecutionListener}. Provides a jdbc based
@@ -41,19 +38,15 @@ import org.springframework.util.StringUtils;
*/
public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBatchExecutionListener> {
private ConfigurableApplicationContext context;
private TaskBatchExecutionListener listener;
private String dataSourceName;
private DataSource dataSource;
/**
* @param context the current application context
*/
public TaskBatchExecutionListenerFactoryBean(ConfigurableApplicationContext context) {
Assert.notNull(context, "A ConfigurableApplicationContext is required");
private TaskExplorer taskExplorer;
this.context = context;
public TaskBatchExecutionListenerFactoryBean(DataSource dataSource, TaskExplorer taskExplorer) {
this.dataSource = dataSource;
this.taskExplorer = taskExplorer;
}
@Override
@@ -61,24 +54,11 @@ public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBa
if(listener != null){
return listener;
}
if(this.context.getBeanNamesForType(DataSource.class).length == 0) {
if(this.dataSource == null) {
this.listener = new TaskBatchExecutionListener(getMapTaskBatchDao());
}
else {
DataSource dataSource;
if(StringUtils.hasText(this.dataSourceName)) {
dataSource = (DataSource) this.context.getBean(this.dataSourceName);
}
else {
if(this.context.getBeanNamesForType(DataSource.class).length == 1) {
dataSource = this.context.getBean(DataSource.class);
}
else {
throw new IllegalStateException("Unable to determine what DataSource to use");
}
}
this.listener = new TaskBatchExecutionListener(new JdbcTaskBatchDao(dataSource));
this.listener = new TaskBatchExecutionListener(new JdbcTaskBatchDao(this.dataSource));
}
return listener;
@@ -94,27 +74,21 @@ public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBa
return true;
}
public void setDataSourceName(String dataSourceName) {
this.dataSourceName = dataSourceName;
}
private MapTaskBatchDao getMapTaskBatchDao() throws Exception {
Field taskExecutionDaoField = ReflectionUtils.findField(SimpleTaskExplorer.class, "taskExecutionDao");
taskExecutionDaoField.setAccessible(true);
MapTaskExecutionDao taskExecutionDao;
TaskExplorer taskExplorer = this.context.getBean(TaskExplorer.class);
if(AopUtils.isJdkDynamicProxy(taskExplorer)) {
SimpleTaskExplorer dereferencedTaskRepository = (SimpleTaskExplorer) ((Advised) taskExplorer).getTargetSource().getTarget();
if(AopUtils.isJdkDynamicProxy(this.taskExplorer)) {
SimpleTaskExplorer dereferencedTaskRepository = (SimpleTaskExplorer) ((Advised) this.taskExplorer).getTargetSource().getTarget();
taskExecutionDao =
(MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, dereferencedTaskRepository);
}
else {
taskExecutionDao =
(MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, taskExplorer);
(MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, this.taskExplorer);
}
return new MapTaskBatchDao(taskExecutionDao.getBatchJobAssociations());

View File

@@ -18,11 +18,14 @@ package org.springframework.cloud.task.batch.listener;
import java.util.Iterator;
import java.util.Set;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Test;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
@@ -35,21 +38,28 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration;
import org.springframework.cloud.task.batch.configuration.TaskBatchExecutionListenerFactoryBean;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.configuration.TaskConfigurer;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import static org.junit.Assert.assertEquals;
/**
* @author Michael Minella
*/
public class BatchTaskExecutionListenerTests {
public class TaskBatchExecutionListenerTests {
private ConfigurableApplicationContext applicationContext;
@@ -62,7 +72,29 @@ public class BatchTaskExecutionListenerTests {
@Test
public void testAutobuiltDataSource() {
this.applicationContext = SpringApplication.run(new Object[] {JobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, TaskBatchAutoConfiguration.class, BatchAutoConfiguration.class, TaskBatchAutoConfiguration.class}, new String[0]);
this.applicationContext = SpringApplication.run(new Object[] {JobConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class,
BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class}, new String[0]);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", new PageRequest(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());
assertEquals(1, jobExecutionIds.size());
assertEquals(1, taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId());
}
@Test
public void testMultipleDataSources() {
this.applicationContext = SpringApplication.run(new Object[] {JobConfigurationMultipleDataSources.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class,
BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class}, new String[0]);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
@@ -76,7 +108,11 @@ public class BatchTaskExecutionListenerTests {
@Test
public void testAutobuiltDataSourceNoJob() {
this.applicationContext = SpringApplication.run(new Object[] {NoJobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, TaskBatchAutoConfiguration.class, BatchAutoConfiguration.class, TaskBatchAutoConfiguration.class}, new String[0]);
this.applicationContext = SpringApplication.run(new Object[] {NoJobConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class,
BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class}, new String[0]);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
@@ -89,7 +125,10 @@ public class BatchTaskExecutionListenerTests {
@Test
public void testMapBased() {
this.applicationContext = SpringApplication.run(new Object[] {JobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class, TaskBatchAutoConfiguration.class}, new String[0]);
this.applicationContext = SpringApplication.run(new Object[] {JobConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class}, new String[0]);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
@@ -103,7 +142,10 @@ public class BatchTaskExecutionListenerTests {
@Test
public void testMultipleJobs() {
this.applicationContext = SpringApplication.run(new Object[] {MultipleJobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class, TaskBatchAutoConfiguration.class}, new String[0]);
this.applicationContext = SpringApplication.run(new Object[] {MultipleJobConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class}, new String[0]);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
@@ -149,6 +191,72 @@ public class BatchTaskExecutionListenerTests {
}
}
@Configuration
@EnableBatchProcessing
@EnableTask
public static class JobConfigurationMultipleDataSources {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job job() {
return jobBuilderFactory.get("job")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
System.out.println("Executed");
return RepeatStatus.FINISHED;
}
}).build())
.build();
}
@Bean
@Primary
public DataSource myDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("myDataSource");
return builder.build();
}
@Bean
public DataSource incorrectDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("incorrectDataSource");
return builder.build();
}
@Bean
public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(TaskExplorer taskExplorer) {
return new TaskBatchExecutionListenerFactoryBean(myDataSource(), taskExplorer);
}
@Bean
public TaskConfigurer taskConfigurer() {
return new DefaultTaskConfigurer(myDataSource());
}
@Bean
public TaskRepositoryInitializer taskRepositoryInitializer() {
TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer();
taskRepositoryInitializer.setDataSource(myDataSource());
return taskRepositoryInitializer;
}
@Bean
public DefaultBatchConfigurer batchConfigurer() {
return new DefaultBatchConfigurer(myDataSource());
}
}
@Configuration
@EnableBatchProcessing
@EnableTask

View File

@@ -26,7 +26,6 @@ import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
import org.springframework.cloud.task.repository.support.SimpleTaskRepository;
import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
@@ -51,14 +50,25 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
private PlatformTransactionManager transactionManager;
private ConfigurableApplicationContext context;
private TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean;
public DefaultTaskConfigurer(ConfigurableApplicationContext context) {
this.context = context;
private DataSource dataSource;
/**
* @param dataSource references the {@link DataSource} to be used as the Task
* repository. If none is provided, a Map will be used (not recommended for
* production use.
*/
public DefaultTaskConfigurer(DataSource dataSource) {
this.dataSource = dataSource;
if(this.dataSource != null) {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource);
}
else {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();
}
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.context);
this.taskRepository = new SimpleTaskRepository(this.taskExecutionDaoFactoryBean);
this.taskExplorer = new SimpleTaskExplorer(this.taskExecutionDaoFactoryBean);
}
@@ -77,7 +87,7 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
public PlatformTransactionManager getTransactionManager() {
if(this.transactionManager == null) {
if(isDataSourceAvailable()) {
this.transactionManager = new DataSourceTransactionManager(this.context.getBean(DataSource.class));
this.transactionManager = new DataSourceTransactionManager(this.dataSource);
}
else {
this.transactionManager = new ResourcelessTransactionManager();
@@ -88,6 +98,6 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
}
private boolean isDataSourceAvailable() {
return this.context.getBeanNamesForType(DataSource.class).length == 1;
return this.dataSource != null;
}
}

View File

@@ -17,7 +17,6 @@
package org.springframework.cloud.task.configuration;
import java.util.Collection;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@@ -27,8 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.cloud.task.listener.TaskLifecycleListener;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutor;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactory;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
@@ -39,6 +37,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.CollectionUtils;
/**
* Base {@code Configuration} class providing common structure for enabling and using
@@ -54,6 +53,9 @@ public class SimpleTaskConfiguration {
protected static final Log logger = LogFactory.getLog(SimpleTaskConfiguration.class);
@Autowired(required = false)
private Collection<DataSource> dataSources;
@Autowired
private ConfigurableApplicationContext context;
@@ -62,34 +64,40 @@ public class SimpleTaskConfiguration {
private boolean initialized = false;
private TaskConfigurer configurer;
private TaskRepository taskRepository;
private TaskLifecycleListener taskLifecycleListener;
private TaskListenerExecutorFactoryBean taskListenerExecutorFactoryBean;
private PlatformTransactionManager platformTransactionManager;
private TaskExplorer taskExplorer;
@Bean
public TaskRepository taskRepository(){
return this.configurer.getTaskRepository();
return this.taskRepository;
}
@Bean
public TaskLifecycleListener taskLifecycleListener() {
return new TaskLifecycleListener(taskRepository(), taskNameResolver(), this.applicationArguments);
return this.taskLifecycleListener;
}
@Bean
public TaskListenerExecutor taskListenerExecutor(ConfigurableApplicationContext context) throws Exception
{
TaskListenerExecutorFactory taskListenerExecutorFactory =
new TaskListenerExecutorFactory(context);
return taskListenerExecutorFactory.getObject();
public TaskListenerExecutorFactoryBean taskListenerExecutor()
throws Exception {
return this.taskListenerExecutorFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager() {
return this.configurer.getTransactionManager();
return this.platformTransactionManager;
}
@Bean
public TaskExplorer taskExplorer() {
return this.configurer.getTaskExplorer();
return this.taskExplorer;
}
@Bean
@@ -101,8 +109,9 @@ public class SimpleTaskConfiguration {
public TaskRepositoryInitializer taskRepositoryInitializer() {
TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer();
if(this.context.getBeanNamesForType(DataSource.class).length == 1) {
taskRepositoryInitializer.setDataSource(context.getBean(DataSource.class));
if(!CollectionUtils.isEmpty(this.dataSources) && this.dataSources.size() == 1) {
DataSource next = this.dataSources.iterator().next();
taskRepositoryInitializer.setDataSource(next);
}
return taskRepositoryInitializer;
@@ -112,40 +121,56 @@ public class SimpleTaskConfiguration {
* Determines the {@link TaskConfigurer} to use.
*/
@PostConstruct
protected void initialize() {
protected void initialize() throws Exception {
if (initialized) {
return;
}
logger.debug("Getting Task Configurer");
if (configurer == null) {
configurer = getDefaultConfigurer(context.getBeansOfType(TaskConfigurer.class).values());
}
TaskConfigurer taskConfigurer = getDefaultConfigurer();
logger.debug(String.format("Using %s TaskConfigurer",
configurer.getClass().getName()));
taskConfigurer.getClass().getName()));
this.taskRepository = taskConfigurer.getTaskRepository();
this.taskListenerExecutorFactoryBean = new TaskListenerExecutorFactoryBean(context);
this.platformTransactionManager = taskConfigurer.getTransactionManager();
this.taskExplorer = taskConfigurer.getTaskExplorer();
this.taskLifecycleListener = new TaskLifecycleListener(this.taskRepository, taskNameResolver(), this.applicationArguments);
initialized = true;
}
private TaskConfigurer getDefaultConfigurer(Collection<TaskConfigurer> configurers) {
verifyEnvironment(configurers);
if (configurers == null || configurers.isEmpty()) {
this.configurer = new DefaultTaskConfigurer(this.context);
return this.configurer;
private TaskConfigurer getDefaultConfigurer() {
verifyEnvironment();
int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;
if (configurers < 1) {
if(!CollectionUtils.isEmpty(this.dataSources) && this.dataSources.size() == 1) {
return new DefaultTaskConfigurer(this.dataSources.iterator().next());
}
else {
return new DefaultTaskConfigurer(null);
}
}
else {
if(configurers == 1) {
return this.context.getBean(TaskConfigurer.class);
}
else {
throw new IllegalStateException("Expected one TaskConfigurer but found " + configurers);
}
}
this.configurer = configurers.iterator().next();
return this.configurer;
}
private void verifyEnvironment(Collection configurers){
private void verifyEnvironment(){
int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;
int dataSources = this.context.getBeanNamesForType(DataSource.class).length;
if (dataSources > 1) {
if(configurers == 0 && dataSources > 1) {
throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than" +
"one DataSource, found " + dataSources);
}
if (configurers.size() > 1) {
throw new IllegalStateException(
"To use a custom TaskConfigurer the context must contain precisely one, found "
+ configurers.size());
" one DataSource, found " + dataSources);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2016 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.
@@ -36,6 +36,7 @@ import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.Assert;
@@ -58,7 +59,7 @@ import org.springframework.util.Assert;
*
* @author Michael Minella
*/
public class TaskLifecycleListener implements ApplicationListener<ApplicationEvent>{
public class TaskLifecycleListener implements ApplicationListener<ApplicationEvent>, SmartLifecycle {
@Autowired(required = false)
private Collection<TaskExecutionListener> taskExecutionListeners;
@@ -106,11 +107,7 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ContextRefreshedEvent) {
doTaskStart();
started = true;
}
else if(applicationEvent instanceof ApplicationFailedEvent) {
if(applicationEvent instanceof ApplicationFailedEvent) {
this.applicationFailedEvent = (ApplicationFailedEvent) applicationEvent;
}
else if(applicationEvent instanceof ExitCodeEvent){
@@ -221,4 +218,37 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
endTime,taskExecution.getExitMessage(),
Collections.unmodifiableList(taskExecution.getParameters()));
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public void stop(Runnable callback) {
Assert.notNull(callback, "A callback is required");
callback.run();
}
@Override
public void start() {
doTaskStart();
this.started = true;
}
@Override
public void stop() {
}
@Override
public boolean isRunning() {
return this.started;
}
@Override
public int getPhase() {
return 0;
}
}

View File

@@ -33,6 +33,7 @@ import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.cloud.task.listener.TaskExecutionListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotationUtils;
@@ -40,7 +41,7 @@ import org.springframework.core.annotation.AnnotationUtils;
/**
* @author Glenn Renfro
*/
public class TaskListenerExecutorFactory implements FactoryBean<TaskListenerExecutor> {
public class TaskListenerExecutorFactoryBean implements FactoryBean<TaskExecutionListener> {
private final static Log logger = LogFactory.getLog(TaskListenerExecutor.class);
@@ -55,7 +56,7 @@ public class TaskListenerExecutorFactory implements FactoryBean<TaskListenerExec
private Map<Method, Object> failedTaskInstances;
public TaskListenerExecutorFactory(ConfigurableApplicationContext context){
public TaskListenerExecutorFactoryBean(ConfigurableApplicationContext context){
this.context = context;
}
@@ -161,5 +162,4 @@ public class TaskListenerExecutorFactory implements FactoryBean<TaskListenerExec
});
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -76,7 +76,7 @@ public class SimpleTaskRepository implements TaskRepository {
validateCreateInformation(startTime, taskName);
TaskExecution taskExecution =
taskExecutionDao.createTaskExecution(taskName, startTime, parameters);
logger.info("Creating: " + taskExecution.toString());
logger.debug("Creating: " + taskExecution.toString());
return taskExecution;
}

View File

@@ -23,10 +23,8 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.repository.dao.TaskExecutionDao;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link FactoryBean} implementation that creates the appropriate
@@ -38,12 +36,10 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
public static final String DEFAULT_TABLE_PREFIX = "TASK_";
private ConfigurableApplicationContext context;
private DataSource dataSource;
private TaskExecutionDao dao = null;
private String dataSourceName;
private String tablePrefix = DEFAULT_TABLE_PREFIX;
/**
@@ -54,37 +50,21 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
}
/**
* ApplicationContext provided will be used to obtain the appropriate
* {@link DataSource}.
* {@link DataSource} to be used.
*
* @param context context for this application
* @param dataSource {@link DataSource} to be used.
*/
public TaskExecutionDaoFactoryBean(ConfigurableApplicationContext context) {
Assert.notNull(context, "An ApplicationContext is required");
public TaskExecutionDaoFactoryBean(DataSource dataSource) {
Assert.notNull(dataSource, "A DataSource is required");
this.context = context;
this.dataSource = dataSource;
}
@Override
public TaskExecutionDao getObject() throws Exception {
if(this.dao == null) {
if(this.context != null) {
if (StringUtils.hasText(this.dataSourceName)) {
if(!this.context.containsBean(this.dataSourceName)) {
throw new IllegalArgumentException("The configured dataSourceName is not available in the current context");
}
DataSource dataSource = (DataSource) this.context.getBean(this.dataSourceName);
buildTaskExecutionDao(dataSource);
}
else if (this.context.getBeanNamesForType(DataSource.class).length == 1) {
DataSource dataSource = this.context.getBean(DataSource.class);
buildTaskExecutionDao(dataSource);
}
else {
this.dao = new MapTaskExecutionDao();
}
if (this.dataSource != null) {
buildTaskExecutionDao(this.dataSource);
}
else {
this.dao = new MapTaskExecutionDao();
@@ -104,17 +84,6 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
return true;
}
/**
* Identifies the {@link DataSource} to be used if one is to be used. By default, the
* name is not specified and it is assumed that only one DataSource exists within the
* context.
*
* @param dataSourceName bean id for the DataSource to be used.
*/
public void setDataSourceName(String dataSourceName) {
this.dataSourceName = dataSourceName;
}
/**
* Indicates a prefix for all of the task repository's tables if the jdbc option is
* used.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -16,38 +16,76 @@
package org.springframework.cloud.task;
import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertThat;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.cloud.task.configuration.SimpleTaskConfiguration;
import org.springframework.cloud.task.configuration.TaskConfigurer;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.support.SimpleTaskRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Verifies that the beans created by the SimpleTaskConfiguration.
*
* @author Glenn Renfro
* @author Michael Minella
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SimpleTaskConfiguration.class, PropertyPlaceholderAutoConfiguration.class})
public class SimpleTaskConfigurationTests {
@Autowired
private TaskRepository taskRepository;
private ConfigurableApplicationContext context;
@After
public void tearDown() {
if(this.context != null) {
this.context.close();
}
}
@Test
public void testRepository() throws Exception {
assertNotNull("testRepository should not be null", taskRepository);
TaskRepository clazz = (TaskRepository) ((Advised)taskRepository).getTargetSource().getTarget();
assertThat(clazz, instanceOf(SimpleTaskRepository.class));
}
}
this.context = new AnnotationConfigApplicationContext(SimpleTaskConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
TaskRepository taskRepository = this.context.getBean(TaskRepository.class);
assertNotNull("testRepository should not be null", taskRepository);
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(taskRepository);
assertEquals(targetClass, SimpleTaskRepository.class);
}
@Test(expected = BeanCreationException.class)
public void testMultipleConfigurers() {
this.context = new AnnotationConfigApplicationContext(MultipleConfigurers.class,
PropertyPlaceholderAutoConfiguration.class);
}
@Configuration
@EnableTask
public static class MultipleConfigurers {
@Bean
public TaskConfigurer taskConfigurer1() {
return new DefaultTaskConfigurer(null);
}
@Bean
public TaskConfigurer taskConfigurer2() {
return new DefaultTaskConfigurer(null);
}
}
}

View File

@@ -26,7 +26,6 @@ import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
import org.springframework.cloud.task.repository.support.SimpleTaskRepository;
import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;
import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
@@ -46,9 +45,6 @@ public class TestConfiguration implements InitializingBean {
@Autowired(required = false)
private ResourceLoader resourceLoader;
@Autowired
private ConfigurableApplicationContext applicationContext;
private TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean;
@Bean
@@ -83,6 +79,11 @@ public class TestConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.applicationContext);
if(this.dataSource != null) {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource);
}
else {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();
}
}
}

View File

@@ -16,24 +16,19 @@
package org.springframework.cloud.task.listener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Date;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.cloud.task.listener.annotation.AfterTask;
import org.springframework.cloud.task.listener.annotation.BeforeTask;
import org.springframework.cloud.task.listener.annotation.FailedTask;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutor;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactory;
import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.util.TestDefaultConfiguration;
import org.springframework.cloud.task.util.TestListener;
@@ -43,6 +38,11 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Verifies that the TaskExecutionListener invocations occur at the appropriate task
* lifecycle stages.
@@ -203,10 +203,9 @@ public class TaskExecutionListenerTests {
}
@Bean
public TaskListenerExecutor taskListenerExecutor(ConfigurableApplicationContext context) throws Exception
public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception
{
TaskListenerExecutorFactory taskListenerExecutorFactory = new TaskListenerExecutorFactory(context);
return taskListenerExecutorFactory.getObject();
return new TaskListenerExecutorFactoryBean(context);
}
public static class AnnotatedTaskListener extends TestListener {

View File

@@ -27,9 +27,6 @@ import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.util.TaskExecutionCreator;
import org.springframework.cloud.task.util.TestVerifierUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.springframework.test.util.AssertionErrors.assertTrue;
@@ -43,8 +40,7 @@ public class SimpleTaskRepositoryMapTests {
@Before
public void setUp() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(EmptyConfiguration.class);
this.taskRepository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean(context));
this.taskRepository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean());
}
@Test
@@ -52,8 +48,7 @@ public class SimpleTaskRepositoryMapTests {
TaskExecution expectedTaskExecution =
TaskExecutionCreator.createAndStoreTaskExecutionNoParams(taskRepository);
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
getSingleTaskExecutionFromMapRepository(taskRepository,
expectedTaskExecution.getExecutionId()));
getSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));
}
@Test
@@ -61,8 +56,7 @@ public class SimpleTaskRepositoryMapTests {
TaskExecution expectedTaskExecution =
TaskExecutionCreator.createAndStoreTaskExecutionWithParams(taskRepository);
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
getSingleTaskExecutionFromMapRepository(taskRepository,
expectedTaskExecution.getExecutionId()));
getSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));
}
@Test
@@ -75,8 +69,7 @@ public class SimpleTaskRepositoryMapTests {
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);
}
private TaskExecution getSingleTaskExecutionFromMapRepository(
TaskRepository repository, long taskExecutionId){
private TaskExecution getSingleTaskExecutionFromMapRepository(long taskExecutionId){
Map<Long, TaskExecution> taskMap = ((MapTaskExecutionDao)
((SimpleTaskRepository)taskRepository).getTaskExecutionDao()).getTaskExecutions();
assertTrue("taskExecutionId must be in MapTaskExecutionRepository",
@@ -91,7 +84,4 @@ public class SimpleTaskRepositoryMapTests {
expectedTaskExecution.setExitCode(-1);
TaskExecutionCreator.completeExecution(taskRepository, expectedTaskExecution);
}
@Configuration
public static class EmptyConfiguration{}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -16,11 +16,6 @@
package org.springframework.cloud.task.repository.support;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import javax.sql.DataSource;
import org.junit.After;
@@ -38,6 +33,11 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/**
* Verifies that task initialization occurs properly.
*
@@ -70,7 +70,7 @@ public class TaskDatabaseInitializerTests {
@Test
public void testNoDatabase() throws Exception {
this.context = new AnnotationConfigApplicationContext(EmptyConfiguration.class);
SimpleTaskRepository repository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean(this.context));
SimpleTaskRepository repository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean());
assertThat(repository.getTaskExecutionDao(), instanceOf(MapTaskExecutionDao.class));
MapTaskExecutionDao dao = (MapTaskExecutionDao) repository.getTaskExecutionDao();
assertEquals(0, dao.getTaskExecutions().size());

View File

@@ -15,9 +15,6 @@
*/
package org.springframework.cloud.task.repository.support;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import javax.sql.DataSource;
import org.junit.After;
@@ -30,11 +27,13 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Michael Minella
*/
@@ -64,20 +63,6 @@ public class TaskExecutionDaoFactoryBeanTests {
new TaskExecutionDaoFactoryBean(null);
}
@Test
public void testMapTaskExecutionDaoWithAppContext() throws Exception {
this.context = new GenericApplicationContext();
this.context.refresh();
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
TaskExecutionDao taskExecutionDao = factoryBean.getObject();
assertTrue(taskExecutionDao instanceof MapTaskExecutionDao);
TaskExecutionDao taskExecutionDao2 = factoryBean.getObject();
assertTrue(taskExecutionDao == taskExecutionDao2);
}
@Test
public void testMapTaskExecutionDaoWithoutAppContext() throws Exception {
@@ -95,7 +80,9 @@ public class TaskExecutionDaoFactoryBeanTests {
public void testDefaultDataSourceConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
DataSource dataSource = this.context.getBean(DataSource.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);
TaskExecutionDao taskExecutionDao = factoryBean.getObject();
assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao);
@@ -105,66 +92,14 @@ public class TaskExecutionDaoFactoryBeanTests {
assertTrue(taskExecutionDao == taskExecutionDao2);
}
@Test
public void testNonDefaultNameDataSourceConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
TaskExecutionDao taskExecutionDao = factoryBean.getObject();
assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao);
TaskExecutionDao taskExecutionDao2 = factoryBean.getObject();
assertTrue(taskExecutionDao == taskExecutionDao2);
}
@Test(expected = IllegalArgumentException.class)
public void testMissingCustomDataSourceNameConfiguration() throws Exception {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(context);
factoryBean.setDataSourceName("wrongName");
factoryBean.getObject();
}
@Test
public void testCustomDataSourceNameConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
factoryBean.setDataSourceName("notDataSource");
TaskExecutionDao taskExecutionDao = factoryBean.getObject();
assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao);
TaskExecutionDao taskExecutionDao2 = factoryBean.getObject();
assertTrue(taskExecutionDao == taskExecutionDao2);
}
@Test
public void testCustomDataSourceNameConfigurationWithMultipleDataSources() throws Exception {
this.context = new AnnotationConfigApplicationContext(MultipleDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
factoryBean.setDataSourceName("useThisDataSource");
JdbcTaskExecutionDao taskExecutionDao = (JdbcTaskExecutionDao) factoryBean.getObject();
Object usedDataSource = ReflectionTestUtils.getField(taskExecutionDao, "dataSource");
assertTrue(usedDataSource == this.context.getBean("useThisDataSource"));
TaskExecutionDao taskExecutionDao2 = factoryBean.getObject();
assertTrue(taskExecutionDao == taskExecutionDao2);
}
@Test
public void testSettingTablePrefix() throws Exception {
this.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context);
DataSource dataSource = this.context.getBean(DataSource.class);
TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);
factoryBean.setTablePrefix("foo_");
TaskExecutionDao taskExecutionDao = factoryBean.getObject();
@@ -180,35 +115,4 @@ public class TaskExecutionDaoFactoryBeanTests {
return builder.build();
}
}
@Configuration
public static class AlternativeDataSourceConfiguration {
@Bean
public DataSource notDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2);
return builder.build();
}
}
@Configuration
public static class MultipleDataSourceConfiguration {
@Bean
public DataSource useThisDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("useThisDataSource");
return builder.build();
}
@Bean
public DataSource dontUseThisDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("dontUseThisDataSource");
return builder.build();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -16,6 +16,8 @@
package org.springframework.cloud.task.util;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
@@ -35,6 +37,7 @@ import org.springframework.context.annotation.Configuration;
* Initializes the beans needed to test default task behavior.
*
* @author Glenn Renfro
* @author Michael Minella
*/
@Configuration
public class TestDefaultConfiguration implements InitializingBean {
@@ -72,6 +75,12 @@ public class TestDefaultConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
this.factoryBean = new TaskExecutionDaoFactoryBean(this.context);
if(this.context.getBeanNamesForType(DataSource.class).length == 1){
DataSource dataSource = this.context.getBean(DataSource.class);
this.factoryBean = new TaskExecutionDaoFactoryBean(dataSource);
}
else {
this.factoryBean = new TaskExecutionDaoFactoryBean();
}
}
}

View File

@@ -33,13 +33,10 @@ Spring Boot application configured to be a task (annotated with the `@EnableTask
annotation).
At the beginning of a task, an entry in the `TaskRepository` is created recording the
start event. This event is triggered via the `ContextRefreshEvent` being triggered by
Spring Framework.
start event. This event is triggered via `SmartLifecycle#start` being triggered by
Spring Framework. This indicates to the system that all beans are ready for use and is
before the execution of any of the `*Runner`s provided by Spring Boot.
NOTE: As Spring Cloud Task is expected to consist of a single application context. If
multiple application contexts are used (parent/child relationships for example), the first
`ContextRefreshEvent` that is published by Spring will be recorded as the start of the
task.
NOTE: The recording of a task will only occur upon the successful bootstrapping of an
`ApplicationContext`. If the context fails to bootstrap at all, the task's execution will
@@ -70,7 +67,7 @@ assumed to be 0.
|The name for the task as determined by the configured `TaskNameResolver`.
|`starTime`
|The time the task was started as indicated by the `ContextRefreshEvent`.
|The time the task was started as indicated by the `SmartLifecycle#start` call.
|`endTime`
|The time the task was completed as indicated by the `ContextClosedEvent`.