Is there a way to have @Lazy
loading @Component
s 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
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?
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.
@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.
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With