У меня есть определение bean-компонента в Spring и его прокси-аналог, который должен использоваться везде:
<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype">
<property name="proxyInterfaces" value="my.Interface"/>
<property name="target" ref="my.BeanTarget"/>
<property name="interceptorNames">
<list>
<value>someInterceptor</value>
</list>
</property>
</bean>
<bean name="my.BeanTarget" class="my.InterfaceImpl" scope="prototype">
<property name="foo" ref="bar"/>
</bean>
Это все работает хорошо; и в pre-Spring v3 мире я использовал его как
ApplicationContext ctx = ...;
my.Interface foo = (my.Interface) ctx.getBean("my.Bean"); // cast is necessary
. В Spring 3 стало возможным делать безопасные поиски типов, например:
my.Interface foo = ctx.getBean(my.Interface.class);
Опять же, это хорошо работает для обычных bean-компонентов, тогда как для проксируемых bean-компонентов я получаю my.BeanTarget
вместо my.Bean
. Я попытался встроить мой. BeanTarget
(как показано в документации Spring), чтобы сделать его скрытым, но все, что я получил, было
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [my.Interface] is defined: expected single bean but found 0:
. Так возможно ли использовать поиск безопасных типов bean-компонентов с проксированными bean-компонентами, и если да - как?
Проблема заключается в scope="prototype"
в вашем ProxyFactoryBean
.
Контекст будет с готовностью инициализировать только одноэлементные определения bean-компонентов. Bean-компоненты неодноэлементной области инициализируются только по запросу. Это означает, что когда вы запрашиваете у контекста bean-компоненты данного типа, контекст не может инициализировать эти неодноэлементные bean-компоненты, чтобы запросить их тип, он должен исходить исключительно из информации в определении bean-компонента.
В случае ProxyFactoryBean
тип сгенерированного прокси определяется сложной логикой, требующей полной инициализации компонента. Без этой инициализации ProxyFactoryBean
может сообщать о целевом типе только как null
.
Я не могу сказать, как обойти это, кроме как использовать определение одноэлементного компонента или явно запрашивать компонент по имени, например.
<bean id="my.Interface"> class="ProxyFactoryBean"... >
а затем:
ctx.getBean(MyInterface.class.getName());
Здесь мы используем соглашение о том, что имена компонентов являются интерфейсом, который они реализуют.
Похоже, область прокси, созданных ProxyFactoryBean
, должна быть указана с использованием свойства singleton
вместо атрибута scope
:
<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="singleton" value="false"/>
...
</bean>
Это решило проблему, когда целевой компонент является внутренним.
Если у вас есть несколько bean-компонентов верхнего уровня одного класса, вы можете использовать безопасный поиск по идентификатору:
my.Interface foo = ctx.getBean("my.Bean", my.Interface.class);