最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Spring Boot `ApplicationContextRunner` loads `Lazy` defined beans - Stack Overflow

programmeradmin5浏览0评论

In the following configuration bean example,

@Configuration
public class LazyConfig
{
    @Bean
    @Lazy
    public SomeBean someBean(final DependencyBean dependencyBean)
    {
        return new SomeBean(dependencyBean);
    }
}

I expected the following test using ApplicationContextRunner should be working, but it fails:

class LazyConfigTest
{
  ApplicationContextRunner runner = new ApplicationContextRunner()
    .withUserConfiguration(LazyConfig.class);

  @Test
  void testNoLazyIsLoaded()
  {
    runner.run(context -> {
      .assertj.core.api.Assertions.assertThat(context).getBeanNames(SomeBean.class).isEmpty();
            // > Expecting empty but was: ["someBean"]
      .assertj.core.api.Assertions.assertThat(context).doesNotHaveBean(SomeBean.class);
            // > Expecting not to have, but found: <["someBean"]>
    });
  }
}

But then trying to get the bean itself fails for depedant,

context.getBean(SomeBean.class);
// > Error creating bean with name 'someBean' defined in .lucasvc.lazy.config.LazyConfig: Unsatisfied dependency expressed through method 'someBean' parameter 0: No qualifying bean of type '.lucasvc.lazy.DependencyBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

It is expected that there is such "beans" in the context, even annotated method with Lazy? How should be the best way to test the Lazy behavior?

In the following configuration bean example,

@Configuration
public class LazyConfig
{
    @Bean
    @Lazy
    public SomeBean someBean(final DependencyBean dependencyBean)
    {
        return new SomeBean(dependencyBean);
    }
}

I expected the following test using ApplicationContextRunner should be working, but it fails:

class LazyConfigTest
{
  ApplicationContextRunner runner = new ApplicationContextRunner()
    .withUserConfiguration(LazyConfig.class);

  @Test
  void testNoLazyIsLoaded()
  {
    runner.run(context -> {
      .assertj.core.api.Assertions.assertThat(context).getBeanNames(SomeBean.class).isEmpty();
            // > Expecting empty but was: ["someBean"]
      .assertj.core.api.Assertions.assertThat(context).doesNotHaveBean(SomeBean.class);
            // > Expecting not to have, but found: <["someBean"]>
    });
  }
}

But then trying to get the bean itself fails for depedant,

context.getBean(SomeBean.class);
// > Error creating bean with name 'someBean' defined in .lucasvc.lazy.config.LazyConfig: Unsatisfied dependency expressed through method 'someBean' parameter 0: No qualifying bean of type '.lucasvc.lazy.DependencyBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

It is expected that there is such "beans" in the context, even annotated method with Lazy? How should be the best way to test the Lazy behavior?

Share Improve this question asked Mar 25 at 12:50 lucasvclucasvc 8501 gold badge13 silver badges37 bronze badges 2
  • 4 Of course the bean names will be there as the definition of the bean is there. You marked it @Lazy so your bean will be there but it will be a proxy which will be used instead of your actual bean (which will be deferred until there is some action on it). Which is what you see when you try to get the bean as the dependent bean isn't there and thus it fails to actually construct it. – M. Deinum Commented Mar 25 at 12:58
  • Always fot about Spring proxy injection. Thanks. – lucasvc Commented Mar 26 at 10:36
Add a comment  | 

1 Answer 1

Reset to default 1

You have to consider how @Lazy beans work in Spring. If I have a class LazyBeanA that is marked as @Lazy, and I declare a class NotLazyB that autowires LazyBeanA does that negate LazyBeanA's laziness? No, it doesn't. But how does it construct NotLazyB if it's "eager" if not all properties can be satisfied? It can't satisfy the LazyBeanA autowire because it's lazy. Well, Spring gets around that by instantiating a proxy that sits in front of LazyBeanA. LazyBeanA isn't constructed, but the Proxy is. The proxy is a "stunt" bean. It's stands in for LazyBeanA until you invoke a method on it. At that point it constructs LazyBeanA, populates it's dependencies, and invokes the method.

So there is something registered under that bean's class/id. It's just the stunt bean.

发布评论

评论列表(0)

  1. 暂无评论