Servlets — concept walkthrough.
Today is intentionally light on code. We diagram the Servlet lifecycle, request dispatch, sessions, filters — so the moment Spring's DispatcherServlet shows up later, you recognize the shape it inherited.
Where we are in the story
Day 1 told you Servlets exist. Today we open the Servlet container's doors and see what's inside. By the end you'll be able to draw the lifecycle, the dispatch flow, and the role of filters from memory.
The Servlet lifecycle
A Servlet is a Java class that the container manages over time. It has three lifecycle phases:
init()— called once when the Servlet is first loaded (lazily on first request, or eagerly on startup if configured). Do one-time setup: open DB connections, read config, etc.service()— called for every request. Internally dispatches todoGet(),doPost(), etc. based on HTTP method. Many threads call this concurrently on the same instance.destroy()— called once when the container shuts down or unloads the Servlet. Clean up.
Because the container creates one Servlet instance and runs many threads through it, your Servlet's instance fields are shared across requests. A field like private User currentUser; is a bug — request A sets it, request B reads A's user. This is exactly the same trap as Spring's stateless beans. Servlets must be stateless. Local variables (per-method, per-thread) are fine. Instance fields holding per-request data are not.
What a Servlet looks like (read-only)
@WebServlet("/users")
public class UsersServlet extends HttpServlet {
private UserDao userDao;
@Override
public void init() {
this.userDao = new UserDao(); // shared, immutable, stateless
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
String idStr = req.getParameter("id");
User u = userDao.findById(Long.parseLong(idStr));
res.setContentType("application/json");
res.getWriter().write(toJson(u)); // you write Jackson manually
}
}Familiar? Your Spring controllers are descendants of this. @RestController + @GetMapping with @RequestParam + automatic JSON serialization is the same machinery, dressed nicer.
What the Servlet container does — recap
| Step | Container's job |
|---|---|
| 1 | Listen on port (8080 typically) |
| 2 | Accept incoming TCP connection |
| 3 | Read & parse raw HTTP bytes into HttpServletRequest |
| 4 | Match URL → which Servlet (URL pattern in web.xml or @WebServlet) |
| 5 | Pull a thread from the thread pool |
| 6 | Call servlet.service(req, res) |
| 7 | Take whatever the Servlet wrote into res and serialize as HTTP bytes back over TCP |
| 8 | Return thread to pool |
The container is doing a lot. The Servlet is doing one thing: compute the response.
Filters — interception around your Servlet
Sometimes you want behavior that runs around every request — authentication, logging, CORS, compression. Embedding that in every Servlet would be repetitive. The Servlet API solves this with Filters.
@WebFilter("/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest http = (HttpServletRequest) req;
String token = http.getHeader("Authorization");
if (!authService.isValid(token)) {
((HttpServletResponse) res).setStatus(401);
return; // short-circuit — never calls chain.doFilter()
}
chain.doFilter(req, res); // pass to next filter or the Servlet
}
}Spring Security is a chain of Servlet filters. OncePerRequestFilter, JwtAuthenticationFilter, CorsFilter — every one of them is a Servlet Filter. When you debug a Spring Security issue, you're debugging the same filter chain you saw on Day 1.
Sessions — making HTTP feel stateful
HTTP is stateless. But web apps need to know "this request is from the same user as the last one." The Servlet API offers HttpSession:
HttpSession session = req.getSession(true); // create if absent
session.setAttribute("userId", 42L);
// later request, same session cookie:
long userId = (Long) session.getAttribute("userId");How? The container generates a JSESSIONID cookie on first session access, sets it on the response, and uses it on subsequent requests to find the same in-memory session object.
Sessions store state on the server. If you scale horizontally to 5 instances, requests can hit different machines — the session is on machine 1 but the next request lands on machine 3. You must either pin requests (sticky sessions) or share session state via Redis. Either is operational pain.
JWT tokens (Day 8) avoid this entirely: state lives in the signed token. Any server with the key can verify. This is why modern REST APIs prefer tokens.
web.xml — the XML era
Old Servlet apps had a web.xml file mapping URL patterns to Servlets and Filters:
<!-- web.xml — historical -->
<servlet>
<servlet-name>UsersServlet</servlet-name>
<servlet-class>com.app.UsersServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UsersServlet</servlet-name>
<url-pattern>/users</url-pattern>
</servlet-mapping>Servlet 3.0 (2009) added annotations like @WebServlet, @WebFilter, @WebListener — which is what Spring eventually built on. You will not write web.xml. Recognize it in legacy code, then close the file.
The bridge to Spring
Here's the most important sentence of the day:
Spring MVC ships one Servlet called DispatcherServlet. Tomcat treats it as a normal Servlet — calls service() on it for every request. Inside service(), Spring runs its own routing: examine @RequestMapping annotations, pick a controller method, parse @RequestBody via Jackson, call your method, serialize the return value back to JSON, write to the response.
Every Spring controller you'll ever write runs inside a Servlet. The Servlet model didn't go away — Spring just built a sophisticated dispatcher on top of it. Now you know.
Lock in today's learning
Just understanding. No coding.
- What three lifecycle methods does a Servlet have, and how often is each called?
- Why must Servlets be stateless? What's the threading reason?
- Describe what a Filter does and how it can short-circuit a request.
- How do sessions make HTTP feel stateful, and why do modern APIs avoid them?
- What is
DispatcherServlet's relationship to Tomcat and to your@RestController? - Spring Security's filter chain — what underlying Servlet API construct is it built on?
End of Day 12. Tomorrow: REST architecture — what 'RESTful' actually means.