Spring 并在运行时将参数传递给工厂方法

发布于 2024-11-26 05:56:12 字数 1461 浏览 0 评论 0原文

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

The documentation of method context.getBean(name, user) says

Allows for specifying explicit constructor arguments / factory method
arguments

but no matter what I do (tried everything), with the most logical setting I get this when the beans are being loaded up during initialization:

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

The commentary says you can do it, but if you specify constructor arguments in xml definiton of that bean or not, it fails.

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

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

发布评论

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

评论(4

灰色世界里的红玫瑰 2024-12-03 05:56:12

javadoc 说:

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

因此,bean 定义必须是原型范围的 bean,即

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

The javadoc says:

args - arguments to use if creating a prototype using explicit arguments to a static factory method.

So the bean definition must be a prototype-scoped bean, i.e.

<bean id="fileValidator" 
      scope="prototype" 
      class="cz.instance.transl.validation.file.FileValidator" 
      factory-method="createInstance" />
爱冒险 2024-12-03 05:56:12

阅读了 20 篇文章,我发现如何让自定义工厂方法在运行时获取参数并不明显,特别是因为我们被迫使用 constructor-arg 标签并在上下文中引用现有的 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 个 User bean!

然而,对于多用户系统,您需要确保每个真实用户都有一个唯一的 User bean,并且在工厂方法调用中使用正确的 User 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);
    ...
}

Reading across 20 posts, I found that it was not apparent how to get a custom factory method to take parameters at run-time, especially since we are forced to use the constructor-arg tags and refer to an existing bean in the context as setup below and the class in question acting as a static factory method.

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

I got it working by fetching an instance of the bean used in the constructor-arg out of the context and then populating it with the values that you are working with at run-time. This bean will then be used as the parameter when you get your factory-generated bean.

public class X {

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

Note this doesn't solve the problem asked of using context.getBean(arg1, arg2) as that method isn't relevant in this scenario. The reason it isn't is because all these beans are singleton and at this point the constructor isn't invoked. Not a problem and not anything to care about if you are working in a single-user system as you only have 1 User bean in your context at any time anyhow!

However, For a multi-user system you will need to make sure that you have a unique User bean for each real user and that you use the correct User bean in the factory method invocation.

In order to do this in a multi-user system, you will need to change the bean types to be prototype AND you should create a bean of your FileValidator that represents the factory (if you plan to dependency injection into the factory) and another bean FileValidator that represents your new instance. They will both be of the same class type but you must give each one a unique name. See below:

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

and in the class where you would like to get this new FileValidator bean from the factory, you can use the technique below:

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

    FileValidator fileValidator = 
               (FileValidator)context.getBean("fileValidatorBean",
                                              user);
    ...
}
街道布景 2024-12-03 05:56:12

为了调用工厂方法,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>

In order to call your factory method Spring needs access to a user instance to pass to createInstance. In this case I am just creating a bean and passing it in:

<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>
聊慰 2024-12-03 05:56:12

您也可以使用抽象工厂来设置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. constructor-arg是工厂方法的参数

You can use an abstract factory too setting the factory-bean attribute. Here we have an ActionFactory which create actions.

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

To use this configuration you have to take this points in account:

  1. create method is not static. Now belongs to an instance
  2. constructor-arg is the parameter of factory method
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文