首页 > 解决方案 > 为什么@Validated + @Component + 实现在spring boot中导致类型误导错误?

问题描述

这里的代码示例列表:

根据

@Validated
@Component
public class MyImpl1 {}

@Validated
@Component
public class MyImpl2 {}

@Service
public MySelector {
    private final MyImpl1 myImpl1;
    private final MyImpl2 myImpl2;

    @Autowired
    public MySelector(MyImpl1 myImpl1, MyImpl2 myImpl2) {
        this.myImpl1 = myImpl1;
        this.myImpl2 = myImpl2;
    }

    public Object select (Long id) {
        switch (id) {
            case 1:
                return myImpl1;
            case 2:
                return myImpl1;
        }
    }
}

有效:注入bean,这里没问题。这里的重要说明是MyImplbean是代理,这对于自动装配没有问题

但是当我这样添加时,事情变得不同implements了:

工具

@Validated
@Component
public class MyImpl1 implements MyInterface{}

@Validated
@Component
public class MyImpl2 implements MyInterface{}

public interface MyInterface {}

@Service
public MySelector {
    private final MyImpl1 myImpl1;
    private final MyImpl2 myImpl2;

    @Autowired
    public MySelector(MyImpl1 myImpl1, MyImpl2 myImpl2) {
        this.myImpl1 = myImpl1;
        this.myImpl2 = myImpl2;
    }

    public Object select (Long id) {
        switch (id) {
            case 1:
                return myImpl1;
            case 2:
                return myImpl2;
        }
    }
}

我在这里得到:

Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'myImpl1' is expected to be of type 'MyImpl1' but was actually of type 'com.sun.proxy.$Proxy108'

如果我删除@Validated每一个重新开始工作。

我知道spring使用代理,最好使用接口。但我不明白为什么我在这里遇到问题?如果 spring可以通过类名自动装配代理,为什么在添加时它不能这样做,implements特别是当这个接口没有用于自动装配字段时。

更新

spring-boot 版本是2.0.3 spring-core 版本是5.0.7.RELEASE

标签: javaspringspring-bootproxybean-validation

解决方案


使用接口 JDK 动态代理(基于接口),否则您使用基于类的代理。较新的 Spring Boot 版本强制始终使用基于类的代理。无论哪种方式,它都使用代理,但对于接口,它只使用接口代理,否则使用基于类(CGLIB)的代理。

来自M. Deinum 评论

这是真的,添加接口会导致 jdk 代理不是原始类的子类。

要强制子类代理子类,请将以下内容添加到 bean 声明中:

@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )

例如:

@Validated
@Component
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class MyImpl2 implements MyInterface{}

推荐阅读