Подтвердить что ты не робот

Как получить beans, созданный FactoryBean spring?

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

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

ApplicationContext:

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

Factory реализация:

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;
    }
    .... 
}

Класс, созданный factory:

public class Searcher() {
      private Service service;

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

Ответ 1

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

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

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

Ответ 2

Вот абстрактная реализация 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(), и вы запускаете его с помощью autowiring.

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

Ответ 3

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

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


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

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

Ответ 4

Ручным способом будет:

  • Ввести зависимости в factory bean
  • установите их вручную на целевой объект.

Вы также можете ввести ApplicationContext в factory bean (или получить его, выполнив ApplicationContextAware) и сделать ctx.getAutowireCapableBeanFactory().autowireBean(bean)

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

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

Ответ 5

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

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

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

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";
  }
}

Ответ 6

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