34

FactoryBean可用于以编程方式创建可能需要复杂实例化逻辑的对象

但是,似乎由 bean创建的beanFactoryBean并没有成为 spring 管理的。这种解释正确吗?如果是这样,有什么好的解决方法吗?包含一个简短的代码示例来说明我的问题。

应用上下文:

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

5 回答 5

33

这是一个为您自动装配的抽象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()anddoCreateInstance()方法,你就可以使用自动装配运行了。

注意:没有应用 BeanPostProcessors,这需要额外的代码。

于 2011-02-11T15:54:15.760 回答
23

由 Spring创建的对象FactoryBean Spring 管理,但不是由 Spring 实例化或配置的。通过使用 a FactoryBean,您自己对此负责。所有注入和配置必须由FactoryBean

有一个替代方案可能更适合您 - 使用基于注释的配置而不是基于 XML 的配置。这意味着您可以在 Java 中拥有复杂的实例化逻辑,同时仍然使用@Autowired对象本身之类的东西。

我现在倾向于为所有非平凡的 Spring 应用程序使用注释样式的配置,它使许多事情变得容易得多。

于 2011-02-11T15:30:18.740 回答
18

What about this ?

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


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

... and then just inject the bean 'service' and do not care about the factory in your code

于 2011-02-11T16:18:28.827 回答
4

手动方式是:

  1. 在工厂 bean 中注入依赖项
  2. 在目标对象上手动设置它们。

您还可以注入ApplicationContext工厂 bean(或通过实现来获取它ApplicationContextAware),然后执行ctx.getAutowireCapableBeanFactory().autowireBean(bean)

不过,我承认两者都感觉很奇怪。

但实际上,如果逻辑这么简单(仅实例化),请使用prototype范围。

于 2011-02-11T14:50:58.463 回答
0

FactoryBean 是您作为开发人员在编写工厂类时实现的接口,并且您希望工厂类创建的对象由 Spring 作为 bean 进行管理,而另一方面 BeanFactory 代表 Spring IoC 容器,它包含托管 bean 并提供检索它们的访问权限。它是实现控制反转容器的基本功能的框架核心的一部分。

在大多数情况下,您不会发现自己直接使用或实现 BeanFactory 接口,除非您正在扩展框架的核心功能。当您拥有由工厂创建的需要由 Spring 管理的对象时,您确实会实现 FactoryBean。

更简洁地说,BeanFactory 代表 Spring 容器,而 FactoryBean 代表工厂类,其创建的对象被拾取并注册为容器中的 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";
  }
}
于 2016-04-19T18:15:33.600 回答