English 中文(简体)
方法参数注入如何使用 CDI?
原标题:How to use CDI for method parameter injection?

能否利用CDI将参数注入方法调用?预期的行为与实地注射相似。对首选生产者进行检查,并使用产品。

我想做的是:

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

或这样(用较少混淆的语句):

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

这种语法在两种情况下都是违法的。 是否有其他选择? 如果不是,如果可能的话,出于某种原因,这会不会是一个坏主意?

谢谢

EDIT -- -- 我可能使我的要求不够明确 -- -- 我希望能够直接调用该方法,将 bar 变量的初始化留给容器。 Jörn Horstmanns和Pervitions的回答表明,这是不可能的。

最佳回答

罐体即时对豆类进行喷射点处理,从而限制方法水平喷射的使用案例数量。

初始化方法注入

public class MyBean {
    private Processor processor;

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

当输入 MyBean 实例时,处理器实例也将通过设置器方法被注入。

Event 观察方法

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

事件被直接注入事件处理方法( 虽然不是用 @ Inject an notation) 。

生产方法

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

生产者方法的参数自动注射。

问题回答

如果您真正想要的不是方法的参数(应该由打电话者提供),而是在方法每次被调用、完全构建和注入时适当初始化的CDI豆类实例,然后检查

javax.inject. provider<T>

基本上,首先先给该类的提供者注射

@Inject Provider<YourBean> yourBeanProvider;

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

YourBean bean = yourBeanProvider.get();

希望这能帮助:)

当我最初对这个议题进行搜索时,我发现这个问题就出现了。 从那时起,我了解到,随着CDI 1.1.1(载于JavaEE 7图7图中)的公布,现在有了一种办法,可以真正部分地完成OP想要完成的任务。

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

但您可以“ 输入” 本地变量, 尽管您不使用 < code_ ject , 而是在程序上查看被注入的实例 :

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. annotation 实例。 也许更容易通过您的 Instance<Bar> 找到您想要的。

我被告知,你需要像我以前所做的那样销毁 Instance<Bar> , 并且能够从经验中证实上述代码有效;然而,我无法发誓你需要 来销毁它。

CDI 的特性被称为“ 初始化方法 ” 。 语法与您的代码不同, 因为整个方法以 < code_ ject 附加说明, 方法参数还可以由修饰符附加说明, 以选择特定的豆。 < a href=" 第3. 9 节 http://www.jcp.org/en/jsr/ detail?id=299" rel=“ noreferr" > JSR 299 显示以下例子, 并且 < code\\\ Sectrect 是一个限定符, 如果只有一个执行的话, 可以省略。

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

请注意

该应用可直接调用初始化器方法,但集装箱不会将任何参数传递给该方法。

您可以在方法中使用 BeanManager API 来获取上下文引用, 或取决于您最终的目标, 您可以输入

Instance<Bar>

在方法外,然后在方法中使用该方法。

如果您的目标是通过反射调用该方法, 可以为每个参数创建 < code> Injectionpoint 。

这里举一个使用 CDI-SE 的例子:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;

public class ParameterInjectionExample {

    public static class Foo {

        // this method will be called by reflection, all parameters will be resolved from the BeanManager
        // calling this method will require 2 different Bar instances (which will be destroyed at the end of the invocation)
        public void doSomething(Bar bar, Baz baz, Bar bar2) {
            System.out.println("got " + bar);
            System.out.println("got " + baz);
            System.out.println("got " + bar2);
        }
    }

    @Dependent
    public static class Bar {

        @PostConstruct
        public void postConstruct() {
            System.out.println("created " + this);
        }

        @PreDestroy
        public void preDestroy() {
            System.out.println("destroyed " + this);
        }
    }

    @ApplicationScoped
    public static class Baz {

        @PostConstruct
        public void postConstruct() {
            System.out.println("created " + this);
        }

        @PreDestroy
        public void preDestroy() {
            System.out.println("destroyed " + this);
        }
    }

    public static Object call(Object target, String methodName, BeanManager beanManager) throws Exception {
        AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(target.getClass());
        AnnotatedMethod<?> annotatedMethod = annotatedType.getMethods().stream()
                .filter(m -> m.getJavaMember().getName().equals(methodName))
                .findFirst() // we assume their is only one method with that name (no overloading)
                .orElseThrow(NoSuchMethodException::new);
        // this creationalContext will be valid for the duration of the method call (to prevent memory leaks for @Dependent beans)
        CreationalContext<?> creationalContext = beanManager.createCreationalContext(null);
        try {
            Object[] args = annotatedMethod.getParameters().stream()
                    .map(beanManager::createInjectionPoint)
                    .map(ip -> beanManager.getInjectableReference(ip, creationalContext))
                    .toArray();
            return annotatedMethod.getJavaMember().invoke(target, args);
        } finally {
            creationalContext.release();
        }
    }

    public static void main(String[] args) throws Exception {
        try (SeContainer container = SeContainerInitializer.newInstance().disableDiscovery().addBeanClasses(Bar.class, Baz.class).initialize()) {
            System.out.println("beanManager initialized");
            call(new Foo(), "doSomething", container.getBeanManager());
            System.out.println("closing beanManager");
        }
    }
}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...