Creating Spring Beans Through Factory Methods – 通过工厂方法创建Spring Bean

最后修改: 2020年 4月 26日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Factory methods can be a useful technique for hiding complex creation logic within a single method call.

工厂方法是一种有用的技术,可以将复杂的创建逻辑隐藏在单个方法调用中。

While we commonly create beans in Spring using constructor or field injection, we can also create Spring beans using factory methods.

虽然我们通常使用constructorfield injection来创建Spring的bean,我们也可以使用工厂方法创建Spring beans

In this tutorial, we will delve into creating Spring beans using both instance and static factory methods.

在本教程中,我们将深入探讨使用实例和静态工厂方法创建Spring Bean。

2. Instance Factory Method

2.实例工厂方法

A standard implementation of the factory method pattern is to create an instance method that returns the desired bean.

工厂方法模式的一个标准实现是创建一个返回所需bean的实例方法。

Additionally, we can configure Spring to create our desired bean with or without arguments.

此外,我们可以配置Spring来创建我们想要的Bean,无论是否有参数

2.1. Without Arguments

2.1.没有论据

We can create a Foo class that represents our bean being created:

我们可以创建一个Foo类,代表我们正在创建的bean。

public class Foo {}

Then, we create an InstanceFooFactory class that includes a factory method, createInstance, that creates our Foo bean:

然后,我们创建一个InstanceFooFactory类,其中包括一个工厂方法createInstance,用于创建我们的Foobean。

public class InstanceFooFactory {

    public Foo createInstance() {
        return new Foo();
    }
}

After that, we configure Spring:

之后,我们配置Spring。

  1. Create a bean for our factory class (InstanceFooFactory)
  2. Use the factory-bean attribute to reference our factory bean
  3. Use the factory-method attribute to reference our factory method (createInstance)

Applying this to a Spring XML configuration, we end up with:

将此应用于Spring XML配置,我们的结果是。

<beans ...>

    <bean id="instanceFooFactory"
      class="com.baeldung.factorymethod.InstanceFooFactory" />

    <bean id="foo"
      factory-bean="instanceFooFactory"
      factory-method="createInstance" />

</beans>

Lastly, we autowire our desired Foo bean. Spring will then create our bean using our createInstance factory method:

最后,我们自动连接我们想要的Foo Bean。然后,Spring将使用createInstance工厂方法创建我们的Bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/instance-config.xml")
public class InstanceFooFactoryIntegrationTest {

    @Autowired
    private Foo foo;
    
    @Test
    public void givenValidInstanceFactoryConfig_whenCreateFooInstance_thenInstanceIsNotNull() {
        assertNotNull(foo);
    }
}

2.2. With Arguments

2.2.有论据

We can also provide arguments to our instance factory method using the constructor-arg element in our Spring configuration.

我们还可以使用Spring配置中的constructor-arg元素为我们的实例工厂方法提供参数

First, we create a class, Bar, that utilizes an argument:

首先,我们创建一个类,Bar,它利用一个参数。

public class Bar {

    private String name;

    public Bar(String name) {
        this.name = name;
    }

    // ...getters & setters
}

Next, we create an instance factory class, InstanceBarFactory, with a factory method that accepts an argument and returns a Bar bean:

接下来,我们创建一个实例工厂类,InstanceBarFactory,其工厂方法接受一个参数并返回一个Barbean。

public class InstanceBarFactory {

    public Bar createInstance(String name) {
        return new Bar(name);
    }
}

Lastly, we add a constructor-arg element to our Bar bean definition:

最后,我们在Barbean定义中添加一个constructor-arg元素。

<beans ...>

    <bean id="instanceBarFactory"
      class="com.baeldung.factorymethod.InstanceBarFactory" />

    <bean id="bar"
      factory-bean="instanceBarFactory"
      factory-method="createInstance">
        <constructor-arg value="someName" />
    </bean>

</beans>

We can then autowire our Bar bean in the same manner as we did for our Foo bean:

然后,我们可以像对待Foo Bean那样,自动连接我们的Bar Bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/instance-bar-config.xml")
public class InstanceBarFactoryIntegrationTest {

    @Autowired
    private Bar instance;
    
    @Test
    public void givenValidInstanceFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
        assertNotNull(instance);
        assertEquals("someName", instance.getName());
    }
}

3. Static Factory Method

3.静态工厂法

We can also configure Spring to use a static method as a factory method.

我们也可以将Spring配置为使用静态方法作为工厂方法。

While instance factory methods should be preferred, this technique can be useful if we have existing, legacy static methods that produce desired beans. For example, if a factory method returns a singleton, we can configure Spring to use this singleton factory method.

虽然应该首选实例工厂方法,但如果我们有现有的、遗留的静态方法可以产生所需的Bean,那么这种技术也是有用的。例如,如果一个工厂方法返回一个单子,我们可以配置Spring以使用这个单子工厂方法。

Similar to instance factory methods, we can configure static methods with and without arguments.

与实例工厂方法类似,我们可以配置带参数和不带参数的静态方法。

3.1. Without Arguments

3.1.没有论据

Using our Foo class as our desired bean, we can create a class, SingletonFooFactory, that includes a createInstance factory method that returns a singleton instance of Foo:

使用我们的 Foo 类作为我们想要的 bean,我们可以创建一个 SingletonFooFactory 类,它包括一个 createInstance 工厂方法,该方法可返回 Foo 的单例。

public class SingletonFooFactory {

    private static final Foo INSTANCE = new Foo();
    
    public static Foo createInstance() {
        return INSTANCE;
    }
}

This time, we only need to create one bean. This bean requires only two attributes:

这一次,我们只需要创建一个Bean。这个Bean只需要两个属性。

  1. class – declares our factory class (SingletonFooFactory)
  2. factory-method – declares the static factory method (createInstance)

Applying this to our Spring XML configuration, we get:

将此应用于我们的Spring XML配置,我们得到了。

<beans ...>

    <bean id="foo"
      class="com.baeldung.factorymethod.SingletonFooFactory"
      factory-method="createInstance" />

</beans>

Lastly, we autowire our Foo bean using the same structure as before:

最后,我们使用与之前相同的结构自动连接我们的Foo Bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/static-foo-config.xml")
public class SingletonFooFactoryIntegrationTest {

    @Autowired
    private Foo singleton;
    
    @Test
    public void givenValidStaticFactoryConfig_whenCreateInstance_thenInstanceIsNotNull() {
        assertNotNull(singleton);
    }
}

3.2. With Arguments

3.2.有论据

While we should avoid changing the state of static objects — like our singleton — when possible, we can still pass arguments to our static factory method.

虽然我们应该尽可能避免改变静态对象的状态–比如我们的单子–但是我们仍然可以向静态工厂方法传递参数。

To do this, we create a new factory method that accepts our desired arguments:

为此,我们创建一个新的工厂方法,接受我们想要的参数。

public class SingletonBarFactory {

    private static final Bar INSTANCE = new Bar("unnamed");
    
    public static Bar createInstance(String name) {
        INSTANCE.setName(name);
        return INSTANCE;
    }
}

After that, we configure Spring to pass in the desired argument using the constructor-arg element:

之后,我们配置Spring,让它使用constructor-arg元素传入所需参数。

<beans ...>

    <bean id="bar"
      class="com.baeldung.factorymethod.SingletonBarFactory"
      factory-method="createInstance">
        <constructor-arg value="someName" />
    </bean>

</beans>

Lastly, we autowire our Bar bean using the same structure as before:

最后,我们使用与之前相同的结构自动连接我们的Bar Bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/factorymethod/static-bar-config.xml")
public class SingletonBarFactoryIntegrationTest {

    @Autowired
    private Bar instance;
    
    @Test
    public void givenValidStaticFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
        assertNotNull(instance);
        assertEquals("someName", instance.getName());
    }
}

4. Conclusion

4.总结

In this article, we looked at how to configure Spring to use instance and static factory methods — both with and without arguments.

在这篇文章中,我们研究了如何配置Spring以使用实例和静态工厂方法–包括有参数和无参数。

While creating beans through constructor and field injection is more common, factory methods can be handy for complex creation steps and legacy code.

虽然通过构造函数和字段注入来创建Bean比较常见,但工厂方法对于复杂的创建步骤和遗留代码来说是很方便的。

The code used in this article can be found over on GitHub.

本文中使用的代码可以在GitHub上找到over