10

方法 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 定义中指定构造函数参数,它会失败。

4

4 回答 4

17

javadoc说:

args - 使用静态工厂方法的显式参数创建原型时使用的参数。

所以bean定义必须是原型范围的bean,即

<bean id="fileValidator" 
      scope="prototype" 
      class="cz.instance.transl.validation.file.FileValidator" 
      factory-method="createInstance" />
于 2011-07-22T06:37:12.360 回答
10

阅读 20 篇文章,我发现如何让自定义工厂方法在运行时获取参数并不明显,特别是因为我们被迫使用构造函数参数标签并将上下文中的现有 bean 引用为 setup下面和有问题的类充当静态工厂方法。

<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 都是单例的,此时没有调用构造函数。如果您在单用户系统中工作,这不是问题,也不需要关心任何事情,因为无论如何您的上下文中始终只有 1 个用户 bean!

但是,对于多用户系统,您需要确保每个真实用户都有一个唯一的用户 bean,并且在工厂方法调用中使用正确的用户 bean。

为了在多用户系统中执行此操作,您需要将 bean 类型更改为原型,并且您应该创建一个代表工厂的 FileValidator bean(如果您打算将依赖项注入工厂)和另一个 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>

在你想从工厂获取这个新的 FileValidator bean 的类中,你可以使用下面的技术:

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

    FileValidator fileValidator = 
               (FileValidator)context.getBean("fileValidatorBean",
                                              user);
    ...
}
于 2012-11-06T01:22:35.760 回答
8

为了调用您的工厂方法,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>
于 2011-07-22T06:24:21.497 回答
6

您也可以使用抽象工厂来设置 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. 创建方法不是静态的。现在属于一个实例
  2. constructor-arg 是工厂方法的参数
于 2012-01-19T13:38:39.537 回答