web-dev-qa-db-fra.com

Comment éviter d'utiliser ApplicationContext.getBean () lors de l'implémentation de Spring IOC

Je commence tout juste à utiliser le concept Spring IOC. Je vois souvent que la plupart des exemples trouvés sur Internet utilisent le code pour obtenir l'objet.

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) appContext.getBean("hello"); 

En référence à ces questions 1 et 2 dans le stackoverflow. J'ai déduit que, il n'est pas nécessaire d'utiliser appContext.getBean ("hello") dans le code, ce qui est considéré comme une mauvaise pratique. En outre, plus recommandé. Corrigez-moi bien ici, si ma déduction est fausse. 

Gardant cela à l’esprit, j’ai apporté des modifications à mon projet en conséquence ... Voici mon applicationContext.xml 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="utilClassRef" class="org.hd.derbyops.DUtils" lazy-init="false" />
<bean id="appContext" class="org.hd.derbyops.ContextProvider" lazy-init="false">
   <property name="utils" ref="utilClassRef" />
</bean>
</beans>

Mon contexte Code de fournisseur

public class ContextProvider implements ApplicationContextAware {

    private static ApplicationContext ctx;

    /**
     * Objects as properties
     */
    private static DUtils utils;

    public void setApplicationContext(ApplicationContext appContext)
            throws BeansException {
        ctx = appContext;

    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }

    public static DUtils getUtils() {
        return utils;
    }

    public void setUtils(DUtils dUtilsRef) {
        utils = dUtilsRef;
    }

}

Par exemple, considérons une classe A qui dépend de org.hd.derbyops.DUtils. J'utilise la ligne de code suivante

ContextProvider.getUtils();

afin d’obtenir DUtils Object en classe A, évitant ainsi l’utilisation de ApplicationContext.getBean() n’importe où dans mon code.

Supposons que si j'ai 10 classes et que ma classe A dépende de toutes, dont les objets doivent être créés et accessibles sans utiliser ApplicationContext.getBean(). Dans ce cas également, comme cela a été fait ci-dessus, j'ai l'idée de créer des propriétés de la classe ContextProvider, suivies des propriétés setter et getter de cette propriété, où get<PropertyName> est statique. Pour que je puisse l'utiliser partout où j'ai besoin d'un objet, comme celui-ci

ContextProvider.get<PropertyName>;

Voici ma brève question. Premièrement, mon approche est-elle correcte? Si c'est correct, charger tous les haricots au démarrage, ne serait-ce pas un tueur de performance? Comment feriez-vous cela dans vos applications sans appeler getBean au moins une fois?

Si vous deviez concevoir une application Web et implémenter Spring IOC, sans utiliser ApplicationContext.getBean() dans le code. Comment feriez-vous cela? 

Note: en référence aux autres questions ci-dessus 

L'appel de ApplicationContext.getBean () n'est pas une inversion de contrôle!

12
srk

Les réponses simples sont oui et non, non et non. Et enfin, effectuez une recherche en ligne pour le printemps MVC, car il fait probablement ce que vous voulez.

Alors, votre approche. Oui, vous avez presque tout droit. Cependant, il est considéré comme une très mauvaise pratique d’utiliser des méthodes statiques pour tout. Et vous n'avez pas besoin de le faire. Spring est basé sur l’idée que vous pouvez simplement créer des pojos normaux, et Spring les utilisera comme des singletons et s’injectera les uns dans les autres (il peut également créer des objets à la volée, mais je vais ici pour le cas courant). Si vous utilisez des classes et des méthodes statiques, alors:

  • Vous ne pouvez pas vous moquer d'eux pour les tests unitaires (vous utilisez JUnit, n'est-ce pas?)
  • Vous ne pouvez pas les utiliser avec l'héritage
  • Les initialiseurs statiques sont un excellent moyen de perdre des exceptions
  • etc

Donc, oui à l'injection, et non aux choses statiques.

Ensuite, la performance. Vous avez raison de dire que l'utilisation du printemps est beaucoup plus lente, mais si vous faites toute votre injection au démarrage, cela ne se produit qu'une fois. Spring est destiné aux applications côté serveur où il est probable qu'un certain nombre de classes singleton transmettent des données. Il peut donc y avoir une classe pour obtenir des éléments d’une base de données, une pour les traiter et une pour les afficher, et spring est utilisé pour les relier ensemble.

Si vous utilisez spring dans une application où vous démarrez de manière répétée, comme une application en ligne de commande, vous l'utilisez pour le mauvais type d'application et vous souhaitez probablement utiliser un générateur. Spring est destiné aux grandes applications d'entreprise qui ne sont pas souvent redémarrées.

Enfin, si vous injectez simplement toutes les dépendances d'une classe au démarrage, et que vous le faites avec toutes vos classes, vous n'avez pas besoin de faire de trucs getBean. De plus, l'utilisation des attributs init-method et destroy-method sur un bean signifie que vous pouvez démarrer les processus une fois que spring a fini d'injecter des dépendances. Il vous suffit de charger le contexte et votre application va naître (jeu de mots).

En ce qui concerne les projets Web, Spring MVC prend essentiellement l’inversion complète du modèle de contrôle et l’applique aux applications Web. Les éléments de printemps sont chargés par le conteneur et vous pouvez définir les URL auxquelles vous souhaitez répondre en n'utilisant que des noms de beans. Et la plupart de votre code peut rester en tant que pojos. Si vous avez quelque chose de incroyablement complexe, vous voudrez peut-être examiner le flux Web du printemps, mais je vous conseillerais de vous assurer que votre ressort de printemps est très fort avant de tenter cela.

9
Jimadilo

Voici mon exemple pour obtenir la première instance sans appeler réellement getBean() sur ApplicationContext.

public class Test{
  // Declare private static variable so that we can access it in main()
  private static Triangle triangle;

  // Use constructor injection to set the triangle
  public Test(Triangle triangle) {
      Test.triangle = triangle;
  }

  public static void main(String[] args) {
      // Specify the context file containing the bean definitions
      // Spring automatically creates instances of all the beans defined
      // in this XML file. This process is performed before you actually make
      // a getBean("beanName") call.
      ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

      // Use instance methods of triangle 
      Test.triangle.draw();
  }
} 

Vous pouvez utiliser un autre moyen:

Dans spring.xml (votre fichier XML de configuration de bean)

<bean class="com.example.Test" init-method="myMethod">
    <constructor-args ref="triangle"/>
</bean>

Maintenant pour votre classe principale

public class Test {
  private final Triangle triangle;

  public Test (Triangle triangle) {
     this.triangle = triangle;
  }

  public static void main (String[] args) {
     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  }

  // Called by Spring immediately after the Triangle Bean has been created and
  // all the properties for the bean have been set. This method name must match
  // the one specified with destroy-method attribute in spring.xml
  public void myMethod () {
     triangle.draw();
  }
}
1
rIshab1988