【问题标题】:How to do iPOJO instantiation如何进行 iPOJO 实例化
【发布时间】:2014-04-03 19:56:03
【问题描述】:

我在理解 iPOJO 中组件实例化的概念时遇到了一些问题。我读了this guide 我得到了类和对象的类比,但我仍然有一些具体的问题和一些概念上的问题,希望有人能澄清一下

我认为我需要通过 iPOJO(@Instantiate 或工厂)为服务提供商创建实例,因为他们从不使用 new,因为impl 总是隐藏的。但是,我有一些我自己实例化的消费者 @Component(比如在我直接在它们上调用 new 的 main() 方法中)。我制作它们 @Component 是因为它们需要注入东西。我假设 ipojo 字节码操作会做到这一点,以便在构造对象时注入它们的依赖项(我主要使用带有 @Bind 的方法注入),但似乎不是案子。有人可以向我澄清一下吗?现在在我看来,要让 iPOJO 进行任何注入,我需要始终使用其中一种 iPOJO 实例化技术。我遇到的问题是,我在消费者类中创建的构造函数没有被调用。

这是一个简化的例子来说明我的困惑

@Component(name="test")
public class MyFoo {
    private List<External> externals; //injected
    private Bar bar; //passed via constructor. Bar is *not* a @Component

    public MyFoo(Bar otherBar) {
        bar = otherBar;
        externals = new ArrayList();
    }

    @Bind(aggregate=true)
    public addExternal(External service) {
        externals.add(service);
    }
}

因此,正如这里可以看到的,我需要有接口External 的所有提供者,但我还需要一个Bar 对象,当我使用new MyFoo(someBar) 构造对象时传递它

我的问题是,如果我需要将 Bar 传递给构造函数,那么我需要使用 new;但是如果我使用 new,iPojo 永远不会调用我的注入方法。另一方面,如果我使用 iPOJO 实例化(比如我添加了@Instantiate),那么注入确实发生了,但没有调用构造函数,因此绑定会抛出 NPE,因为尚未创建列表 + 不会设置 bar。我知道我可以在 bind 方法中创建列表,但我的问题更具概念性。

  1. 您应该如何实现这一点(框架注入 + 构造函数中的参数传递)?
  2. iPOJO 如何在不调用我唯一的创建对象的构造函数的情况下调用 addExternal(这意味着对象已创建)?这在标准 java 中是非常违反直觉的
  3. 难道你只是在使用 iPOJO 组件时不应该使用构造函数吗?

【问题讨论】:

    标签: java dependency-injection osgi ipojo


    【解决方案1】:

    iPojo 的工作方式类似于其他 DI(依赖注入)框架,例如 Blueprint (OSGi)、Spring、Guice 等。也就是说,为了让 DI 完成它的工作,您必须让容器 (iPojo) 管理您正在与之交互的对象的生命周期。因此,您的倾向是正确的:您必须使用 iPojo 的一种实例化技术。如果您选择在对象上使用 new,您的代码 将管理生命周期(因此您将需要手动“注入”所有参数)。

    在示例中,您的构造函数没有被调用,因为开箱即用的 iPojo 将支持两种主要情况:默认构造函数 (MyFoo()) 或接受 BundleContext 的构造函数 (MyFoo(BundleContext c))。 iPojo 还支持构造函数服务和属性注入,如果您使用的是 1.7.0 或更高版本,则分别在构造函数变量(或元数据中的等效项)上使用 @Requires / @Property

    当 iPojo bytecode manipulation 启动时,它会操纵字节码以使其由 iPojo管理,而不是由 iPojo管理。它通过添加 MyClass(InstanceManager) 构造函数以及 iPojo 在实例化对象时在内部使用的其他内容来做到这一点。

    所以,回答你的问题:

    1. 您可以通过将注入变量定义为属性或服务要求并委托给 iPojo 来创建它们来完成此操作。 iPojo 有 multiple methods 用于与实例创建进行交互,但您可能感兴趣的两个是通过 OSGi ConfigurationAdmin 或 iPojo 工厂(假设 publicFactory 在您的 @Component 上设置为 true,这是默认设置)。作为使用配置管理员的示例并假设 Bar 不在 OSGi 服务注册表中,您的 MyFoo 类将如下所示:

      @Component(name="test")
      public class MyFoo {
          private List<External> externals; //injected
          private Bar bar; //passed via constructor. Bar is *not* a @Component
      
          public MyFoo(@Property(name = "somebar") Bar otherBar) {
              bar = otherBar;
              externals = new ArrayList();
          }
      
          @Bind(aggregate=true)
          public addExternal(External service) {
              externals.add(service);
          }
      }
      

      然后,您将使用配置管理员(或 iPojo 工厂)来创建实例。因此,您的主要方法将从 OSGi 服务层拉入 ConfigAdmin 或 iPojo 工厂(例如,通过将其从 BundleContext 拉出等),创建一个将“somebar”属性设置为“new Bar() " 并保存该配置。然后,为您创建的 iPojo 托管服务工厂将使用您在配置中提供的新 Bar 实例化一个 MyFoo 版本,并将其注入 MyFoo 构造函数:

      ...
      Configuration config = configAdmin.createFactoryConfiguration(
          MyFoo.class.getCanonicalName());
      Hashtable<String, String> properties = new Hashtable<>();
      properties.put("somebar", new Bar()); // This is where you new
      config.update(properties);
      // do something useful with the config if you need to update 
      // the instance or destroy it later.
      ...
      

      配置管理员createFactoryConfiguration 的第一个参数指定pid。在这种情况下,pid 是类的名称,这是 iPojo 默认使用的名称,除非您在 @Component 注释中覆盖它。然后将您的 somebar 添加到属性并更新配置。 iPojo 工厂与此类似,尽管我相信它使用构建器模式来创建实例。如果您不想添加对 OSGi 配置管理员的依赖项,则最好使用 iPojo 工厂。

    2. 我不是 iPojo 内部结构方面的专家,我在这里根据我的经历和我在他们的文档中阅读的内容得出一个结论。如前所述,iPojo 进行字节码操作以增强您的类,使其可由 iPojo 管理。它为您的类添加的一个特征是带有InstanceManager 的构造函数。由于您添加的构造函数没有绑定到它的元数据(即注释 - 我假设清单或 xml 文件中没有手动元数据)它或多或少完全忽略该构造函数,而是选择使用一个由字节码操作过程动态生成。完成后,它最终会调用您的 @Bind 方法来添加外部服务(因为该方法已标记),您会发现自己处于您描述的状态。
    3. 这里的关键是让 iPojo 管理对象的生命周期,如上所述。通过调用构造函数,您实际上是在管理该实例的生命周期,因此 iPojo 脱离了循环。因此,您可以使用构造函数并将参数手动“注入”到其中,也可以依靠 iPojo 为您完成。

    【讨论】:

    • 很好的答案!在过去的两天里,我学到了很多东西,并且成功了,但我没有使用构造函数注入或@Properties。我会合并的。谢谢
    猜你喜欢
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多