Как использовать Spring FactoryBean?

Как использовать Spring FactoryBean?

1. обзор

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

Проще говоря, мы можем создать фабричный компонент, реализовав интерфейсorg.springframework.beans.factory.FactoryBean.

2. Основы фабричной фасоли __

2.1. РеализуйтеFactoryBean

Давайте сначала посмотрим на интерфейсFactoryBean:

public interface FactoryBean {
    T getObject() throws Exception;
    Class getObjectType();
    boolean isSingleton();
}

Давайте обсудим три метода:

  • getObject() - возвращает объект, созданный фабрикой, и это объект, который будет использоваться контейнером Spring

  • getObjectType() - возвращает тип объекта, который производит этотFactoryBean

  • isSingleton() - обозначает, является ли объект, созданный этимFactoryBean, одноэлементным

Теперь давайте реализуем примерFactoryBean. Мы реализуемToolFactory, который создает объекты типаTool:

public class Tool {

    private int id;

    // standard constructors, getters and setters
}

СамToolFactory:

public class ToolFactory implements FactoryBean {

    private int factoryId;
    private int toolId;

    @Override
    public Tool getObject() throws Exception {
        return new Tool(toolId);
    }

    @Override
    public Class getObjectType() {
        return Tool.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    // standard setters and getters
}

Как мы видим,ToolFactory - этоFactoryBean, который может создавать объектыTool.

2.2. ИспользуйтеFactoryBean с конфигурацией на основе XML

Давайте теперь посмотрим, как использовать нашToolFactory.

Мы начнем создавать инструмент с конфигурацией на основе XML -factorybean-spring-ctx.xml:



    
        
        
    

Затем мы можем проверить, правильно ли введен объектTool:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" })
public class FactoryBeanXmlConfigTest {
    @Autowired
    private Tool tool;

    @Test
    public void testConstructWorkerByXml() {
        assertThat(tool.getId(), equalTo(1));
    }
}

Результат теста показывает, что нам удалось внедрить объект инструмента, созданныйToolFactory, со свойствами, которые мы настроили вfactorybean-spring-ctx.xml.

Результат теста также показывает, что контейнер Spring использует объект, созданныйFactoryBean, вместо себя для внедрения зависимости.

Хотя контейнер Spring использует возвращаемое значение методаFactoryBean ’sgetObject() в качестве компонента, вы также можете использовать самFactoryBean.

Чтобы получить доступ кFactoryBean, вам просто нужно добавить «&» перед именем bean-компонента.

Давайте попробуем получить фабричный компонент и его свойствоfactoryId:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:factorybean-spring-ctx.xml" })
public class FactoryBeanXmlConfigTest {

    @Resource(name = "&tool")
    private ToolFactory toolFactory;

    @Test
    public void testConstructWorkerByXml() {
        assertThat(toolFactory.getFactoryId(), equalTo(9090));
    }
}

2.3. ИспользуйтеFactoryBean с конфигурацией на основе Java

ИспользованиеFactoryBean с конфигурацией на основе Java немного отличается от конфигурации на основе XML, вам нужно явно вызвать методFactoryBean‘sgetObject().

Давайте преобразуем пример из предыдущего раздела в пример конфигурации на основе Java:

@Configuration
public class FactoryBeanAppConfig {

    @Bean(name = "tool")
    public ToolFactory toolFactory() {
        ToolFactory factory = new ToolFactory();
        factory.setFactoryId(7070);
        factory.setToolId(2);
        return factory;
    }

    @Bean
    public Tool tool() throws Exception {
        return toolFactory().getObject();
    }
}

Затем мы проверяем, правильно ли введен объектTool:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FactoryBeanAppConfig.class)
public class FactoryBeanJavaConfigTest {

    @Autowired
    private Tool tool;

    @Resource(name = "&tool")
    private ToolFactory toolFactory;

    @Test
    public void testConstructWorkerByJava() {
        assertThat(tool.getId(), equalTo(2));
        assertThat(toolFactory.getFactoryId(), equalTo(7070));
    }
}

Результат теста показывает тот же эффект, что и предыдущий тест конфигурации на основе XML.

3. Способы инициализации

Иногда вам нужно выполнить некоторые операции после установкиFactoryBean, но до вызова методаgetObject(), например, проверки свойств.

Вы можете добиться этого, реализовав интерфейсInitializingBean или используя аннотацию@PostConstruct.

Более подробная информация об использовании этих двух решений была представлена ​​в другой статье:Guide To Running Logic on Startup in Spring.

4. AbstractFactoryBeanс

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

Давайте реализуемSingleToolFactory иNonSingleToolFactory, чтобы показать, как использоватьAbstractFactoryBean как для одиночного, так и для прототипного типа:

public class SingleToolFactory extends AbstractFactoryBean {

    private int factoryId;
    private int toolId;

    @Override
    public Class getObjectType() {
        return Tool.class;
    }

    @Override
    protected Tool createInstance() throws Exception {
        return new Tool(toolId);
    }

    // standard setters and getters
}

А теперь не единственная реализация:

public class NonSingleToolFactory extends AbstractFactoryBean {

    private int factoryId;
    private int toolId;

    public NonSingleToolFactory() {
        setSingleton(false);
    }

    @Override
    public Class getObjectType() {
        return Tool.class;
    }

    @Override
    protected Tool createInstance() throws Exception {
        return new Tool(toolId);
    }

    // standard setters and getters
}

Кроме того, XML-конфигурация для этих фабричных компонентов:



    
        
        
    

    
        
        
    

Теперь мы можем проверить, вводятся ли свойства объектовWorker так, как мы ожидали:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:factorybean-abstract-spring-ctx.xml" })
public class AbstractFactoryBeanTest {

    @Resource(name = "singleTool")
    private Tool tool1;

    @Resource(name = "singleTool")
    private Tool tool2;

    @Resource(name = "nonSingleTool")
    private Tool tool3;

    @Resource(name = "nonSingleTool")
    private Tool tool4;

    @Test
    public void testSingleToolFactory() {
        assertThat(tool1.getId(), equalTo(1));
        assertTrue(tool1 == tool2);
    }

    @Test
    public void testNonSingleToolFactory() {
        assertThat(tool3.getId(), equalTo(2));
        assertThat(tool4.getId(), equalTo(2));
        assertTrue(tool3 != tool4);
    }
}

Как видно из тестов,SingleToolFactory создает одноэлементный объект, аNonSingleToolFactory создает объект-прототип.

Обратите внимание, что нет необходимости устанавливать свойство singleton вSingleToolFactory, потому что вAbstractFactory значение свойства singleton по умолчанию равноtrue.

5. Заключение

ИспользованиеFactoryBean может быть хорошей практикой для инкапсуляции сложной логики построения или упрощения настройки легко настраиваемых объектов в Spring.

Итак, в этой статье мы представили основы того, как реализовать нашFactoryBean, как использовать его как в конфигурации на основе XML, так и в конфигурации на основе Java, а также некоторые другие различные аспектыFactoryBean, такие как инициализацияFactoryBean иAbstractFactoryBean.

Как всегда, полный источник -over on GitHub.