You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:15:40