我正在尝试按类和另一个对象的接口加载代理。
为了确保创建代理,我用 @Cacheable 和 @CacheEvict 注释对其进行了包装。
对于一个班级来说,有一个参考 C1 是可行的。
但是当 C2 的引用用于实现另一个接口 I2 的类时,它不起作用。
如果我将 C2 的参考替换为 I2,那么它会再次工作。
有人可以指出我发生了什么事吗?
我还需要阅读什么才能理解?
为什么c2情况会抛出异常?
这是代码:
@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() {
}
}
连同:
@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;
}
}
正在打印:
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'
如果可能的话,Spring 默认创建 java 代理。代理仅适用于接口,因此对于类,它必须回退到 CGLIB。
您可以使用
@Scope注释
C2
,将其 proxyMode
设置为 TARGET_CLASS
。这将强制此类使用 CGLIB。
您还可以通过使用此配置注释来全局使用此设置
@EnableAspectJAutoProxy(proxyTargetClass=true)
您将需要导入额外的依赖项
还值得添加到此线程中的是,应用程序上下文上的代理行为略有不同,具体取决于它是基于接口的代理还是基于类的(CGLIB)代理。需要注意的事情。
这在 SpringDeveloper 会议演讲中以 Spring security 为例得到了很好的证明: https://www.youtube.com/watch?v=9eoi1TViceM&ab_channel=SpringDeveloper