Java EE中如何在Servlet中注入需Session参数的RepositoryImpl实例?
最佳处理方案:使用CDI注入HttpSession到RepositoryImpl
1. 启用CDI支持
首先确保项目已开启CDI,在WEB-INF目录下创建beans.xml(CDI 1.1+支持隐式扫描,但显式配置更稳妥):
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" version="2.0" bean-discovery-mode="all"> </beans>
2. 让RepositoryImpl成为CDI托管Bean并注入HttpSession
直接在RepositoryImpl中通过@Inject注入HttpSession,CDI会自动关联当前请求的会话实例:
import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.servlet.http.HttpSession; import java.util.ArrayList; import java.util.List; @RequestScoped // 请求作用域匹配HttpSession的请求绑定特性,避免线程安全问题 public class RepositoryImpl implements Repository { @Inject private HttpSession session; private static final String DATA_STORAGE_KEY = "session_items"; @Override public void addItem(String item) { List<String> items = getData(); items.add(item); session.setAttribute(DATA_STORAGE_KEY, items); } @Override public List<String> getData() { @SuppressWarnings("unchecked") List<String> items = (List<String>) session.getAttribute(DATA_STORAGE_KEY); return items == null ? new ArrayList<>() : items; } }
3. 在Servlet中注入Repository接口
直接在Servlet中用@Inject注入Repository接口,CDI会自动注入RepositoryImpl的实例:
import javax.inject.Inject; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/add-item") public class AddItemServlet extends HttpServlet { @Inject private Repository repository; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String item = req.getParameter("item"); repository.addItem(item); resp.sendRedirect("/view-items"); } }
import javax.inject.Inject; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.List; @WebServlet("/view-items") public class ViewItemsServlet extends HttpServlet { @Inject private Repository repository; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); List<String> items = repository.getData(); out.println("<h1>Stored Items</h1>"); out.println("<ul>"); for (String item : items) { out.printf("<li>%s</li>", item); } out.println("</ul>"); } }
4. 为什么不推荐EJB?
EJB的设计偏向业务逻辑层,无状态EJB不适合绑定HttpSession,有状态EJB的会话机制和HttpSession完全独立,强行绑定会增加复杂度,且生命周期匹配度远不如CDI。CDI是Web层依赖注入的更优选择。
无CDI环境的替代方案
如果容器不支持CDI,可在Servlet中手动获取HttpSession并传递给RepositoryImpl,但这种方式会破坏接口封装性:
@WebServlet("/add-item") public class AddItemServlet extends HttpServlet { private Repository repository; @Override public void init() { repository = new RepositoryImpl(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String item = req.getParameter("item"); HttpSession session = req.getSession(); // 需要给RepositoryImpl添加setSession方法 ((RepositoryImpl) repository).setSession(session); repository.addItem(item); resp.sendRedirect("/view-items"); } }
内容的提问来源于stack exchange,提问作者ruskaof
相关产品推荐
相关产品推荐

