如何让FactoryBean创建的bean被spring管理?

发布于 2024-10-17 06:30:11 字数 1088 浏览 7 评论 0原文

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

然而,由 FactoryBean 创建的 Bean 似乎并未由 Spring 管理。这个解释正确吗?如果是这样,有什么好的解决方法吗?包含一个简短的代码示例来说明我的问题。

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

The FactoryBean can be used to programmatically create objects which might require complex instantiation logic.

However, it seems that the beans created by the FactoryBean doesn't become spring managed. Is this interpretation correct? If so, are there any nice workarounds? A short code sample is included to illustrate my problem.

ApplicationContext:

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

Factory implementation:

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

Class created by the factory:

public class Searcher() {
      private Service service;

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心病无药医 2024-10-24 06:30:11

这是一个抽象的 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() 方法,然后您就可以了通过自动装配启动并运行。

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

Here is an abstract FactoryBean implementation that does autowiring for you:

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();

}

Extend it, implement the getObjectType() and doCreateInstance() methods and you're up and running with autowiring.

Note: BeanPostProcessors are not applied, that would require additional code.

逆光飞翔i 2024-10-24 06:30:11

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

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

我现在倾向于对所有重要的 Spring 应用程序使用注释式配置,它使许多事情变得更加容易。

The object created by the FactoryBean are managed by Spring, but not instantiated or configured by Spring. By using a FactoryBean, you take responsibility for that yourself. All injection and config must be handled by the FactoryBean

There is an alternative which may work better for you - use annotation-based config instead of XML-based config. This means you can have complex instantiation logic in Java, whilst still using things like @Autowired on the objects themselves.

I tend to use annotation-style config for all non-trivial Spring apps now, it makes many things a lot easier.

嗳卜坏 2024-10-24 06:30:11

这又如何呢?

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


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

...然后只需注入 bean 'service' 并且不关心代码中的工厂

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

可是我不能没有你 2024-10-24 06:30:11

手动方法是:

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

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

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

但事实上,如果逻辑那么简单(仅实例化),请使用原型范围。

A manual way would be:

  1. Inject the dependencies in the factory bean
  2. set them manually on the target object.

You can also inject ApplicationContext in the factory bean (or get it by implementing ApplicationContextAware), and do ctx.getAutowireCapableBeanFactory().autowireBean(bean)

I admit both feel strange, though.

But in fact, if the logic is that simple (only instantiation), use prototype scope.

孤者何惧 2024-10-24 06:30:11

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

A FactoryBean is an interface that you, as a developer, implements when writing factory classes and you want the object created by the factory class to be managed as a bean by Spring, while a BeanFactory on the other hand, represents the Spring IoC container, it contains the managed beans and provides access to retrieving them. It is part of the core of the framework which implements the base functionality of an inversion of control container.

In most cases you won't find yourself using or implementing the BeanFactory interface directly, unless you are extending the core functionality of the framework. While you would do implement the FactoryBean when you have objects that are created by Factories that needs to be managed by Spring.

In more succinct words, the BeanFactory represents the Spring container while the FactoryBean represents factory classes whose created object are picked up and registered as a bean in the container.

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";
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文