Comment utiliser le Spring FactoryBean?

1. Vue d'ensemble

Il existe deux types de haricots dans le conteneur de haricots de printemps: les haricots ordinaires et les haricots d'usine. Spring utilise directement le premier, tandis que le second peut produire des objets eux-mêmes, qui sont gérés par le framework.

Et, en termes simples, nous pouvons créer un bean usine en implémentant l' interface org.springframework.beans.factory.FactoryBean .

2. Les bases des haricots d'usine

2.1. Implémenter un FactoryBean

Regardons d' abord l'interface FactoryBean :

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

Discutons des trois méthodes:

  • getObject () - renvoie un objet produit par la fabrique, et c'est l'objet qui sera utilisé par le conteneur Spring
  • getObjectType () - renvoie le type d'objet produit par ce FactoryBean
  • isSingleton () - indique si l'objet produit par ce FactoryBean est un singleton

Maintenant, implémentons un exemple FactoryBean . Nous allons implémenter une ToolFactory qui produit des objets de type Tool :

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

La ToolFactory elle-même:

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 }

Comme nous pouvons le voir, ToolFactory est un FactoryBean , qui peut produire des objets Tool .

2.2. Utiliser FactoryBean avec une configuration basée sur XML

Voyons maintenant comment utiliser notre ToolFactory .

Nous allons commencer à construire un outil avec une configuration basée sur XML - factorybean-spring-ctx.xml :

Ensuite, nous pouvons tester si l' objet Tool est correctement injecté:

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

Le résultat du test montre que nous parvenons à injecter l'objet outil produit par ToolFactory avec les propriétés que nous avons configurées dans le fichier factorybean-spring-ctx.xml .

Le résultat du test montre également que le conteneur Spring utilise l'objet produit par FactoryBean au lieu de lui-même pour l'injection de dépendances.

Bien que le récipient Spring utilise le FactoryBean de getObject () la valeur de retour de la méthode que le haricot, vous pouvez également utiliser le FactoryBean lui - même.

Pour accéder à FactoryBean , il vous suffit d'ajouter un «&» avant le nom du bean.

Essayons d'obtenir le bean factory et sa propriété 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. Utiliser FactoryBean avec une configuration basée sur Java

Utilisation FactoryBean avec la configuration Java est un peu différent avec la configuration XML, vous devez appeler le FactoryBean de getObject () méthode explicitement.

Convertissons l'exemple de la sous-section précédente en un exemple de configuration basé sur 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(); } }

Ensuite, nous testons si l' objet Tool est correctement injecté:

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

Le résultat du test montre un effet similaire à celui du test de configuration XML précédent.

3. Façons d'initialiser

Parfois, vous devez effectuer certaines opérations après que FactoryBean a été défini mais avant que la méthode getObject () ne soit appelée, comme la vérification des propriétés.

Vous pouvez y parvenir en implémentant l' interface InitializingBean ou en utilisant l' annotation @PostConstruct .

Plus de détails sur l'utilisation de ces deux solutions ont été présentés dans un autre article: Guide pour exécuter Logic au démarrage au printemps.

4. AbstractFactoryBean

Spring fournit le AbstractFactoryBean comme une simple superclasse de modèle pour les implémentations FactoryBean . Avec cette classe de base, nous pouvons maintenant implémenter plus facilement un bean factory qui crée un singleton ou un objet prototype.

Implémentons un SingleToolFactory et un NonSingleToolFactory pour montrer comment utiliser AbstractFactoryBean pour les types singleton et prototype:

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 }

Et maintenant l'implémentation non -ingleton:

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 }

En outre, la configuration XML pour ces beans d'usine:

Nous pouvons maintenant tester si les propriétés des objets Worker sont injectées comme prévu:

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

Comme nous pouvons le voir à partir des tests, le SingleToolFactory produit un objet singleton et le NonSingleToolFactory produit un objet prototype.

Notez qu'il n'est pas nécessaire de définir la propriété singleton dans SingleToolFactory car, dans AbstractFactory , la valeur par défaut de la propriété singleton est true .

5. Conclusion

L'utilisation d'un FactoryBean peut être une bonne pratique pour encapsuler une logique de construction complexe ou faciliter la configuration d'objets hautement configurables dans Spring.

Donc, dans cet article, nous avons présenté les bases de la façon d'implémenter notre FactoryBean , comment l'utiliser à la fois dans une configuration XML et une configuration basée sur Java, ainsi que d'autres aspects divers de FactoryBean , tels que l'initialisation de FactoryBean et AbstractFactoryBean .

Comme toujours, la source complète est terminée sur GitHub.