Как получить бобы созданные FactoryBean весной удалось? - PullRequest
31 голосов
/ 11 февраля 2011

FactoryBean может использоваться для программного создания объектов, для которых может потребоваться сложная логика создания экземпляров.

Однако, похоже, что компоненты , созданные FactoryBean, не становятся управляемыми пружинами.Правильно ли это толкование?Если так, есть ли хорошие обходные пути?Краткий пример кода включен, чтобы проиллюстрировать мою проблему.

ApplicationContext:

<bean id="searcher" class="some.package.SearcherFactory" /> 
<bean id="service" class="some.package.Service" /> 

Реализация фабрики:

public class SearcherFactory implements FactoryBean<Searcher> {

    @Override
    public Searcher getObject() throws Exception {
        return new Searcher(); // not so complex after all ;)
    }

    @Override
    public Class<Searcher> getObjectType() {
        return Searcher.class;
    }
    .... 
}

Класс, созданный фабрикой:

public class Searcher() {
      private Service service;

      @Autowired
      public void setService(Service service) {
           // never invoked
           this.service=service;
      } 
}

Ответы [ 6 ]

29 голосов
/ 11 февраля 2011

Вот абстрактная реализация FactoryBean, которая выполняет автоматическую разводку для вас:

public abstract class AbstractAutowiringFactoryBean<T> extends
    AbstractFactoryBean<T> implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(
        final ApplicationContext applicationContext){
        this.applicationContext = applicationContext;
    }

    @Override
    protected final T createInstance() throws Exception{
        final T instance = doCreateInstance();
        if(instance != null){
            applicationContext
              .getAutowireCapableBeanFactory()
              .autowireBean(instance);
        }
        return instance;
    }

    /**
     * Create the bean instance.
     * 
     * @see #createInstance()
     */
    protected abstract T doCreateInstance();

}

Расширьте ее, реализуйте методы getObjectType() и doCreateInstance(), и вы приступите к работе с автопроводкой.1007 *

Примечание: BeanPostProcessors не применяются, для этого потребуется дополнительный код.

20 голосов
/ 11 февраля 2011

Объект, созданный FactoryBean , управляется Spring, но не создается и не конфигурируется Spring. Используя FactoryBean, вы сами берете на себя ответственность за это. Все инъекции и настройки должны быть обработаны FactoryBean

Существует альтернатива, которая может работать лучше для вас - используйте config на основе аннотаций вместо XML-config . Это означает, что вы можете иметь сложную логику создания экземпляров в Java, все еще используя такие вещи, как @Autowired на самих объектах.

Сейчас я склонен использовать конфигурацию в стиле аннотаций для всех нетривиальных приложений Spring, это упрощает многие вещи.

18 голосов
/ 11 февраля 2011

Как насчет этого?

<bean id="serviceFactory"
      class="some.package.SearcherFactory" />


<bean id="service"
      factory-bean="serviceFactory"
      factory-method="getObject"/>

... а затем просто введите 'service' компонента и не заботьтесь о фабрике в вашем коде

4 голосов
/ 11 февраля 2011

Ручной способ будет выглядеть следующим образом:

  1. Вставить зависимости в фабричный компонент
  2. , установить их вручную для целевого объекта.

Вы можететакже введите ApplicationContext в фабричный бин (или получите его путем реализации ApplicationContextAware) и выполните ctx.getAutowireCapableBeanFactory().autowireBean(bean)

Я признаю, что оба чувствуют себя странно.

Но на самом деле, еслилогика так проста (только создание экземпляров), используйте prototype scope.

0 голосов
/ 19 апреля 2016

FactoryBean - это интерфейс, который вы, как разработчик, реализуете при написании фабричных классов, и вы хотите, чтобы объект, созданный фабричным классом, управлялся как bean-компонентом Spring, тогда как BeanFactory представляет Spring.Контейнер IoC, он содержит управляемые компоненты и предоставляет доступ к их получению.Он является частью ядра платформы, которая реализует базовую функциональность инверсии контейнера управления.

В большинстве случаев вы не обнаружите, что используете или реализуете интерфейс BeanFactory напрямую, если только вы не расширяете ядро.функциональность фреймворка.Хотя вы бы реализовали FactoryBean, когда у вас есть объекты, созданные фабриками, которыми нужно управлять Spring.

Другими словами, BeanFactory представляет контейнер Spring, а FactoryBean представляет классы фабрики, чей созданный объектсобраны и зарегистрированы как бобовые в контейнере.

File: context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="sha" class="MessageDigestFactoryBean">
        <property name="algorithm" value="SHA1"/>
    </bean>

    <bean id="md5" class="MessageDigestFactoryBean"/>

</beans>


File: Main.java

import java.security.MessageDigest;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class Main {
  public static void main(String[] args) {
    XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("context.xml"));
    String d1 = (String) factory.getBean("sha");
    String d2 = (String) factory.getBean("md5");
    System.out.println(d1);
    System.out.println(d2);
  }

}

class MessageDigestFactoryBean implements FactoryBean, InitializingBean {
  private static final String DEFAULT_ALGORITHM = "MD5";

  private String algorithm = DEFAULT_ALGORITHM;

  public Object getObject() throws Exception {
    return this.algorithm;
  }

  public Class getObjectType() {
    return MessageDigest.class;
  }

  public boolean isSingleton() {
    return true;
  }

  public void setAlgorithm(String algorithm) {
    this.algorithm = algorithm;
  }

  public void afterPropertiesSet() throws Exception {
    this.algorithm += " after setting";
  }
}
0 голосов
/ 11 февраля 2011

Нет, бобы, созданные FactoryBean, также управляются весной.

...