I'm on spring framework version 5.3.23, spring boot version 2.7.0
I know I can extend CachingConfigurerSupport
to provide a CacheErrorHandler
for handling cache layer errors. However, the interface of the bean creation is:
interface CachingConfigurer {
public CacheErrorHandler errorHandler();
}
My problem is: we need to inject some other beans into this CacheErrorHandler
bean. The interface does not allow me to do that. Is there another way to configure a CacheErrorHandler
bean with injection? If I simply declare a regular CacheErrorHandler
bean, would it be automatically discovered by the cache configuration?
Thanks.
CodePudding user response:
No, only get CacheErrorHandler from the CachingConfigurer bean
CodePudding user response:
Well, technically, the previous answer is wrong!
In fact, you can inject other bean dependencies/collaborators into Spring Cache infrastructure components, such as a CacheErrorHandler
(Javadoc) when implementing the CachingConfigurer
interface (Javadoc), although maybe not in a way you might expect.
I have demonstrated your use case in this test class.
In summary:
My test configuration implements the
CachingConfigurer
.I override the
errorHandler()
method to return a "custom"CacheErrorHandler
. Also see theTestCacheErrorHandler
(custom) implementation, here.As you can see, the
TestCacheErrorHandler
requires aLogger
.The
Logger
is declared and configured as a bean in the Spring container (ApplicationContext
).
NOTE: Now, you could imagine the
Logger
being replaced by a sophisticated management/monitoring service usingMicrometer
, or perhaps a backend database. This was a test and I wanted to minimize the dependencies and complexity to focus on the problem at hand.
- In good Spring fashion, I used constructor-injection, as is recommended.
TIP: The key to this injection (autowiring), is that the bean method for the "mockLogger" bean is "proxied" by Spring (using CGLIB (class-based) proxy (as opposed to interface based proxying JDK Dynamic Proxies)). This allows the actual
mockLogger
bean to be inject and not some arbitrary object. This implicit in the@SpringBootConfiguration
annotation declaration, where theproxyBeanMethods
is by default, set totrue
. If I change this configuration toproxyBeanMethods
set tofalse
, the test will fail, since theCacheErrorHandler
will get a reference to an unmanagedLogger
. See the Javadoc for@SpringBootConfiguration
for more details.
- The test case method goes on to assert and verify that the proper interactions happen based on the bean invocations.
NOTE: I used mock Spring Cache infrastructure components to precisely control the
Cache
behavior, such as simulating an error that would necessarily involve customCacheErrorHandler
in my test. The mock infrastructure will also allow you to test other caching infrastructure components (such as a customCacheResolver
) or caching behaviors in a similar manner.
Ultimately, the test proves and demonstrates that you can inject other dependencies into caching infrastructure components, using preferably constructor injection (which is truly the only Thread-safe way to wire collaborators, especially in a multi-Threaded environment, such as a Web application, providing the this
reference does not escape during construction of course ;-) ).
As 1 final test, I also tested and demonstrated that it is also possible to declare the "custom" CacheErrorHandler
as a Spring "bean" managed by the Spring container and inject (autowire) additional dependencies (and here) using (field-based) setter injection (not recommended, but also possible).
The 2 key things in this test case is this and this.
If you have additional questions, please post in the comments, but I think the test class is pretty self-explanatory.
Cheers!