«1. Введение

Фабричные методы могут быть полезным методом для сокрытия сложной логики создания в одном вызове метода.

Хотя мы обычно создаем bean-компоненты в Spring с помощью конструктора или внедрения полей, мы также можем создавать bean-компоненты Spring с использованием фабричных методов.

В этом уроке мы углубимся в создание bean-компонентов Spring с использованием методов экземпляра и статической фабрики.

2. Метод фабрики экземпляров

Стандартная реализация шаблона метода фабрики заключается в создании метода экземпляра, который возвращает желаемый компонент.

Кроме того, мы можем настроить Spring для создания желаемого bean-компонента с аргументами или без них.

2.1. Без аргументов

Мы можем создать класс Foo, представляющий создаваемый наш bean-компонент:

public class Foo {}

Затем мы создаем класс InstanceFooFactory, который включает фабричный метод createInstance, создающий наш bean-компонент Foo:

public class InstanceFooFactory {

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

~~ ~ После этого мы настраиваем 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)

Применяя это к XML-конфигурации Spring, мы получаем:

<beans ...>

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

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

</beans>

Наконец, мы автоматически связываем желаемый bean-компонент Foo. Затем Spring создаст наш bean-компонент, используя наш фабричный метод createInstance:

@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. С аргументами

Мы также можем предоставить аргументы нашему методу фабрики экземпляров, используя элементstructor-arg в нашей конфигурации Spring.

Сначала мы создаем класс Bar, который использует аргумент:

public class Bar {

    private String name;

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

    // ...getters & setters
}

Затем мы создаем класс фабрики экземпляров, InstanceBarFactory, с фабричным методом, который принимает аргумент и возвращает bean-компонент Bar: ~~ ~

public class InstanceBarFactory {

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

Наконец, мы добавляем элемент конструктора-аргумента в определение нашего bean-компонента Bar:

<beans ...>

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

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

</beans>

Затем мы можем автоматически связать наш bean-компонент Bar так же, как мы сделали это для нашего bean-компонента Foo:

@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. Статический фабричный метод

Мы также можем настроить Spring для использования статического метода в качестве фабричного метода.

Хотя методы фабрики экземпляров следует отдавать предпочтение, этот метод может быть полезен, если у нас есть существующие, устаревшие статические методы, которые производят желаемые компоненты. Например, если фабричный метод возвращает синглтон, мы можем настроить Spring для использования этого фабричного метода синглтона.

Подобно методам фабрики экземпляров, мы можем настраивать статические методы с аргументами и без них.

3.1. Без аргументов

Используя наш класс Foo в качестве желаемого bean-компонента, мы можем создать класс SingletonFooFactory, который включает фабричный метод createInstance, возвращающий одноэлементный экземпляр Foo:

public class SingletonFooFactory {

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

На этот раз нам нужно только создать один боб. Этот bean-компонент требует только два атрибута:

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

Применив это к нашей XML-конфигурации Spring, мы получим:

<beans ...>

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

</beans>

Наконец, мы автоматически подключаем наш bean-компонент Foo, используя ту же структуру, что и раньше:

@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. С аргументами

Хотя нам следует избегать изменения состояния статических объектов, таких как наш синглтон, когда это возможно, мы все же можем передавать аргументы в наш статический фабричный метод.

Для этого мы создаем новый фабричный метод, который принимает нужные нам аргументы:

public class SingletonBarFactory {

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

После этого мы настраиваем Spring для передачи нужного аргумента с помощью элемента конструктора-аргумента:

<beans ...>

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

</beans>

Наконец, мы автоматически связываем наш bean-компонент Bar, используя ту же структуру, что и раньше: без аргументов.

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

Хотя создание bean-компонентов с помощью конструктора и внедрения полей более распространено, фабричные методы могут быть удобны для сложных шагов создания и устаревшего кода.

Код, использованный в этой статье, можно найти на GitHub.

«

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