gpt4 book ai didi

java - Spring @Bean 配置和 Java 多态性

转载 作者:行者123 更新时间:2023-11-30 09:53:03 26 4
gpt4 key购买 nike

我越来越频繁地使用新的 @Bean Spring 3 中的配置样式,作为 XML bean 定义文件的更类型安全的替代方案。但有时,由于 Java 缺乏类型表达能力和 Spring 作用域代理的结合,这种类型安全会阻止您做应该是有效的事情。

演示问题的完整单元测试如下,但简要说明我有一个类 ServiceBean , 它实现接口(interface) ServiceAServiceB .这个 bean 是一个作用域代理(在本例中是 session 作用域)。我也有 bean ClientAClientB , 注入(inject)类型为 ServiceA 的对象和 ServiceB分别。

在Spring XML配置中,这个是没有问题的。 Spring 为 ServiceBean 生成一个 JDK 代理,它实现了这两个接口(interface),并且都被注入(inject)到客户端 bean 中。这都是反射性的,并且类型在运行时没问题。

@Bean 中试试这个-style,但是,你有问题。这是演示测试。

首先是服务:

public interface ServiceA {}

public interface ServiceB {}

public class ServiceBean implements ServiceA, ServiceB {}

现在,客户:

public class ClientA {
public ClientA(ServiceA service) {}
}

public class ClientB {
public ClientB(ServiceB service) {}
}

现在,Spring bean 定义:

@Configuration
public class ScopedProxyConfig {

@Bean @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public ServiceBean services() {
return new ServiceBean();
}

@Bean
public ClientA clientA() {
return new ClientA(services());
}

@Bean
public ClientB clientB() {
return new ClientB(services());
}
}

最后,单元测试和支持上下文:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ScopedProxyTest {

private @Resource ClientA clientA;
private @Resource ClientB clientB;

public @Test void test() {
assertThat(clientA, is(notNullValue()));
assertThat(clientB, is(notNullValue()));
}
}

<beans>            
<context:annotation-config/>
<bean class="test.ScopedProxyConfig"/>
</beans>

(为清楚起见省略了 XML namespace )。

这一切都很好地编译。但是,运行测试,你会得到一个类型转换运行时异常:

Caused by: java.lang.ClassCastException: $Proxy11 cannot be cast to test.ServiceBean at test.ScopedProxyConfig$$EnhancerByCGLIB$$d293ecc3.services() at test.ScopedProxyConfig.clientA(ScopedProxyConfig.java:26)

我不清楚这究竟告诉我什么,但它似乎是 JDK 代理(实现 ServiceAServiceB )和 ServiceBean 之间的冲突。对象。

我尝试过使用泛型变得聪明:

@Bean @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public <T extends ServiceA & ServiceB> T services() {
return (T)new ServiceBean();
}

但这甚至无法编译。

我认为这不是一个特别奇特的情况,我以前也遇到过几次。过去,解决方法是使用 TARGET_CLASS代理而不是接口(interface)代理,但这不是我的选择。

任何人都可以弄清楚如何让它工作吗?

最佳答案

我认为您必须寻求更基于界面的解决方案:

创建接口(interface)ServiceC:

public interface ServiceC extends ServiceA, ServiceB {}

然后让ServiceBean实现那个接口(interface)

public class ServiceBean implements ServiceC{}

在你的 ScopedProxyConfig 中:

@Bean @Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ServiceC services() {
return new ServiceBean();
}

接口(interface)的一致使用应该让 Spring 与 JDK 代理一起工作。

关于java - Spring @Bean 配置和 Java 多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4033470/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com