我的学习项目有问题。我有一个带有一个 servlet 的简单项目,我需要一些具有不同范围的 CDI bean。这部分非常简单,但我必须能够将 HttpSession 注入到我的每个 CDI bean 中。为了解决这个问题,我创建了 ServletRequestListener 来获取 HttpServletRequest 对象,我将此对象存储在 ThreadLocal 对象中的应用程序范围的 bean 中,并且在此 bean 中,我有来自存储的 HttpServletRequest 的 HttpSession 对象的生产者方法。之后,我可以在任何 CDI bean 中注入 HttpSession,除了会话范围的 bean。在会话初始化之后,会话被正确注入到该 bean,但是对于同一会话中的第二个请求,我有空指针异常,因为会话 bean 在 RequestInitialized 方法之前创建(或反序列化)并且我的生产者返回空值,
这是一个会话中第二个请求的堆栈跟踪:
org.jboss.weld.exceptions.IllegalProductException: WELD-000052 Cannot return null from a non-dependent producer method: [method] @Produces @RequestScoped public pl.lab2.cdi.producers.SessionObjectsProducer.getSession()
org.jboss.weld.bean.AbstractProducerBean.checkReturnValue(AbstractProducerBean.java:217)
org.jboss.weld.bean.AbstractProducerBean.create(AbstractProducerBean.java:300)
org.jboss.weld.context.AbstractContext.get(AbstractContext.java:107)
org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:90)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:104)
org.jboss.weld.proxies.HttpSession$776413422$Proxy$_$$_WeldClientProxy.getId(HttpSession$776413422$Proxy$_$$_WeldClientProxy.java)
pl.lab2.bean.SessionBean.toString(SessionBean.java:31)
java.lang.String.valueOf(String.java:2854)
java.lang.StringBuilder.append(StringBuilder.java:128)
org.jboss.weld.context.SerializableContextualInstanceImpl.toString(SerializableContextualInstanceImpl.java:60)
java.lang.String.valueOf(String.java:2854)
java.lang.StringBuilder.append(StringBuilder.java:128)
org.jboss.weld.context.beanstore.AttributeBeanStore.attach(AttributeBeanStore.java:109)
org.jboss.weld.context.AbstractBoundContext.activate(AbstractBoundContext.java:66)
org.jboss.weld.servlet.WeldListener.requestInitialized(WeldListener.java:141)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
java.lang.Thread.run(Thread.java:724)
和来源:
听众
package pl.lab2.servlet;
import org.apache.log4j.Logger;
import pl.lab2.cdi.BeanManagerHelper;
import pl.lab2.servlet.events.literal.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
public class ServletListener implements ServletRequestListener {
private static final Logger log = Logger.getLogger(ServletListener.class);
@Override
public void requestDestroyed(ServletRequestEvent sre) {
log.info("request destroyed event");
BeanManagerHelper.getBeanManagerByJNDI().fireEvent((HttpServletRequest) sre.getServletRequest(), DestroyedLiteral.INSTANCE);
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
log.info("request initialized event");
BeanManagerHelper.getBeanManagerByJNDI().fireEvent((HttpServletRequest) sre.getServletRequest(), InitializedLiteral.INSTANCE);
}
}
持有者
package pl.lab2.servlet;
import org.apache.log4j.Logger;
import pl.lab2.servlet.events.Destroyed;
import pl.lab2.servlet.events.Initialized;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ApplicationScoped
public class ServletObjectHolder {
private static final Logger log = Logger.getLogger(ServletObjectHolder.class);
private final ThreadLocal<HttpServletRequest> threadRequest = new ThreadLocal<HttpServletRequest>();
public HttpSession getSession() {
log.info("get session");
if (threadRequest.get() != null) {
return threadRequest.get().getSession();
}
return null;
}
public void servletRequestInitialized(@Observes @Initialized final HttpServletRequest request) {
log.info("receive request initialization");
threadRequest.set(request);
}
public void servletRequestDestroyed(@Observes @Destroyed final HttpServletRequest request) {
log.info("receive request destroyed");
threadRequest.set(null);
}
}
制片人
package pl.lab2.cdi.producers;
import org.apache.log4j.Logger;
import pl.lab2.servlet.ServletObjectHolder;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import java.io.Serializable;
public class SessionObjectsProducer implements Serializable {
private static final Logger log = Logger.getLogger(SessionObjectsProducer.class);
@Inject
private ServletObjectHolder servletObjectHolder;
@Produces
@RequestScoped
public HttpSession getSession() {
log.info("get session");
return servletObjectHolder.getSession();
}
}
会话 bean
package pl.lab2.bean;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
import java.io.Serializable;
@SessionScoped
@Named
public class SessionBean implements Serializable {
private String name;
@Inject
private HttpSession session;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "SessionBean{" +
"name='" + name + "', " +
"sessionId='" + session.getId() + "'" +
'}';
}
}
和小服务程序:
package pl.lab2.servlet;
import org.apache.log4j.Logger;
import org.jboss.weld.context.ConversationContext;
import org.jboss.weld.context.http.Http;
import pl.lab2.bean.ApplicationBean;
import pl.lab2.bean.ConversationBean;
import pl.lab2.bean.RequestBean;
import pl.lab2.bean.SessionBean;
import pl.lab2.cdi.producers.SessionObjectsProducer;
import javax.enterprise.context.Conversation;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ServletDispatcher extends HttpServlet {
private static final Logger log = Logger.getLogger(ServletDispatcher.class);
@Inject
private ApplicationBean applicationBean;
@Inject
private SessionBean sessionBean;
@Inject
private ConversationBean conversationBean;
@Inject
private RequestBean requestBean;
@Inject
private Conversation conversation;
@Inject
@Http
private ConversationContext conversationContext;
@Inject
private SessionObjectsProducer sessionObjectsProducer;
@Override
public void init() throws ServletException {
super.init();
conversationContext.setParameterName("cId");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
this.request(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
this.request(request, response);
}
private void request(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("request started in session " + request.getSession().getId());
String cid = request.getParameter(conversationContext.getParameterName());
if (cid != null) {
conversationContext.activate(cid);
} else {
conversationContext.activate();
}
takeActions(request);
updateData(request);
printState(response.getWriter(), request);
}
private void printState(PrintWriter writer, HttpServletRequest request) {
writer.print("<div>");
writer.print("<div>Beans:</div>");
writer.print(applicationBean.toString() + "<br />");
writer.print(sessionBean.toString() + "<br />");
writer.print(conversationBean.toString() + "<br />");
writer.print(requestBean.toString() + "<br />");
writer.print("</div>");
writer.print("<div>");
writer.print("<div>Data:</div>");
writer.print("session id: " + request.getSession().getId() + "<br />");
writer.print("conversation id: " + conversation.getId() + "<br />");
writer.print("</div>");
}
private void takeActions(HttpServletRequest request) {
if ("begin".equals(request.getParameter("conversationState"))) conversation.begin();
else if ("end".equals(request.getParameter("conversationState"))) conversation.end();
}
private void updateData(HttpServletRequest request) {
if (request.getParameter("application") != null) {
applicationBean.setName(request.getParameter("application"));
}
if (request.getParameter("session") != null) {
sessionBean.setName(request.getParameter("session"));
}
if (request.getParameter("conversation") != null) {
conversationBean.setName(request.getParameter("conversation"));
}
if (request.getParameter("request") != null) {
requestBean.setName(request.getParameter("request"));
}
}
}
为此,我使用来自 github 的 seam/servlet 源代码作为示例。
我已将我当前的代码上传到刚刚构建的Dropbox,在 JBoss 上部署为 7.1.1.Final,转到 localhost:8080/lab2,按两次 F5,您会看到问题。