Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to achieve @Autowired @Lazy @Components via annotations?

Is there a way to have @Lazy loading @Components that are still @Autowired in a factory via annotations? The problem I found is that by autowiring my lazy components in the factory, they will all be instantiated immediately once the factory is loaded, negating the lazy annotation.

I have defined several lazy beans such as

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

It is important that they be lazy because

  • Whenever one of them is created, the browser window pops up.
  • my data driven tests may or may not require any one or all of them i.e. one run may be all Firefox, or may require Firefox and Chrome.
  • this is more important because in fact I have six such beans - Firefox, Chrome, IE, Remote Firefox, Remote Chrome, Remote IE.
  • So, if my tests only use one of them, then I only want that one browser to show, not all them.

I have a Factory for getting the requested browser, but my first attempt at this failed because whenever any class used the factory, all of the autowired beans were being instantiated straight away, irrespective of whether they were actually requested. I understand this is because once the class is instantiated, it must instantiate all of the instance variables belonging to it.

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

So here is my second approach which is to ensure lazy loading by requesting the bean through the application context:

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

This approach achieves my goal, but I feel it really negates the usefulness of using annotations. Is there a purely annotation based way to achieve this?

  • JDK 6
  • Spring 3.2.6.RELEASE
  • No xml, just annotations.
like image 579
Robert Mark Bram Avatar asked Oct 22 '14 09:10

Robert Mark Bram


People also ask

What will be happen when @lazy is used with @autowired?

Lazy Initialize @Autowired DependencyThe Person bean will be created eagerly. But the autowired Address bean is annotated with the @Lazy annotation, which tells the spring container to initialize the bean only when it's first requested.

What does @lazy annotation do?

@Lazy annotation indicates whether a bean is to be lazily initialized. It can be used on @Component and @Bean definitions. A @Lazy bean is not initialized until referenced by another bean or explicitly retrieved from BeanFactory . Beans that are not annotated with @Lazy are initialized eagerly.

Which annotation is used for Autowiring?

The @Autowired annotation provides more fine-grained control over where and how autowiring should be accomplished. The @Autowired annotation can be used to autowire bean on the setter method just like @Required annotation, constructor, a property or methods with arbitrary names and/or multiple arguments.


1 Answers

You have to have @Lazy annotation on your component as well at the point where it is @Autowired in. This is because if you don't have @Lazy on your component, then it is eagerly created as a bean, and if you have don't have an @Lazy on your @Autowired then again it is eagerly created and injected into the bean. So try the following and it should just work:

@Component public final class WebDriverFactory {    @Autowired @Lazy    private CloseableChromeWebDriver chromeWebDriver;    @Autowired @Lazy    private CloseableFirefoxWebDriver firefoxWebDriver; 
like image 172
Biju Kunjummen Avatar answered Sep 18 '22 09:09

Biju Kunjummen