web-dev-qa-db-ja.com

実行時にパラメータをファクトリメソッドに渡す

メソッドcontext.getBean(name、user)のドキュメントによると

明示的なコンストラクター引数/ファクトリメソッド引数を指定できます

しかし、私が何をしても(すべてを試しました)、最も論理的な設定では、初期化中にBeanがロードされているときにこれを取得します:

org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?
    org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'fileValidator' defined in
PortletContext resource
[/WEB-INF/classes/context/customer-form-portlet.xml]: Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.liferay.portal.model.User]: Ambiguous factory method argument
types - did you specify the correct bean references as factory method
arguments?

<bean id="fileValidator" 
      class="cz.instance.transl.validation.file.FileValidator" 
      factory-method="createInstance" />

private FileValidator(User user) {
    this.user = user;
}

public static FileValidator createInstance(User user) {
    return new FileValidator(user);
}

解説にはそれができると書かれていますが、そのBeanのxml定義でコンストラクター引数を指定するかどうかにかかわらず、失敗します。

9
lisak

javadoc のコメント:

args-静的ファクトリメソッドへの明示的な引数を使用してプロトタイプを作成する場合に使用する引数。

したがって、Beanの定義mustは、プロトタイプスコープのBeanである必要があります。

<bean id="fileValidator" 
      scope="prototype" 
      class="cz.instance.transl.validation.file.FileValidator" 
      factory-method="createInstance" />
16
skaffman

20の投稿を読んで、特にコンストラクター引数タグを使用し、コンテキスト内の既存のBeanをセットアップとして参照する必要があるため、実行時にパラメーターを取得するカスタムファクトリメソッドを取得する方法が明確でないことがわかりました。以下と、静的ファクトリメソッドとして機能する問題のクラス。

<bean id="user" class="something.something.User" />

<bean id="fileValidator" 
      class="cz.instance.transl.validation.file.FileValidator" 
      factory-method="createInstance" >
      <constructor-args ref="user" />
</bean>

コンストラクター引数で使用されるBeanのインスタンスをコンテキストからフェッチし、実行時に使用している値をそのインスタンスに入力することで、機能するようになりました。このBeanは、工場で生成されたBeanを取得するときにパラメーターとして使用されます。

public class X {

   public void callFactoryAndGetNewInstance() {
      User user = context.getBean("user");
      user.setSomethingUsefull(...);
      FileValidator validator = (FileValidator)context.getBean("fileValidator");
      ...
   }
}

このシナリオではそのメソッドは関係ないため、これはcontext.getBean(arg1、arg2)の使用で求められる問題を解決しないことに注意してください。そうでない理由は、これらのBeanがすべてシングルトンであり、この時点ではコンストラクターが呼び出されていないためです。とにかくいつでもコンテキストにユーザーBeanが1つしかないため、シングルユーザーシステムで作業している場合は問題ありません。

ただし、マルチユーザーシステムの場合は、実際のユーザーごとに一意のユーザーBeanがあり、ファクトリメソッド呼び出しで正しいユーザーBeanを使用していることを確認する必要があります。

マルチユーザーシステムでこれを行うには、Beanタイプをプロトタイプに変更する必要があります。また、ファクトリ(ファクトリへの依存性注入を計画している場合)と別のBeanを表すFileValidatorのBeanを作成する必要があります。新しいインスタンスを表すFileValidator。どちらも同じクラスタイプになりますが、それぞれに一意の名前を付ける必要があります。下記参照:

<bean id="user" scope="prototype" class="something.something.User" />

<bean id="validatorFactory"
            class="cz.instance.transl.validation.file.FileValidator">
    <constructor-arg value="something" />
</bean>

<bean id="fileValidatorBean"
            class="cz.instance.transl.validation.file.FileValidator"
    scope="prototype"
    factory-method="createInstance" >
    <constructor-arg ref="user" />
</bean>

この新しいFileValidatorBeanをファクトリから取得したいクラスでは、以下の手法を使用できます。

public void someMethod() {
    ...
    User user = context.getBean("user");
    user.setSomethingUsefull(...);

    FileValidator fileValidator = 
               (FileValidator)context.getBean("fileValidatorBean",
                                              user);
    ...
}
11
gannable

ファクトリメソッドを呼び出すために、SpringはcreateInstanceに渡すユーザーインスタンスにアクセスする必要があります。この場合、私はBeanを作成し、それを渡すだけです。

<bean id="user" class="something.something.User">
</bean>

<bean id="validator" class="cz.instance.transl.validation.file.FileValidator" factory-method="createInstance">
    <constructor-arg ref="user"/>
</bean>
8
alexwen

抽象ファクトリを使用して、factory-bean属性を設定することもできます。ここに、アクションを作成するActionFactoryがあります。

<bean id="actions_factory" class="com.imagina.control.actions.impl.ActionFactoryImpl"/>

<bean id="load_person_action" class="com.imagina.control.actions.impl.LoadPersonAction" 
  factory-bean="actions_factory" factory-method="create">
  <constructor-arg value="load_person_action"/>      
</bean>

この構成を使用するには、次の点を考慮する必要があります。

  1. createメソッドは静的ではありません。現在はインスタンスに属しています
  2. コンストラクター引数はファクトリメソッドのパラメーターです
6
yeraycaballero