【问题标题】:How to use spring @Lookup annotation?如何使用spring@Lookup注解?
【发布时间】:2014-11-19 14:55:47
【问题描述】:

我需要从单例中获取原型类。我发现方法注入是要走的路,但我真的不知道如何使用spring @Lookup注解。

我是依赖注入的新手,我选择使用注解配置,所以我想继续朝这个方向发展。

我发现@Lookup 注释是最近才添加的(https://spring.io/blog/2014/09/04/spring-framework-4-1-ga-is-here),但我找不到任何地方如何使用它。

所以,这里是简化的例子

配置类:

@Configuration
@Lazy
public class ApplicationConfiguration implements ApplicationConfigurationInterface {

  @Bean
  public MyClass1 myClass1() {
    return new ContentHolderTabPaneController();
  }

  @Bean
  @Scope("prototype")
  public MyClass2 myClass2() {
    return new SidebarQuickMenuController();
  }
}

这是类示例:

public class MyClass1 {
  doSomething() {
    myClass2();
  }

  //I want this method to return MyClass2 prototype
  public MyClass2 myClass2(){
  }
}

如何使用 @Lookup 注释来做到这一点?

【问题讨论】:

    标签: java spring dependency-injection


    【解决方案1】:

    在将@Lookup 注释应用到您的public MyClass2 myClass2() 方法之前,请阅读@Lookup's Javadoc

    容器将通过CGLIB生成方法的包含类的运行时子类,这就是为什么这样的查找方法只能在容器通过常规构造函数实例化的bean上工作(即查找方法不能在工厂返回的bean上被替换方法,我们不能为它们动态提供子类)。

    所以从ApplicationConfiguration中删除以下工厂方法样式的bean声明:

      @Bean
      public MyClass1 myClass1() {
        return new ContentHolderTabPaneController();
      }
    

    并添加@Component注解让Spring实例化bean(同时在方法中添加@Lookup注解):

    @Component
    public class MyClass1 {
      doSomething() {
        myClass2();
      }
    
      //I want this method to return MyClass2 prototype
      @Lookup
      public MyClass2 myClass2(){
        return null; // This implementation will be overridden by dynamically generated subclass
      }
    }
    

    现在让 myClass1 bean 脱离上下文,并且它的 myClass2 方法应该已经被替换/覆盖以每次都获得一个新的原型 bean。


    更新

    使用工厂方法声明

    实现@Lookup 注释方法(“查找方法”)并不难。没有@Lookup 并保持你的配置类不变,现在MyClass1 看起来像(事实上,如果使用@Lookup,Spring 会在子类中生成类似的实现):

    public class MyClass1 {
      doSomething() {
        myClass2();
      }
    
      //I want this method to return MyClass2 prototype
      @Autowired
      private ApplicationContext applicationContext;
      public MyClass2 myClass2() {
          return applicationContext.getBean(MyClass2.class);
      }
    }
    

    Spring 为您注入 ApplicationContext

    【讨论】:

    • 谢谢。有没有办法在工厂风格的 bean 声明中使用 MyClass1 Bean 作为依赖项?
    • 然后我们实现自己的查找方法——幸运的是它非常简单。请参阅我对答案的更新。
    • 但是这不是 DI 的失败目的吗,因为 Bean 实际上必须知道 DI 容器?
    • 是的,所以方法注入是prefereed。我没有看到将工厂方法 bean 声明与方法注入一起使用的简单方法。
    • 使用下一点:return applicationContext.getBean(MyClass2.class);它确实是糟糕的代码,因为您将基础架构组件注入到业务逻辑中
    【解决方案2】:

    如果您不在 Spring 4.1 上,则可以改用提供程序注入:

    public class MyClass1 {
      @Autowired
      private Provider<MyClass2> myClass2Provider;
    
      doSomething() {
        MyClass2 myClass2 = myClass2();
        myClass2.fooBar()
      }
    
      public MyClass2 myClass2(){
        return myClass2Provider.get();
      }
    }
    

    这是 DI,IoC,避免了查找方法的抽象类和 xml 定义。

    【讨论】:

    • javax.inject.Provider 准确地说
    • 这在我的单元测试中效果很好。我无法让@Lookup 工作
    • 是否有类似的方法允许为 bean 传递初始参数?
    【解决方案3】:

    另外,您可以使用 TARGET_CLASS proxyMode 声明 myClass2 bean。

      @Bean
      @Scope("prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
      public MyClass2 myClass2() {
        return new SidebarQuickMenuController();
      }
    

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 1970-01-01
      • 2017-06-24
      • 1970-01-01
      • 2011-01-31
      • 2014-02-20
      • 2019-09-20
      • 2021-12-20
      • 1970-01-01
      相关资源
      最近更新 更多