我尝试使用Jersey 2.1,并CDI在我的Java EE 7项目,该项目被部署在Glassfish 4.0.
Jersey模块依赖于Guava库.但是使用带有CDI的Guava库(14.0.1)会导致抛出以下异常.
CDI deployment failure:WELD-001408 Unsatisfied dependencies for type [Set<Service>] with qualifiers [@Default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject com.google.common.util.concurrent.ServiceManager(Set<Service>)].
Run Code Online (Sandbox Code Playgroud)
我怎样才能克服这个问题?
我正在阅读Oracle Java EE 6 教程和“Beans as Injectable Objects”部分下,它说
可以注入以下类型的对象:
(几乎)任何 Java 类
会话豆......
无法注入的 Java 类的示例是什么?这只是他们提到的一些理论上的技术限制,还是可以注入的类有已知的限制?
我可以将自己的POJO注入到这样的托管对象中:
import javax.ejb.Stateless;
import javax.inject.Inject;
@Stateless
public class SomeEjb {
@Inject
private SomePojo somePojo;
}
Run Code Online (Sandbox Code Playgroud)
我有这个POJO:
// No annotations
public class SomePojo {
}
Run Code Online (Sandbox Code Playgroud)
这很好用.如果我将EJB注入JSF支持bean,我可以看到值somePojo是非空值,如预期的那样.
但是,如果我尝试注入java.util.Date到SomeEjb,我得到部署以下异常:
Severe: Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [Date] with qualifiers [@Default] at injection point [[field] @Inject private SomeEjb.date]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Date] with qualifiers [@Default] at injection point [[field] @Inject private SomeEjb.date]
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:311)
Run Code Online (Sandbox Code Playgroud)
SomeEjb现在:
// No annotations
public class …Run Code Online (Sandbox Code Playgroud) 我有一个会话范围的 bean ComponenteM,它被注入到请求范围的 bean ComponenteC 中。
@Named
@RequestScoped
public class ComponenteC implements Serializable {
@Inject
ComponenteM componenteM;
}
Run Code Online (Sandbox Code Playgroud)
ComponenteC 有一个由 HtmlCommandLink(以编程方式创建)调用的导出方法。导出方法调用与 SAP BO 网络服务集成的网络服务,以便将报表导出到 excel。但是,只有当调用时间过长时,我才会收到 BusyConversationException。任何其他少于 10 分钟的导出都是成功的。
同时我在对话中没有其他电话(AJAX 或非 AJAX 调用)。我已经尝试在开始对话时为对话 bean 设置显式超时,但我读到它仅用作对 CDI 容器的建议,并且可能会被忽略:
public void beginConversation() {
if (conversation.isTransient()) {
conversation.setTimeout(60 * 60 * 1000);
conversation.begin();
}
}
Run Code Online (Sandbox Code Playgroud)
错误是:
ServletException.org.jboss.weld.context.BusyConversationException 的根本原因:WELD-000322 对话锁定超时:1
我还尝试通过线程发出导出请求,然后将导出的文档返回到对话中。我的想法是让一个线程忙于处理文档和 componenteC 的导出,在等待线程完成时,偶尔会检查执行 componenteM.beginConversation();
我试图理解为什么即使没有并发请求也会抛出 BusyConversationException。
谢谢你。
Java EE 7 应用程序在 Wildfly 9.0.2.Final 上运行。从@Asynchronous 方法中访问请求范围的数据存在问题。
在 Web 过滤器中,数据(例如令牌)被设置到 RequestScoped CDI bean 中。稍后我们要访问这些数据。如果我们在一个线程中工作,则一切正常。但是如果需要异步运行代码,就会出现问题。CDI 注入空 bean,请求数据丢失。
这是示例:
@RequestScoped
public class CurrentUserService implements Serializable {
public String token;
}
@Stateless
public class Service {
@Inject
private RestClient client;
@Resource
private ManagedExecutorService executorService;
@Resource
private ContextService contextService;
@Asynchronous
private <T> Future<T> getFuture(Supplier<T> supplier) {
Callable<T> task = supplier::get;
Callable<T> callable = contextService.createContextualProxy(task, Callable.class);
return executorService.submit(callable);
}
public String getToken() throws Exception {
return getFuture(client::getToken).get();
}
}
@ApplicationScoped
public class RestClient { …Run Code Online (Sandbox Code Playgroud) 我想从producer方法获取bean以读取其属性.在某些情况下,bean是一个EJB Singletonbean.
我简化了我的代码以专注于这个问题.
我的简单限定符:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface InjectMe {}
Run Code Online (Sandbox Code Playgroud)
简单生产者:
@Dependent
public class SimpleProducer {
@Produces
@InjectMe
public String getInjectMe(InjectionPoint ip) {
// ip.getBean() returns null for some reason
return "ip=" + ip + ", bean=" + ip.getBean();
}
}
Run Code Online (Sandbox Code Playgroud)
EJB(Singleton):
@Singleton
@Startup
public class SimpleSingleton {
@Inject
@InjectMe
private String injectMe;
@PostConstruct
public void init() {
System.out.println(injectMe);
}
Run Code Online (Sandbox Code Playgroud)
}
控制台输出:
信息:ip = [BackedAnnotatedField] @Inject @InjectMe private com.test.ejb.SimpleSingleton.injectMe,
bean=null
当我将Singletonbean 更改为 …
我有一个JAX-RS资源类,它使用@Context ResourceContext为子资源类提供路径路由,为每种资源类型创建子资源实例.在此示例中,我将实例化报告子资源.
资源
@Context
ResourceContext rc;
@Path("reports")
public ReportsResource reportsResource() {
return rc.initResource(new ReportsResource());
}
Run Code Online (Sandbox Code Playgroud)
子资源需要一个ReportService类的实例(使用@Stateless注释定义),自然的解决方案是@Inject it ...
报告SubResource
@Inject
ReportsService rs;
@GET
@Path("{rptno}")
@Produces(MediaType.APPLICATION_XML)
public Report report(@PathParam("rptno") int rptNumber) throws Exception {
return rs.getReport(rptNumber);
}
Run Code Online (Sandbox Code Playgroud)
我将Glass EE7与Glassfish和WAS Liberty Profile一起使用的经验是,不会注入ReportService rs的实例,而是将rs保留为null并导致NPE.
我的假设是因为资源类正在执行"新的ReportsResource()",所以CDI无法查看ReportsResource实例,因此ReportsResource不是容器管理的.这似乎是与通过ResourceContext获取子资源时将EJB注入JAX-RS 2.0子资源的问题相同的情况
我的解决方案有所不同,我在Resource类中选择@Inject ReportService,然后在ReportsResource构造函数上传递实例.
修改资源
@Inject
ReportsSerivce rs;
@Context
ResourceContext rc;
@Path("reports")
public ReportsResource reportsResource() {
return rc.initResource(new ReportsResource(rs));
}
Run Code Online (Sandbox Code Playgroud)
修改报告子资源
public class ReportsResource {
private ReportsSerivce rs;
public ReportsResource(ReportsSerivce rs) {
this.rs = rs;
}
@Context …Run Code Online (Sandbox Code Playgroud) 我有一个带@Produces注释的方法可以创建一个Apple.
当我@ApplicationScoped像这样使用它
public class AppleProducer {
@ApplicationScoped
@Produces
public Apple createApple() {
return new Apple();
}
}
Run Code Online (Sandbox Code Playgroud)
然后Apple只为整个应用程序创建一次.
当我@RequestScoped像这样使用它
public class AppleProducer {
@RequestScoped
@Produces
public Apple createApple() {
return new Apple();
}
}
Run Code Online (Sandbox Code Playgroud)
然后它会为每个请求创建.
但是,如果我没有指定范围怎么办?
public class AppleProducer {
@Produces
public Apple createApple() {
return new Apple();
}
}
Run Code Online (Sandbox Code Playgroud)
Apple会多久创建一次?我怀疑每次访问,是否正确?有关于此的文件吗?
我试图在扩展中可观察到的 CDI 容器引发的事件的上下文中了解 @Initialized() 事件的生命周期/流程。
- 发现Bean之前
- ProcessAnnotatedType 和 ProcessSyntheticAnnotatedType
- 类型发现后
- ProcessInjectionTarget 和 ProcessProducer
- 进程注入点
- ProcessBean 属性
- ProcessBean、ProcessManagedBean、ProcessSessionBean、ProcessProducerMethod 和 ProcessProducerField
- 进程观察者方法
- 豆子发现之后
- 部署后验证
- 关机前
我无法找到的是在此容器生命周期中将@Initialized触发事件的位置。我怀疑它是 AfterDeploymentValidation 完成的,但我找不到任何文档来支持这一事实。此外,我似乎无法在CDI 1.1 规范中找到任何指示何时/何处抛出 @Initalized 事件的内容。
例如,事件是在@PostConstruct发现的bean的所有方法执行之前还是之后抛出?该事件是在 EJB@Startup初始化之前还是之后引发的?是否有任何文档清楚地列出了 CDI 中这些事件的顺序/顺序?
在用户登录时更新 HTTP 会话是一种常见的最佳实践。这将强制使用新的会话 ID,避免会话固定漏洞。
当涉及@SessionScoped bean 时,是否有使用 CDI 实现此功能的首选模式?困难在于,通过使当前的 HTTP 会话无效,您将在下一个请求中获得一个不同的会话范围的 bean,但直到下一个请求才会如此。
例如,假设一个会话 bean 用于存储用户登录信息:
@Named("sessionbean")
@SessionScoped
public class SessionBean implements Serializable {
private int userId;
private String username;
private List<String> privileges;
// Accessors omitted
}
Run Code Online (Sandbox Code Playgroud)
另一个用于管理登录的 bean:
@Named("loginbean")
@ViewScoped
public class LoginBean implements Serializable {
private String username;
private String password;
@Inject private SessionBean session;
@Inject private SessionManager sessionManager;
@Inject private PrivilegeManager privilegeManager;
public String doLogin() {
String destinationUrl;
if (validate(username, password)) {
FacesContext context = FacesContext.getCurrentInstance();
// force …Run Code Online (Sandbox Code Playgroud)