"Unsatisfied dependencies" 尝试将 EJB 注入另一个组件时出现 UnsatisfiedResolutionException

"Unsatisfied dependencies" with UnsatisfiedResolutionException when trying to inject EJB into another component

我正在尝试实现 Java EE 的托管执行器 ManagedExecutorService 以提交可调用任务,其中每个任务都会调用注入的 bean 方法。

我正在使用 Instance class 让容器知道任务对象,但是当执行 get() 时抛出以下异常:

Caused by: javax.ejb.EJBException: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type MyTask with qualifiers @Default

我在 WildFly 14 上运行。

注入的bean:

@Stateless
public class MyBean {

    public void print() {
        System.out.println("MyBean printed");
    }
}

任务:

@Stateless
public class MyTask implements Callable<String> {

    @Inject
    MyBean myBean;

    @Override
    public String call() throws Exception {

        System.out.println("MyTask called");
        myBean.print();
        return "Task called";

    }
}

任务调用者:

@Stateless
public class TestBean {

    @Inject
    Instance<MyTask> myTaskInstance;

    @Resource
    private ManagedExecutorService executor;

    public void test() throws InterruptedException, ExecutionException {

        List<Callable<String>> tasks = new ArrayList<>(); 
        MyTask task = myTaskInstance.get();  // <------- Exception is thrown here
        tasks.add(task);
        MyTask task2 = myTaskInstance.get();
        tasks.add(task2);

        List<Future<String>> taskResults = null;
        taskResults = executor.invokeAll(tasks);

        List<String> results = new ArrayList<>(); 

        for(Future<String> taskResult : taskResults) {
                results.add(taskResult.get());
        }

    }
}

为什么会抛出异常,如何解决这个问题? class路径中是否缺少库?

问题是 MyTask 作为实现 Callable 的 EJB,您已经删除了 MyTask class本身来自这个bean的"bean type",也就是说不能注入@Inject MyTask xxx "client",按照CDI 2.0 spec里面的规则]:

18.2.2. Bean types of a session bean

The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their superinterfaces. If the session bean has a no-interface view, the unrestricted set of bean types contains the bean class and all superclasses. In addition, java.lang.Object is a bean type of every session bean.

这就是为什么 Weld 找不到有效的 MyTask bean 来满足对 TestBean 客户端的注入。

您可以通过添加 @LocalBean 注释为 MyTask EJB 提供无接口视图,例如:

@Stateless
@LocalBean
public class MyTask implements Callable<String> {

或者,您可以删除 implements Callable 并重构为:

public class MyTask {

    @Inject
    MyBean myBean;

    MyCallable callable = new MyCallable();

    public Callable getCallable() {
        return callable;
    }

    private class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {

            System.out.println("MyTask called");
            myBean.print();
            return "Task called";
        }
    }
}    

public class TestBean {

    // ...

    MyTask task = myTaskInstance.get(); 
    tasks.add(task.getCallable())

    // ...
}

有关更多讨论,请参阅 here for a quick reference on the no-interface view, as well as this post。