Reputation: 33
I'm trying to load the proxy by class and by interface for another object.
To ensure that a proxy is created, I have wrapped it with @Cacheable and @CacheEvict annotations on it.
For having a reference C1 which is for a class, works.
But when having a reference for C2 which is for a class that implements another interface I2 it does not work.
If I replace the reference of C2 to I2 then it works again.
Could somebody please point me what is happening?
What else I need to read in order to understand?
Why is it thrown an exception for the c2 case?
Here is the code:
@Component
class HolderC {
@Autowired
private C1 c1;
@Autowired
private C2 c2;
@Autowired
private I2 i3;
@PostConstruct
public void postConstruct() {
System.out.println(c1.getClass());
System.out.println(c2.getClass());
System.out.println(i3.getClass());
}
}
@Component
@Caching
class C1 {
@CacheEvict
public void m1() {
}
}
interface I2 {
void m2();
}
@Component
@Caching
class C2 implements I2 {
@CacheEvict
@Override
public void m2() {
}
}
Along with :
@ComponentScan
@EnableCaching
public class ApplicationConfig {
@Bean
public Caffeine caffeineConfig() {
return Caffeine.newBuilder().expireAfterWrite(60, TimeUnit.MINUTES);
}
@Bean
public CacheManager cacheManager(Caffeine caffeine) {
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCaffeine(caffeine);
return caffeineCacheManager;
}
}
And it is printing :
21:25:24.244 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c1'
21:25:24.290 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c2'
21:25:24.297 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'holderC'
class java.config.context.C1$$EnhancerBySpringCGLIB$$a871b65d
21:25:24.302 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'caffeineConfig'
21:25:24.320 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'cacheManager'
21:26:53.706 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c1'
21:26:53.755 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c2'
21:26:53.764 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'holderC'
21:26:53.769 [main] WARN org.springframework.context.annotation.AnnotationConfigApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'holderC': Unsatisfied dependency expressed through field 'c2'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'c2' is expected to be of type 'java.config.context.C2' but was actually of type 'java.config.context.$Proxy22'
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'holderC': Unsatisfied dependency expressed through field 'c2'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'c2' is expected to be of type 'java.config.context.C2' but was actually of type 'java.config.context.$Proxy22'
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
at java.config.context.Runner.main(Runner.java:9)
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'c2' is expected to be of type 'java.config.context.C2' but was actually of type 'java.config.context.$Proxy22'
at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1672)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1650)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1213)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
... 14 more
21:28:26.331 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c1'
21:28:26.386 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'c2'
21:28:26.397 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'holderC'
class java.config.context.$Proxy22
21:28:26.405 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'caffeineConfig'
21:28:26.431 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'cacheManager'
Upvotes: 1
Views: 738
Reputation: 1
Also worth adding to this thread, the bahaviour of proxy on the application context is slightly different depending whether it's an interface based proxy or class based (CGLIB) proxy. Something to be aware of.
This is nicely demonstrated on this SpringDeveloper conference talk taking Spring security as an example: https://www.youtube.com/watch?v=9eoi1TViceM&ab_channel=SpringDeveloper
Upvotes: 0
Reputation: 1026
Spring creates java proxy by default if its possible. Proxy works only on interface, so for class it has to fallback to CGLIB.
You can annotate C2
with @Scope setting its proxyMode
to TARGET_CLASS
. This will force this class to use CGLIB.
You can also use this setting globally by using this configuration annotation @EnableAspectJAutoProxy(proxyTargetClass=true)
you will need to import additional dependency though
Upvotes: 1