web-dev-qa-db-fra.com

La meilleure façon d'obtenir @Autowired @Lazy @Components via des annotations?

Existe-t-il un moyen d'avoir @Lazy chargement @Components qui sont encore @Autowired dans une usine via des annotations? Le problème que j'ai trouvé est qu'en câblant automatiquement mes composants paresseux en usine, ils seront tous instanciés immédiatement une fois l'usine chargée, annulant l'annotation paresseuse.

J'ai défini plusieurs haricots paresseux tels que

@Component
@Lazy
public final class CloseableChromeWebDriver
      extends ChromeDriver
      implements DisposableBean {
...
}

@Component
@Lazy
public final class CloseableFirefoxWebDriver
      extends FirefoxDriver
      implements DisposableBean {
...
}

Il est important qu'ils soient paresseux car

  • Chaque fois que l'un d'eux est créé, la fenêtre du navigateur apparaît.
  • mes tests basés sur les données peuvent nécessiter ou non l'un d'entre eux ou tous, c'est-à-dire qu'une seule exécution peut être entièrement Firefox ou peut nécessiter Firefox et Chrome.
  • c'est plus important car en fait j'ai six de ces beans - Firefox, Chrome, IE, Firefox à distance, Chrome à distance, IE à distance.
  • Donc, si mes tests n'utilisent qu'un seul d'entre eux, alors je veux seulement qu'un navigateur s'affiche, pas tous.

J'ai une usine pour obtenir le navigateur demandé, mais ma première tentative a échoué car chaque fois qu'une classe utilisait l'usine, tous les beans câblés automatiquement étaient instanciés immédiatement, qu'ils aient été réellement demandés ou non. Je comprends que c'est parce qu'une fois que la classe est instanciée, elle doit instancier toutes les variables d'instance qui lui appartiennent.

@Component
public final class WebDriverFactory {
   @Autowired
   private CloseableChromeWebDriver chromeWebDriver;
   @Autowired
   private CloseableFirefoxWebDriver firefoxWebDriver;

   public synchronized WebDriver getWebDriver(final Browser browser) {
     // get whatever webdriver is matched by the enum Browser.
   }
}

Voici donc ma deuxième approche qui consiste à assurer un chargement paresseux en demandant le bean via le contexte de l'application:

@Component
public final class WebDriverFactory {
   private CloseableChromeWebDriver chromeWebDriver;
   private CloseableFirefoxWebDriver firefoxWebDriver;
   @Autowired
   private ApplicationContext appContext;

   public synchronized WebDriver getWebDriver(final Browser browser) {
      WebDriver driver = null;
      switch (browser) {
         case FIREFOX:
            if (firefoxRemoteWebDriver == null) {
               firefoxRemoteWebDriver = appContext.getBean("closeableRemoteFirefoxWebDriver",
                     CloseableRemoteFirefoxWebDriver.class);
            }
            driver = firefoxRemoteWebDriver;
            break;
      // etc...
      return driver;
   }
}

Cette approche atteint mon objectif, mais je pense qu'elle nie vraiment l'utilité d'utiliser des annotations. Existe-t-il un moyen purement basé sur des annotations pour y parvenir?

  • JDK 6
  • Spring 3.2.6.RELEASE
  • Pas de xml, juste des annotations.
29
Robert Mark Bram

Tu dois avoir @Lazy annotation sur votre composant également au point où il se trouve @Autowired in. C'est parce que si vous n'avez pas @Lazy sur votre composant, il est alors créé avec empressement en tant que bean, et si vous n'avez pas de @Lazy Sur ton @Autowired puis à nouveau, il est créé avec impatience et injecté dans le haricot. Essayez donc ce qui suit et cela devrait fonctionner:

@Component
public final class WebDriverFactory {
   @Autowired @Lazy
   private CloseableChromeWebDriver chromeWebDriver;
   @Autowired @Lazy
   private CloseableFirefoxWebDriver firefoxWebDriver;
49
Biju Kunjummen