springspring-boot

How to intercept/handle BeanCreationExceptions in Spring during app startup (auto-wiring)?


I work on a company-wide framework (reusable libraries) for all Spring Boot applications in a large enterprise. We support hundreds of Boot microservices based on the framework. This context limits certain solutions available to me (more below).

What are my options to intercept BeanCreationExceptions that happen during auto-wiring of a Spring Boot app startup?


Context (probably too much for most readers to care):

During autowiring BeanCreationException can occur due to typical, but foreseeable, mistakes or choices made by developers. One of those is the use of @Resource to auto-wire fields. This is a somewhat common practice in our company but has subtle "gotchas," especially its behavior compared to using @Autowire*.

One of my team's purposes is improving Developer Experience - including helping prevent, or at least highlight, common mistakes. To that end, when a BeanCreationException is thrown due to something that can be explained in our context, we'd like to offer a more specific error message than the default. For example, with @Resource you can (easily?) get BeanNotOfRequiredTypeException due to the name-first matching that Spring does. I want to intercept that and throw with a more specific message or at least log out our custom message in addition to the exception.

Due to my situation not in a specific application/service, no solution that involves changing the usage of @Resource or modifying the main Application class, is feasible. I need to provide a plug-and-play solution to the hundreds of apps/services we support. Ideally something I can inject from the library or that requires a minimal (ie, config-only) update to every service.


*@Autowire matches first based on the type of the declared field, whereas @Resource matches first based on bean name.


Solution

  • Thanks to the comment by @m-deinum I was able to accomplish what I needed by writing a FailureAnalyzer and registering it. There are several good tutorials about doing so, but here's the gist of what I did.

    1. Wrote a class that extends AbstractFailureAnalyzer<T> , where T is the type of exception I wanted to handle. In the situation of the original question, that was BeanNotOfRequiredTypeException.

      a. In my case, the exception type BeanNotOfRequiredTypeException contains plenty of details about the problem so I was easily able to filter down to the exact scenario(s) I was interested in. Specifically, BeanNotOfRequiredTypeException.getRequiredType() and BeanNotOfRequiredTypeException.getActualType().

    2. Registered my custom analyzer in the META-INF/spring.factories file, like this:
      org.springframework.boot.diagnostics.FailureAnalyzer=my.fully.qualified.package.ClassTypeMismatchAnalyzer