web-dev-qa-db-ja.com

FactoryBean Spring管理によって作成されたBeanを取得する方法は?

FactoryBean は、複雑なインスタンス化ロジックを必要とする可能性のあるオブジェクトをプログラムで作成するために使用できます。

ただし、FactoryBeanによって作成されたBeanが作成されたは、スプリング管理されないようです。この解釈は正しいですか?その場合、ニースの回避策はありますか?問題を説明するために、短いコードサンプルが含まれています。

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;
      } 
}
32
Johan Sjöberg

FactoryBeanareによって作成されたオブジェクトは、Springによって管理されますが、Springによってインスタンス化または構成されません。 FactoryBeanを使用することにより、あなたはその責任を自分で負います。すべてのインジェクションと設定は、FactoryBeanによって処理される必要があります

より適切に機能する代替手段があります。 XMLベースの構成の代わりに注釈ベースの構成 を使用します。つまり、Javaで複雑なインスタンス化ロジックを使用しながら、@Autowiredオブジェクト自体。

私は今、すべての非自明なSpringアプリに注釈スタイルの設定を使用する傾向があります。これにより、多くのことがより簡単になります。

20
skaffman

自動配線を行う抽象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は適用されず、追加のコードが必要になります。

29

これはどうですか ?

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


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

...そして、Bean 'サービス'を注入するだけで、コードのファクトリを気にしません

18
Rostislav Matl

手動の方法は次のとおりです。

  1. ファクトリBeanに依存関係を注入します
  2. ターゲットオブジェクトに手動で設定します。

ファクトリBeanにApplicationContextを挿入(またはApplicationContextAwareを実装して取得)して、ctx.getAutowireCapableBeanFactory().autowireBean(bean)を実行することもできます。

しかし、私は両方とも奇妙に感じると認めます。

しかし、実際には、ロジックがそれほど単純(インスタンス化のみ)の場合は、prototypeスコープを使用します。

4
Bozho

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";
  }
}
0
Kumar Abhishek