类和接口的代理之间的区别

问题描述 投票:0回答:2

我正在尝试按类和另一个对象的接口加载代理。

为了确保创建代理,我用 @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;
    }
}

正在打印:

  • 对于 c1:
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'
  • 对于c2
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
  • 对于c3
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 spring-boot spring-aop
2个回答
1
投票

如果可能的话,Spring 默认创建 java 代理。代理仅适用于接口,因此对于类,它必须回退到 CGLIB。

您可以使用

@Scope
注释 C2,将其
proxyMode
设置为
TARGET_CLASS
。这将强制此类使用 CGLIB。

您还可以通过使用此配置注释来全局使用此设置

@EnableAspectJAutoProxy(proxyTargetClass=true)
您将需要导入额外的依赖项


0
投票

还值得添加到此线程中的是,应用程序上下文上的代理行为略有不同,具体取决于它是基于接口的代理还是基于类的(CGLIB)代理。需要注意的事情。

这在 SpringDeveloper 会议演讲中以 Spring security 为例得到了很好的证明: https://www.youtube.com/watch?v=9eoi1TViceM&ab_channel=SpringDeveloper

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.