Support multiple task listener beans of same type

This commit is contained in:
Işık Erhan
2021-08-15 14:58:24 +03:00
parent a1d94ac475
commit 8b4352095d
3 changed files with 220 additions and 81 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 the original author or authors.
* Copyright 2018-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.
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,6 +46,7 @@ import org.springframework.core.annotation.AnnotationUtils;
* Initializes TaskListenerExecutor for a task.
*
* @author Glenn Renfro
* @author Isik Erhan
* @since 2.1.0
*/
public class TaskListenerExecutorObjectFactory
@@ -57,11 +59,11 @@ public class TaskListenerExecutorObjectFactory
private ConfigurableApplicationContext context;
private Map<Method, Object> beforeTaskInstances;
private Map<Method, Set<Object>> beforeTaskInstances;
private Map<Method, Object> afterTaskInstances;
private Map<Method, Set<Object>> afterTaskInstances;
private Map<Method, Object> failedTaskInstances;
private Map<Method, Set<Object>> failedTaskInstances;
public TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context) {
this.context = context;
@@ -141,20 +143,23 @@ public class TaskListenerExecutorObjectFactory
}
if (!beforeTaskMethods.isEmpty()) {
for (Method beforeTaskMethod : beforeTaskMethods.keySet()) {
this.beforeTaskInstances.put(beforeTaskMethod,
this.context.getBean(beanName));
this.beforeTaskInstances
.computeIfAbsent(beforeTaskMethod, k -> new LinkedHashSet<>())
.add(this.context.getBean(beanName));
}
}
if (!afterTaskMethods.isEmpty()) {
for (Method afterTaskMethod : afterTaskMethods.keySet()) {
this.afterTaskInstances.put(afterTaskMethod,
this.context.getBean(beanName));
this.afterTaskInstances
.computeIfAbsent(afterTaskMethod, k -> new LinkedHashSet<>())
.add(this.context.getBean(beanName));
}
}
if (!failedTaskMethods.isEmpty()) {
for (Method failedTaskMethod : failedTaskMethods.keySet()) {
this.failedTaskInstances.put(failedTaskMethod,
this.context.getBean(beanName));
this.failedTaskInstances
.computeIfAbsent(failedTaskMethod, k -> new LinkedHashSet<>())
.add(this.context.getBean(beanName));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-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.
@@ -31,18 +31,19 @@ import org.springframework.cloud.task.repository.TaskExecution;
* appropriate time.
*
* @author Glenn Renfro
* @author Isik Erhan
*/
public class TaskListenerExecutor implements TaskExecutionListener {
private Map<Method, Object> beforeTaskInstances;
private Map<Method, Set<Object>> beforeTaskInstances;
private Map<Method, Object> afterTaskInstances;
private Map<Method, Set<Object>> afterTaskInstances;
private Map<Method, Object> failedTaskInstances;
private Map<Method, Set<Object>> failedTaskInstances;
public TaskListenerExecutor(Map<Method, Object> beforeTaskInstances,
Map<Method, Object> afterTaskInstances,
Map<Method, Object> failedTaskInstances) {
public TaskListenerExecutor(Map<Method, Set<Object>> beforeTaskInstances,
Map<Method, Set<Object>> afterTaskInstances,
Map<Method, Set<Object>> failedTaskInstances) {
this.beforeTaskInstances = beforeTaskInstances;
this.afterTaskInstances = afterTaskInstances;
@@ -81,48 +82,55 @@ public class TaskListenerExecutor implements TaskExecutionListener {
}
private void executeTaskListener(TaskExecution taskExecution, Set<Method> methods,
Map<Method, Object> instances) {
Map<Method, Set<Object>> instances) {
for (Method method : methods) {
try {
method.invoke(instances.get(method), taskExecution);
}
catch (IllegalAccessException e) {
throw new TaskExecutionException(
"@BeforeTask and @AfterTask annotated methods must be public.",
e);
}
catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format(
"Failed to process @BeforeTask or @AfterTask"
+ " annotation because: %s",
e.getTargetException().getMessage()), e);
}
catch (IllegalArgumentException e) {
throw new TaskExecutionException("taskExecution parameter "
+ "is required for @BeforeTask and @AfterTask annotated methods",
e);
for (Object instance : instances.get(method)) {
try {
method.invoke(instance, taskExecution);
}
catch (IllegalAccessException e) {
throw new TaskExecutionException(
"@BeforeTask and @AfterTask annotated methods must be public.",
e);
}
catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format(
"Failed to process @BeforeTask or @AfterTask"
+ " annotation because: %s",
e.getTargetException().getMessage()), e);
}
catch (IllegalArgumentException e) {
throw new TaskExecutionException("taskExecution parameter "
+ "is required for @BeforeTask and @AfterTask annotated methods",
e);
}
}
}
}
private void executeTaskListenerWithThrowable(TaskExecution taskExecution,
Throwable throwable, Set<Method> methods, Map<Method, Object> instances) {
Throwable throwable, Set<Method> methods,
Map<Method, Set<Object>> instances) {
for (Method method : methods) {
try {
method.invoke(instances.get(method), taskExecution, throwable);
}
catch (IllegalAccessException e) {
throw new TaskExecutionException(
"@FailedTask annotated methods must be public.", e);
}
catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format(
"Failed to process @FailedTask " + "annotation because: %s",
e.getTargetException().getMessage()), e);
}
catch (IllegalArgumentException e) {
throw new TaskExecutionException("taskExecution and throwable parameters "
+ "are required for @FailedTask annotated methods", e);
for (Object instance : instances.get(method)) {
try {
method.invoke(instance, taskExecution, throwable);
}
catch (IllegalAccessException e) {
throw new TaskExecutionException(
"@FailedTask annotated methods must be public.", e);
}
catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format(
"Failed to process @FailedTask " + "annotation because: %s",
e.getTargetException().getMessage()), e);
}
catch (IllegalArgumentException e) {
throw new TaskExecutionException(
"taskExecution and throwable parameters "
+ "are required for @FailedTask annotated methods",
e);
}
}
}
}