为什么@Validated + @Component + implement 在 spring 启动时导致类型误导性错误?
Why @Validated + @Component + implement leads type misleading error in 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,这里没问题。这里的重要说明是 MyImpl
bean 是代理 而这是 否
自动装配问题。
但是当我像这样添加 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 可以 通过 class 名称自动装配代理 为什么在添加 implements
时不能这样做,尤其是当此接口未在自动装配字段中使用时.
已更新
Spring-引导版本为2.0.3
spring-核心版本是5.0.7.RELEASE
With interfaces JDK dynamic proxies (interface based) are use, else
you are using class based proxies. Newer Spring Boot versions force
always to use class based proxies. Either way it uses proxies but with
interfaces it uses interface only proxies and else uses class based
(CGLIB) proxies.
来自 M. Deinum .
这是真的,添加接口导致 jdk 代理不是原始 class 的子 class。
强制 subclass 代理 subclass 将以下内容添加到 bean 声明中:
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
例如:
@Validated
@Component
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class MyImpl2 implements MyInterface{}
这里是代码示例列表:
基础
@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,这里没问题。这里的重要说明是 MyImpl
bean 是代理 而这是 否
自动装配问题。
但是当我像这样添加 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 可以 通过 class 名称自动装配代理 为什么在添加 implements
时不能这样做,尤其是当此接口未在自动装配字段中使用时.
已更新
Spring-引导版本为2.0.3
spring-核心版本是5.0.7.RELEASE
With interfaces JDK dynamic proxies (interface based) are use, else you are using class based proxies. Newer Spring Boot versions force always to use class based proxies. Either way it uses proxies but with interfaces it uses interface only proxies and else uses class based (CGLIB) proxies.
来自 M. Deinum
这是真的,添加接口导致 jdk 代理不是原始 class 的子 class。
强制 subclass 代理 subclass 将以下内容添加到 bean 声明中:
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
例如:
@Validated
@Component
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class MyImpl2 implements MyInterface{}