2014-10-22 6 views
22

Есть ли способ иметь @Lazy loading @Component s что еще @Autowired на заводе через аннотации? Проблема, которую я обнаружил, заключается в том, что, автолюбив свои ленивые компоненты на заводе, все они будут созданы сразу после загрузки фабрики, отрицая ленивую аннотацию.Лучший способ добиться @Autowired @Lazy @Components через аннотации?

Я определили несколько ленивые бобы, такие как

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

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

Важно, чтобы они были ленивы, потому что

  • Всякий раз, когда один из них создается, в окне браузера всплывает.
  • Мои тесты, управляемые данными, могут требовать или не требовать ни одного или всех из них, то есть один запуск может быть всем Firefox, или может потребоваться Firefox и Chrome.
  • это более важно, потому что на самом деле у меня есть шесть таких бобы - Firefox, Chrome, IE, удаленный Firefox, удаленный Chrome, удаленный IE.
  • Итак, если в моих тестах используется только один из них, то я хочу, чтобы этот браузер показывал не все.

У меня есть завод для получения запрошенной браузера, но моя первая попытка это не удалось, потому что всякий раз, когда какой-либо класс, используемый на заводе, все autowired бобы были экземпляры сразу, независимо от того, были ли они на самом деле требуется. Я понимаю, это потому, что как только экземпляр класса создается, он должен создать экземпляр всех принадлежащих ему переменных экземпляра.

@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. 
    } 
} 

Так вот мой второй подход, который заключается в обеспечении отложенной загрузки, запрашивая боб через контекст приложения:

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

Этот подход достигает своей цели, но я чувствую, что это действительно сводит на нет полезность используя аннотации. Существует ли чисто основанный на аннотации способ достичь этого?

  • JDK 6
  • Spring 3.2.6.RELEASE
  • Нет XML, только аннотации.
+0

Несомненно, атрибут '@ Lazy' распространяется на пользователя компонента, а не на определение компонента. Поэтому я ожидаю, что вы повесите '@ Lazy' всюду, которая нуждается в том, чтобы bean был ленивый загружен. Если это ВЕЗДЕ, тогда компонент будет создан при первом использовании. –

+0

@AshleyFrieze Если я не понял, что вы говорите, ни один '@ Lazy' не переходит к пользователю компонента. Из [@Lazy Javadoc] (http://docs.spring.io/spring/docs /current/javadoc-api/org/springframework/context/annotation/Lazy.html): _ Может использоваться для любого класса, прямо или косвенно аннотированного с помощью @Component или методов, аннотированных с помощью @Bean ....Если присутствует и задано значение true, @Bean или @Component не будут инициализированы до тех пор, пока не будет указан другой компонент или явно извлечен из прилагаемого BeanFactory._ –

+0

@AshleyFrieze, весной 4, вы на самом деле правы, как ответ Биджу. так что спасибо. :) –

ответ

29

Вы должны иметь @Lazy аннотацию на компоненте, а в точке, где она @Autowired. Это происходит потому, что если вы не имеете @Lazy на компоненте, то он охотно создан как боб, и если у вас нет @Lazy на вашем @Autowired, то снова он охотно создается и вводится в bean-компонент. Поэтому попробуйте следующее, и оно должно просто работать:

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

Я достаточно уверен, что мне нужна весна 4, так как я читал об этом вчера вечером: http://zezutom.blogspot.com.au/2014/01/spring-series-part-4-lazy-on- injection.html. Мы используем Spring 3 atm, однако эта страница, похоже, объясняет, как добиться такого же эффекта с провайдером. Я не пробовал, потому что, честно говоря, я еще не понял этого. –

+0

ОК, я тестировал это. Я не могу использовать '@Autowired @ Lazy' с Spring 3, но могу с Spring 4 - и он отлично работает. Я также нашел время, чтобы выяснить, как использовать 'javax.inject.Inject' и' javax.inject.Provider' как [Блог Тома] (http://zezutom.blogspot.com.au/2014/01/spring- series-part-4-lazy-on-injection.html), но для этого просто требуется слишком много дополнительного кода, потому что мне придется писать тип «Provider» для каждого веб-драйвера, потому что это разные классы. –

+1

Итак, в заключение, если я могу перейти к Spring 4, '@Autowired @ Lazy' делает именно то, что я хочу. Если мне нужно остаться с весной 3, я достаточно доволен, чтобы использовать 'appContext.getBean (..)' в качестве компромисса. Итак, спасибо @Biju! –

Смежные вопросы