Wie benutze ich die Spring FactoryBean?

Wie benutzt man die Spring FactoryBean?

1. Überblick

Es gibt zwei Arten von Bohnen im Frühlingsbohnenbehälter: gewöhnliche Bohnen und Werksbohnen. Spring verwendet ersteres direkt, während letzteres selbst Objekte erzeugen kann, die vom Framework verwaltet werden.

Einfach ausgedrückt können wir eine Factory-Bean erstellen, indem wir die Schnittstelle vonorg.springframework.beans.factory.FactoryBeanimplementieren.

2. Die Grundlagen der Fabrikbohnen __

2.1. Implementieren Sie aFactoryBean

Schauen wir uns zuerst dieFactoryBean-Schnittstelle an:

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

Lassen Sie uns die drei Methoden diskutieren:

  • getObject() - gibt ein vom Werk hergestelltes Objekt zurück. Dies ist das Objekt, das vom Spring-Container verwendet wird

  • getObjectType() - Gibt den Objekttyp zurück, denFactoryBean erzeugt

  • isSingleton() - Gibt an, ob das von diesemFactoryBean erzeugte Objekt ein Singleton ist

Implementieren wir nun ein BeispielFactoryBean. Wir implementieren einToolFactory, das Objekte vom TypTool erzeugt:

public class Tool {

    private int id;

    // standard constructors, getters and setters
}

DasToolFactory selbst:

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
}

Wie wir sehen können, istToolFactory einFactoryBean, dasTool Objekte erzeugen kann.

2.2. Verwenden SieFactoryBean mit XML-basierter Konfiguration

Schauen wir uns nun an, wie wir unsereToolFactoryverwenden.

Wir beginnen mit der Erstellung eines Tools mit XML-basierter Konfiguration -factorybean-spring-ctx.xml:



    
        
        
    

Als nächstes können wir testen, ob das ObjektToolkorrekt injiziert wurde:

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

Das Testergebnis zeigt, dass es uns gelingt, das vonToolFactory erzeugte Werkzeugobjekt mit den infactorybean-spring-ctx.xml konfigurierten Eigenschaften zu injizieren.

Das Testergebnis zeigt auch, dass der Spring-Container das vonFactoryBean erzeugte Objekt anstelle von sich selbst für die Abhängigkeitsinjektion verwendet.

Obwohl der Spring-Container den Rückgabewert dergetObject()-Methode vonFactoryBeanals Bean verwendet, können Sie auch dieFactoryBean selbst verwenden.

Um aufFactoryBean zuzugreifen, müssen Sie nur ein "&" vor dem Bean-Namen einfügen.

Versuchen wir, die Factory-Bean und ihrefactoryId-Eigenschaft abzurufen:

@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. Verwenden SieFactoryBean mit Java-basierter Konfiguration

Die Verwendung vonFactoryBean bei Java-basierter Konfiguration unterscheidet sich geringfügig von der XML-basierten Konfiguration. Sie müssen dieFactoryBeangetObject()-Methode explizit aufrufen.

Lassen Sie uns das Beispiel im vorherigen Unterabschnitt in ein Java-basiertes Konfigurationsbeispiel konvertieren:

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

Dann testen wir, ob das ObjektToolkorrekt injiziert wurde:

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

Das Testergebnis zeigt den ähnlichen Effekt wie der vorherige XML-basierte Konfigurationstest.

3. Möglichkeiten zur Initialisierung

Manchmal müssen Sie einige Operationen ausführen, nachdemFactoryBean festgelegt wurde, aber bevor die MethodegetObject() aufgerufen wird, z. B. die Eigenschaftenprüfung.

Sie können dies erreichen, indem Sie die SchnittstelleInitializingBeanimplementieren oder die Annotation@PostConstructverwenden.

Weitere Einzelheiten zur Verwendung dieser beiden Lösungen wurden in einem anderen Artikel vorgestellt:Guide To Running Logic on Startup in Spring.

4. AbstractFactoryBean

Spring stelltAbstractFactoryBean als einfache Vorlagen-Superklasse fürFactoryBean-Implementierungen bereit. Mit dieser Basisklasse können wir jetzt bequemer ein Factory-Bean implementieren, das einen Singleton oder ein Prototyp-Objekt erstellt.

Implementieren wir einSingleToolFactory und einNonSingleToolFactory, um zu zeigen, wieAbstractFactoryBean sowohl für Singleton- als auch für Prototypentypen verwendet werden:

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
}

Und jetzt die Nicht-Singleton-Implementierung:

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
}

Auch die XML-Konfiguration für diese Factory-Beans:



    
        
        
    

    
        
        
    

Jetzt können wir testen, ob die Eigenschaften derWorker-Objekte wie erwartet injiziert werden:

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

Wie wir aus den Tests sehen können, erzeugtSingleToolFactory ein Singleton-Objekt undNonSingleToolFactory erzeugt ein Prototypobjekt.

Beachten Sie, dass die Singleton-Eigenschaft nicht inSingleToolFactory festgelegt werden muss, da inAbstractFactory der Standardwert der Singleton-Eigenschafttrue ist.

5. Fazit

Die Verwendung vonFactoryBean kann eine gute Vorgehensweise sein, um komplexe Konstruktionslogiken zu kapseln oder die Konfiguration hoch konfigurierbarer Objekte in Spring zu vereinfachen.

In diesem Artikel haben wir die Grundlagen zur Implementierung unsererFactoryBean, zur Verwendung sowohl in der XML-basierten Konfiguration als auch in der Java-basierten Konfiguration sowie einige andere verschiedene Aspekte vonFactoryBean vorgestellt, z Initialisierung vonFactoryBean undAbstractFactoryBean.

Wie immer ist die vollständige Quelleover on GitHub.