2014-04-03 146 views
2

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

我认为我需要通过iPOJO创建实例一些概念上的问题(@Instantiate或工厂)只有服务提供商,因为他们从来没有使用因为impl总是隐藏。但是,我有一些消费者可以实例化我自己(例如在main()方法中,我直接调用新的)。我让他们@组件,因为他们需要注入东西。我假设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传递给构造函数,然后我需要使用;但如果我使用新的,iPojo永远不会调用我的注入方法。另一方面,如果我使用iPOJOs实例化(比如添加@Instantiate),那么注入的确发生了,但是构造函数没有被调用,所以绑定会抛出一个NPE,因为列表还没有被创建,所以bar不会被设置。我知道我可以在绑定方法中创建列表,但我的问题更具概念性。

  1. 你应该如何完成这个(框架注入+参数传递给构造函数)?
  2. iPOJO如何在不调用创建对象的唯一构造函数的情况下调用addExternal(意味着该对象已创建)?这在标准java中是非常直观的
  3. 你是否应该在使用iPOJO组件时使用构造函数?

回答

3

iPojo的工作原理类似于其他的DI(依赖注入)的框架,如蓝图(OSGi的),春,吉斯等。也就是说,为了让DI做到这一点是你必须让容器作业(iPojo )管理您正在与之交互的对象的生命周期。所以,你的倾向是正确的:你必须使用iPojo的实例化技术之一。如果你选择在你的对象上使用新的代码,你的代码然后管理生命周期(因此你将手动需要“注入”所有参数)。

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

当iPojo bytecode manipulation踢,它操纵字节码,使其通过iPojo 管理,不通过iPojo管理。它通过在实例化对象时添加MyClass(InstanceManager)构造函数以及iPojo内部使用的其他内容来实现此目的。

因此,要回答你的问题:

  1. 您可以通过定义注入的变量或者属性或服务要求和委派iPojo创建他们做到这一点。 iPojo有multiple methods与实例创建进行交互,但您可能感兴趣的两个是通过OSGi ConfigurationAdmin或iPojo工厂(假设publicFactory在您的默认@Component上设置为true)。作为使用配置管理,并假设酒吧不生活在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”属性设置为你的“新Bar() “并保存该配置。该iPojo管理是创造了你,然后实例化一个版本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为您执行此操作。
+1

很好的答案!在过去的两天里,我学到了很多东西,并使其工作,但我没有使用构造函数注入或@Properties。我将纳入这一点。谢谢 – Hilikus