Closed spring-projects-issues closed 6 years ago
John Blum commented
Also, as I pointed out in my post on StackOverflow, another way to create programmatic caching proxies, is to declare Spring's ProxyFactory
and CacheInterceptor
as @Bean
definitions in the Spring @Configuration
class, like so...
@Configuration
class ApplicationConfiguration {
@Bean
CacheInterceptor cacheInterceptor(CacheManager cacheManager) {
CacheInterceptor cacheInterceptor = new CacheInterceptor();
cacheInterceptor.setCacheManager(cacheManager);
cacheInterceptor.setCacheOperationSources(...);
return cacheInterceptor;
}
@Bean
Object thirdPartyObject(ConfigurableListableBeanFactory beanFactory,
CacheInterceptor cacheInterceptor) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(cacheInterceptor));
proxyFactory.setInterfaces(ThirdParty.class);
proxyFactory.setTarget(new ThirdParty());
return proxyFactory.getProxy(beanFactory.getBeanClassLoader());
}
}
This is covered in Spring Framework's Reference Documentation, "6.7 - Creating AOP proxies programmatically with the ProxyFactory". Conveniently, a user could use the o.s.aop.framework.ProxyFactoryBean
instead of ProxyFactory
, directly.
Still, using the o.s.cache.interceptor.CacheProxyFactoryBean
is far more convenient and consistent with Spring's policy on complex instantiation and initialization logic nicely encapsulated with a FactoryBean
.
One example of alternative methods for programmatically creating caching proxies, for possibly 3rd party library/framework classes, can be found here.
Juergen Hoeller commented
CacheProxyFactoryBean
is quite a stepchild here: This class essentially never worked (in particular not since #16941), and nobody seems to have noticed and complained... Since I still consider it a rather secondary configuration variant, I went with the simplest possible revision that does the job: For 4.3.14, simply delegating BeanFactoryAware
and SmartInitializatingSingleton
; for 5.0.3, also adding the three additional setters from CacheInterceptor
for common configuration instead of individual operation settings.
For simplicity's sake, we're just doing integration testing (since that's all that really matters here) and without any custom configuration adaptation in CacheProxyFactoryBean
itself, both of which significantly streamline the implementation and make it straightforward to backport. This also keeps things very aligned with TransactionProxyFactoryBean
, the original inspiration behind our class here. For those reasons, I went with a custom variant instead of your PR, John. Thanks for pointing this out and for the tests, in any case!
John Blum opened SPR-16295 and commented
When a user attempts to create caching proxies using the
o.s.cache.interceptor.CacheProxyFactoryBean
, this fails to work.A user might want to use the
CacheProxyFactoryBean
to introduce caching behavior and logic to classes from a 3rd party library. This recently came up in a StackOverflow post. Please read the post and the answers (especially this one) for further details.Ideally, a user would be able to add caching behavior to any class, programmatically (not declaratively) using...
Unfortunately, this does not work because the internal
CacheInterceptor's
afterSingletonesInitialized()
method never gets called, thereby setting theinitialized
bit and therefore allowing the caching behavior/logic to be evaluated. As result, the target object's original operation is always invoked, forgoing any caching behavior, making any caching proxy configuration useless.This can be fixed by having
CacheProxyFactoryBean
implement theSmartInitializingSingleton
interface along withBeanFactoryAware
and delegating said operations to the internalCacheInterceptor
.See Pull Request for fix.
Affects: 4.3.13, 5.0.2
Reference URL: https://stackoverflow.com/questions/47665485/how-can-i-manually-add-a-spring-cacheinterceptor-using-java-config
Issue Links:
16941
@EnableCaching
provokes early initialization of any config class declaring a CacheManagerReferenced from: pull request https://github.com/spring-projects/spring-framework/pull/1624, and commits https://github.com/spring-projects/spring-framework/commit/b160f93495f762b1f59519b66c3e07fe6bf387fd, https://github.com/spring-projects/spring-framework/commit/d53ede9bd3325269411efc67ab248389e02c85aa
Backported to: 4.3.14