Reputation: 24679
I would like to configure and use a Spring 4.1 AsyncUncaughtExceptionHandler. According to the Spring team (see relevant comment here) one will be able to configure an AsyncUncaughtExceptionHandler
either by with the <task:annotation-driven>
or by implementing AsyncConfigurer
as shown here:
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler() ;
}
Now my question is as follows: Is there another web-layer annotation similar to @ExceptionHandler
that would work like a AsyncUncaughtExceptionHandler
?
Upvotes: 2
Views: 1749
Reputation: 10075
As stated in the comment, here's an approach I've taken:
It's about async data imports so all classes are called Import...
What I did not do (yet) is the uncaught exception handling, but reading your post made me think about it and it should be straight forward with Spring-AOP wrapping the Importer.process() methods. This will not be global solution but it would be adaptable for a complete application by using a more generalized Result object.
The Controller uses the ImportRequests to get processing (or done) messages. The Importer itself is not removing the results from the map but this is delegated to the controller instead (A user is clicking delete). We also have a @Scheduled task which cleans up done results after 1 hour to ensure there are not left-overs.
So here's part of the code that the Controller is able to get import results during processing:
@Service
public class ImportRequests {
private final Map<User, ImportResult> importRequests = new ConcurrentHashMap<>();
/** Add, remove, get methods for current user omitted */
}
public class ImportResult {
/** The done. */
private Future<Boolean> done;
/** The error messages. */
private List<String> messages = Collections.synchronizedList(new ArrayList<String>());;
}
@Service
public class ImportService {
@Autowired
private ImportRequests importRequests;
@Autowired
private Importer importer;
public ImportResult doImport(final ImportForm importForm) {
ImportResult result = new ImportResult();
importRequests.addImportResultForCurrentUser(result);
/* This is the actual Async call (process) */
result.setDone(importer.process(result));
return result;
}
}
@Service
public class ImporterImpl implements Importer {
/**
* doProcess will import the *big* file and update the result object with the necessary messages
*/
@Async
public Future<Boolean> process(ImportResult result) {
Boolean done = doProcess(result);
return new AsyncResult<Boolean>(done);
}
}
Hope this helps.
Original Text:
One possibility that I have used is the "@ControllerAdvice" on a class scanned by the servletcontext.
You simply create a method with the exception as a parameter and annotate that method with "@ExceptionHandler". You can even have multiple handlers for specific exception types.
The result of these methods are again handled by the DispatcherServlet, so you can render a view the same way as with request mappings.
Upvotes: 1