2012-05-23 20 views
14

是否可以使用CDI将参数注入方法调用?预期的行为与野外注射相似。查找首选生产商并使用该产品。如何使用CDI进行方法参数注入?

我想这样做是这样的:

public void foo(@Inject Bar bar){ 
    //do stuff 
} 

或本(与减少混乱的语法时才):

public void foo(){ 
    @Inject 
    Bar bar; 
    //do stuff 
} 

这句法是在两种情况下是非法的。有其他选择吗?如果不是 - 如果可能的话,这是否是一个坏主意?

谢谢

编辑 - 我可能已经做了我的要求不够明确的 - 我想能够直接调用该方法,使bar变量容器的初始化。 JörnHorstmann和Perception的答案表明这是不可能的。

回答

16

注入点是在bean被容器实例化时处理的,它限制了方法级别注入的用例数量。该规范的当前版本识别以下类型方法注射的:

初始化方法注射

public class MyBean { 
    private Processor processor; 

    @Inject 
    public void setProcessor(final Processor processor) { 
     this.processor = processor; 
    } 
} 

MyBean一个实例被注入,处理器例如也将被注入,经由它的设置方法。

事件观察方法

public class MyEventHandler { 
    public void processSomeEvent(@Observes final SomeEvent event) { 
    } 
} 

事件实例被直接注入事件处理方法(虽然不与@Inject注解)

制作方法

public class ProcessorFactory { 
    @Produces public Processor getProcessor(@Inject final Gateway gateway) { 
     // ... 
    } 
} 

生产者方法的参数自动获取注入编辑。

+0

谢谢,感知。第一句话足以毁掉我的梦想:)“当它被实例化时”。我想到的应该是一个制作人的方法,而不是一个。我想我的用例不是专家组的意图。 – kostja

+0

是的,不幸的是,该规范没有要求方法调用成为bean生命周期管理的一部分。因此,直接调用方法将* not *调用注入(类似于直接在对象上调用'new')。我不会感到惊讶,尽管如果方法注入成为下一个版本的规范。 – Perception

5

CDI的这一特性被称为“初始化方法”。语法与您的代码不同,因为整个方法用@Inject注解,方法参数可以进一步由限定符注释来选择特定的bean。 JSR 299的3.9节显示了以下示例,如果只有一个bean实现,则@Selected是可以省略的限定符。

@Inject 
void setProduct(@Selected Product product) { 
    this.product = product; 
} 

请注意,

的应用可以直接调用初始化方法,但随后没有参数将被传递到由容器的方法。

+0

谢谢,乔恩,我阅读该规范的一部分了。在你的笔记中的情况是确切的,我想要做的 - 直接调用方法,并让容器提供一个bean实例。 CDI有没有另一种可能性呢? – kostja

1

您可以使用BeanManager API在你的方法来获取上下文的引用,或根据您的最终目标,你可以注入的

Instance<Bar> 

方法外部的,并且该方法使用它。

+0

谢谢,包围。很高兴知道它可以完成,尽管“手动”。我想大多数情况下不需要为明确的lokup添加WTF潜力,但我会记住这种可能性。 – kostja

7

如果你真正想要的不是方法的参数(应该由调用者提供),而是每次调用该方法时正确初始化CDI bean的实例,并且完全构造和注入,然后检查

javax.inject.Provider<T>

基本上,第一提供者注入到类

@Inject Provider<YourBean> yourBeanProvider; 

然后,在该方法中,获取一个新的实例

YourBean bean = yourBeanProvider.get(); 

希望这有助于:)

+1

很酷,谢谢。这个bean不一定是一个方法参数。我只需要为每个方法调用正确初始化的bean实例,而不需要调用方提供它。所以你的答案指甲:) – kostja

4

这个问题上来时,我本来对这个话题进行搜索,并因为我已经了解到,随着CDI 1.1发布(包含在JavaEE的规范7)现在有一种方法可以部分实现OP的目标。你仍然不能做

public void foo(@Inject Bar bar){ 
    //do stuff 
} 

,但你可以“注入”一个局部变量,虽然你不使用@Inject而是编程查找注入的情况是这样的:

public void foo() { 
    Instance<Bar> instance = CDI.current().select(Bar.class); 
    Bar bar = instance.get(); 
    CDI.current().destroy(instance); 
    // do stuff with bar here 
} 

注意,select()方法可以选择使用您可能需要提供的任何限定符注释。尽管获得java.lang.annotation.Annotation的实例,祝你好运。遍历你的Instance<Bar>找到你想要的可能更容易。

我已经告诉你需要摧毁的Instance<Bar>如我上面做的,可以从经验验证上面的代码工作;但是,我也不敢保证你需要摧毁它。

+0

这工作正常,但可能在单元测试中造成问题。 –