通过注释实现@Autowired @Lazy @Components的最佳方法?

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.

我定义了几个懒豆,例如

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

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

他们懒惰很重要,因为

  • 只要创建其中之一,浏览器窗口就会弹出。
  • 我的数据驱动测试可能需要也可能不需要任何一项或全部,即一次运行可能全部是Firefox,或者可能需要Firefox和Chrome。
  • 这一点更为重要,因为实际上我有六个这样的bean-Firefox,Chrome,IE,远程Firefox,远程Chrome,远程IE。
  • 因此,如果我的测试仅使用其中一种,那么我只希望显示一种浏览器,而不是全部。

我有一个工厂来获取请求的浏览器,但是我的第一次尝试失败了,因为每当有一个类使用工厂时,所有自动装配的Bean都会立即实例化,而不管它们是否实际被请求。我知道这是因为一旦实例化了类,它就必须实例化属于它的所有实例变量。

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

因此,这是我的第二种方法,即通过在应用程序上下文中请求Bean来确保延迟加载:

@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
  • 春天3.2.6.RELEASE
  • 没有xml,只有注释。

最佳答案

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;