ApplicationContext.getBean (Class clazz) не подходит для прокси - PullRequest
8 голосов
/ 26 августа 2010

У меня есть определение 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);

Опять же, это хорошо работает дляобычные бины, тогда как для прокси-бинов я получаю my.BeanTarget вместо my.Bean.Я попытался встроить my.BeanTarget (как показано в документации по Spring), чтобы сделать его скрытым, но все, что я получил, было

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [my.Interface] is defined: expected single bean but found 0: 

Так что можно ли использовать поиск типа bean-компонентов с прокси-компонентами, и если да- как?

Ответы [ 4 ]

6 голосов
/ 26 августа 2010

Проблема в том, что scope="prototype" на вашем ProxyFactoryBean.

Контекст будет только инициализировать определения одноэлементного компонента.Бины не-одиночной области видимости инициализируются только по запросу.Это означает, что когда вы запрашиваете контекст для bean-компонентов заданного типа, контекст не может инициализировать эти не-одиночные bean-компоненты для запроса их типа, он должен опираться исключительно на информацию в определении bean-компонента.1006 * В случае ProxyFactoryBean тип сгенерированного прокси определяется сложной логикой, которая требует полной инициализации компонента.Без этой инициализации ProxyFactoryBean может сообщить о целевом типе только как null.

Я не могу обойти это иначе, кроме использования определения одиночного бина или явного запроса бина по имениНапример,

<bean id="my.Interface"> class="ProxyFactoryBean"... >

, а затем:

ctx.getBean(MyInterface.class.getName());

Здесь мы используем соглашение об именах компонентов, являющихся интерфейсом, который они реализуют.

2 голосов
/ 26 августа 2010

Похоже, что область прокси, созданных 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); 
1 голос
/ 26 августа 2010

Разве ты не можешь сделать my.Interface foo = ctx.getBean(my.Bean.class);?

0 голосов
/ 02 мая 2017

Поскольку Spring работает с интерфейсами, в контексте aop вы можете определить другой набор интерфейсов и запросить тот, который вы ожидаете.Таким образом, для реального класса не понадобится приведение, но Spring будет управлять интерфейсами.

Допустим, у вас есть орудия класса A B. Вы хотите привести A к B, но вам отказано, поскольку A является прокси из-за aop.Затем make A реализует C, а C расширяет B. C владеет необходимыми методами, а C является частным интерфейсом, доступным только из кода вашей реализации.Наконец, попросите Spring ввести B или C. В зависимости от ваших ожиданий.

PrivateItf executor = context.getBean(PrivateItf.class);

Таким образом, даже если реальный класс является прокси, он реализует ваш Частный Интерфейс со всем, что вам нужно.

...