Я использую новый стиль конфигурации @Bean
в Spring 3, как более безопасную для типов альтернатив файлам XML-компонентов. Иногда, однако, этот тип безопасности может помешать вам делать то, что должно быть правдоподобным, из-за сочетания отсутствия выраженности языка Java и прокси-серверов Spring.Spring @Bean configs и java polymorphism
Полный блок-тест, который демонстрирует проблему, приведен ниже, но вкратце поставил у меня класс ServiceBean
, который реализует интерфейсы ServiceA
и ServiceB
. Этот компонент является областью действия прокси (с учетом сеанса). У меня также есть фасоль ClientA
и ClientB
, которым вводят объекты типа ServiceA
и ServiceB
соответственно.
Весной XML config, нет проблем с этим. Spring генерирует JDK-прокси для ServiceBean
, который реализует оба интерфейса, и оба они вводятся в клиентские компоненты. Это все рефлексивно, и типы хорошо работают во время выполнения.
Попробуйте это в @Bean
-стиле, хотя, и у вас есть проблемы. Вот демонстративный тест.
Во-первых, услуги:
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 фасоли:
@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 опущены для ясности).
Все это прекрасно компилируется. Выполните тест, хотя, и вы получите исключение типа отливка выполнения:
Вызванный: java.lang.ClassCastException: $ Proxy11 не может быть приведен к test.ServiceBean в test.ScopedProxyConfig $$ EnhancerByCGLIB $$ d293ecc3 .Услуги() в test.ScopedProxyConfig.clientA (ScopedProxyConfig.java:26)
это мне не ясно, что именно это говорит мне, но это, кажется, столкновение между прокси JDK (который реализует ServiceA
и ServiceB
) и объект ServiceBean
.
Я пытался получать умный с обобщениями:
@Bean @Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public <T extends ServiceA & ServiceB> T services() {
return (T)new ServiceBean();
}
Но это даже не скомпилируется.
Это не особо экзотическая ситуация, я думаю, и я сталкивался с ней несколько раз.Раньше обходным путем было использование проксирования вместо проксирования интерфейса, но это не вариант для меня здесь.
Может ли кто-нибудь выяснить, как это сделать?
BTW: Я не вижу преимуществ использования стиля конфигурации Java. Если вы используете STS, стиль XML гораздо удобнее в использовании, а конструктор Spring будет анализировать и сообщать больше ошибок, чем компилятор java. –
@seanizer: Я вижу, что вы говорите, это вопрос личных предпочтений. Оба действительны. – skaffman
true. и я знаю, что весна была XML-адом уже много лет, но с IDE, которая * понимает * XML, это на самом деле весело и очень продуктивно. –