Wie benutzt man die Spring FactoryBean?

1. Übersicht

Der Springbohnenbehälter enthält zwei Arten von Bohnen: normale Bohnen und Fabrikbohnen. Spring verwendet erstere direkt, während letztere selbst Objekte produzieren können, die vom Framework verwaltet werden.

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

2. Die Grundlagen der Fabrikbohnen

2.1. Implementieren Sie eine FactoryBean

Schauen wir uns zuerst die FactoryBean- Oberfläche an:

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

Lassen Sie uns die drei Methoden diskutieren:

  • getObject () - gibt ein von der Factory erstelltes Objekt zurück. Dies ist das Objekt, das vom Spring-Container verwendet wird
  • getObjectType () - gibt den Objekttyp zurück, den diese FactoryBean erzeugt
  • isSingleton () - Gibt an, ob das von dieser FactoryBean erzeugte Objekt ein Singleton ist

Lassen Sie uns nun ein Beispiel für FactoryBean implementieren . Wir werden eine ToolFactory implementieren, die Objekte vom Typ Tool erzeugt :

public class Tool { private int id; // standard constructors, getters and setters }

Die ToolFactory 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, ist die ToolFactory eine FactoryBean , die Tool- Objekte erzeugen kann.

2.2. Verwenden Sie FactoryBean mit XML-basierter Konfiguration

Lassen Sie uns nun einen Blick auf die Verwendung unserer ToolFactory werfen .

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

Als nächstes können wir testen, ob das Tool- Objekt korrekt eingefügt 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 von der ToolFactory erzeugte Werkzeugobjekt mit den Eigenschaften zu injizieren, die wir in der factorybean-spring-ctx.xml konfiguriert haben .

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

Obwohl der Spring-Container den Rückgabewert der getObject () -Methode der FactoryBean als Bean verwendet, können Sie auch die FactoryBean selbst verwenden.

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

Versuchen wir, die Factory-Bean und ihre factoryId- 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 Sie FactoryBean mit Java-basierter Konfiguration

Verwenden FactoryBean mit Java-basierter Konfiguration ist ein wenig anders mit XML-basierten Konfiguration, müssen Sie das nennen FactoryBean ‚s getObject () explizit Methode.

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 Tool- Objekt korrekt eingefügt 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 Vorgänge ausführen, nachdem die FactoryBean festgelegt wurde, aber bevor die getObject () -Methode aufgerufen wird, z. B. die Eigenschaftenprüfung.

Sie können dies erreichen, indem Sie die InitializingBean- Schnittstelle implementieren oder die Annotation @PostConstruct verwenden .

Weitere Informationen zur Verwendung dieser beiden Lösungen wurden in einem anderen Artikel vorgestellt: Anleitung zum Ausführen von Logik beim Start im Frühjahr.

4. AbstractFactoryBean

Spring bietet die AbstractFactoryBean als einfache Vorlagen-Superklasse für FactoryBean- Implementierungen. Mit dieser Basisklasse können wir jetzt bequemer eine Factory-Bean implementieren, die ein Singleton- oder ein Prototypobjekt erstellt.

Implementieren wir eine SingleToolFactory und eine NonSingleToolFactory, um zu zeigen, wie AbstractFactoryBean sowohl für Singleton- als auch für Prototypentypen verwendet wird:

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 Nonsingleton-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 der Worker- Objekte wie erwartet eingefügt 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 aus den Tests hervorgeht, erzeugt die SingleToolFactory ein Singleton-Objekt und die NonSingleToolFactory ein Prototypobjekt.

Beachten Sie, dass die Singleton-Eigenschaft in SingleToolFactory nicht festgelegt werden muss, da in AbstractFactory der Standardwert der Singleton-Eigenschaft true ist .

5. Schlussfolgerung

Die Verwendung einer FactoryBean kann eine gute Methode sein, um komplexe Konstruktionslogiken zu kapseln oder die Konfiguration hoch konfigurierbarer Objekte im Frühjahr zu vereinfachen.

In diesem Artikel haben wir die Grundlagen zur Implementierung unserer FactoryBean , zur Verwendung sowohl in der XML-basierten Konfiguration als auch in der Java-basierten Konfiguration sowie einige andere verschiedene Aspekte von FactoryBean vorgestellt , z. B. die Initialisierung von FactoryBean und AbstractFactoryBean .

Wie immer ist die komplette Quelle auf GitHub vorbei.