Interview Java ‐ J2EE - Yash-777/MyWorld GitHub Wiki
Servlet Container → Spring Container
Servlet Containerpackage javax.servlet;
|
Spring Containerpackage org.springframework.web.servlet;
|
|---|---|
/* A servlet is a small Java program that runs within a Web server. Servlets
* receive and respond to requests from Web clients, usually across HTTP, the
* HyperText Transfer Protocol.
*
* This interface defines methods to initialize a servlet, to service requests,
* and to remove a servlet from the server. These are known as life-cycle */
public interface Servlet {
/* Called by the servlet container to indicate to a servlet that the servlet
* is being placed into service. */
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
/* Called by the servlet container to allow the servlet to respond to a request. */
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
/**
* A servlet configuration object used by a servlet container to pass
* information to a servlet during initialization.
*/
public interface ServletConfig {
public String getServletName();
public ServletContext getServletContext();
public String getInitParameter(String name);
public Enumeration getInitParameterNames();
}
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable { }
package javax.servlet.http;
public abstract class HttpServlet extends GenericServlet {
// Called by the server (via the service method) toallow a servlet to handle a GET request.
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
//...
}
|
@SuppressWarnings("serial")
public abstract class HttpServletBean
extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
}
@SuppressWarnings("serial")
public abstract class FrameworkServlet
extends HttpServletBean implements ApplicationContextAware { }
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet { }
|
Filters are part of the Servlet container. They intercept the request before it reaches the Controller and the response before it goes back to the client.
Request Flow: Servlet Container → Spring Container |
Filter Chainpackage org.springframework.web.servlet;
|
|---|---|
HTTP Request: GET /api/test
│
▼
┌─────────────────────── SERVLET CONTAINER ─────────────────────────────────────────┐
| ┌────────────────────────────────────┐ |
| │ Servlet Container (Tomcat) │ |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ Filter Chain Starts │ |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ CorsFilter.doFilter() │ ← Can modify request/response |
| │ - Set CORS headers │ ← Can block request |
| │ - chain.doFilter() │ ← Can log |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ ┌────────────────────────────────────┐ |
| │ AuthenticationFilter.doFilter() │ │ LoggingFilter.doFilter() │ |
| │ - Validate JWT token │ │ - Log request details │ |
| │ - Set SecurityContext │ │ - chain.doFilter() │ |
| │ - chain.doFilter() │ └────────────────────────────────────┘ |
| └────────────────────────────────────┘ |
| ↓ |
| ╔════════════════════════════════════╗ |
| ║ DispatcherServlet ║ ← ENTRY TO SPRING MVC |
| ║ (Spring's Front Controller) ║ |
| ╚════════════════════════════════════╝ |
└───────────────────────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────── SPRING CONTAINER ──────────────────────────────────────────┐
| ┌────────────────────────────────────┐ |
| │ Handler Mapping │ |
| │ - Find @Controller method │ |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ Interceptor.preHandle() │ ← Spring-level interception |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ @RestController Method │ |
| │ public String test() {...} │ |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ Interceptor.postHandle() │ |
| └────────────────────────────────────┘ |
| ↓ |
| ┌────────────────────────────────────┐ |
| │ Response Rendering │ |
| └────────────────────────────────────┘ |
└───────────────────────────────────────────────────────────────────────────────────┘
↓
╔════════════════════════════════════╗
║ Back through Filter Chain ║
║ (in reverse order) ║
╚════════════════════════════════════╝
│
▼
HTTP Response to Client
|
package javax.servlet;
/** A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static
* content), or on the response from a resource, or both.
*
* Filters perform filtering in the doFilter method. Every Filter has access to a FilterConfig object from
* which it can obtain its initialization parameters, a reference to the ServletContext which it can use, for example,
* to load resources needed for filtering tasks.
*
* Examples that have been identified for this design are
* 1) Authentication Filters
* 2) Logging and Auditing Filters
* 3) Image conversion Filters
* 4) Data compression Filters
* 5) Encryption Filters
* 6) Tokenizing Filters
* 7) Filters that trigger resource access events
* 8) XSL/T filters
* 9) Mime-type chain Filter
*
* @since Servlet 2.3 */
public interface Filter {
// Called once when filter is initialized
default void init(FilterConfig filterConfig) throws ServletException {
}
// Called for every request
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
// Called once when filter is destroyed
default void destroy() {
}
}/** A filter configuration object used by a servlet container to pass information to a filter during initialization.
* @since Servlet 2.3 */
public interface FilterConfig {
String getFilterName();
ServletContext getServletContext();
String getInitParameter(String name);
Enumeration getInitParameterNames();
}package org.springframework.web.filter; public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {
}
public abstract class OncePerRequestFilter extends GenericFilterBean {
@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
//...
}
// ...
} |
| Filter (Interface) - @since Servlet 2.3 FilterConfig (Interface): FilterRegistrationBean (RECOMMENDED) - @since Servlet 2.3 @interface WebFilter - @since Servlet 3.0 [ WARNING: @Autowired may not work reliably!] |
OncePerRequestFilter (Abstract Class) | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Filter (Interface): The base Servlet API interface that all filters must implement.
// Regular Filter - may execute MULTIPLE times
// With request forwarding:
// GET /api/user → forwards to /api/user/details
// Output: "Executed" (twice!)
@Component
public class RegularFilter implements Filter {
@Autowired
private SomeService service; // Can inject Spring beans
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter initialized");
// Read init parameters, initialize resources
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("Executed"); // May print multiple times!
// Pre-processing
chain.doFilter(request, response); // Continue chain
// Post-processing
}
@Override
public void destroy() {
System.out.println("Filter destroyed");
// Cleanup resources
}
}
FilterConfig (Interface): Configuration object passed to the filter during initialization. Provides access to: Filter name, Initialization parameters, ServletContext
Registering with Init Parameters: @Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean filterToRegister() {
FilterRegistrationBean registrationBean =
new FilterRegistrationBean<>();
registrationBean.setFilter(new RegularFilter());
registrationBean.addUrlPatterns("/*");
// Set init parameters (accessible via FilterConfig)
registrationBean.addInitParameter("allowedOrigins", "http://localhost:3000,http://example.com");
registrationBean.addInitParameter("maxRequestSize", "2097152");
return registrationBean;
}
}
@WebFilter + @ServletComponentScan
// Enable scanning
@SpringBootApplication
@ServletComponentScan(basePackages = "com.example.filters")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// Filter
@WebFilter(urlPatterns = "/api/*")
public class WebFilterExample implements Filter {
// WARNING: @Autowired may not work reliably!
// @Autowired private SomeService service;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("@WebFilter executing");
chain.doFilter(request, response);
}
} |
Spring Framework class that guarantees filter execution only once per request, even with forwards and includes.
@Component
public class LoggingFilter extends OncePerRequestFilter {
@Autowired
private UserService userService; // Dependency injection works!
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
System.out.println("Executed ONLY ONCE"); // Guaranteed single execution
// Pre-processing
long startTime = System.currentTimeMillis();
filterChain.doFilter(request, response);
// Post-processing
long duration = System.currentTimeMillis() - startTime;
System.out.println("Request completed in " + duration + "ms");
}
}CachingRequestFilter extends OncePerRequestFilter@Component
public class CachingRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
// Wrap request to cache body (for multiple reads)
CachedBodyHttpServletRequest cachedRequest =
new CachedBodyHttpServletRequest(request);
// Wrap response to capture output
ContentCachingResponseWrapper cachedResponse =
new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(cachedRequest, cachedResponse);
} finally {
// Log request body
String requestBody = new String(cachedRequest.getCachedBody(),
StandardCharsets.UTF_8);
logger.debug("Request Body: {}", requestBody);
// Log response body
byte[] responseContent = cachedResponse.getContentAsByteArray();
String responseBody = new String(responseContent, StandardCharsets.UTF_8);
logger.debug("Response Body: {}", responseBody);
// Important: Copy content back to response
cachedResponse.copyBodyToResponse();
}
}
}
// Custom wrapper to cache request body
class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
private byte[] cachedBody;
public CachedBodyHttpServletRequest(HttpServletRequest request)
throws IOException {
super(request);
InputStream requestInputStream = request.getInputStream();
this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
}
@Override
public ServletInputStream getInputStream() {
return new CachedBodyServletInputStream(this.cachedBody);
}
@Override
public BufferedReader getReader() {
ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(this.cachedBody);
return new BufferedReader(
new InputStreamReader(byteArrayInputStream));
}
public byte[] getCachedBody() {
return cachedBody;
}
} |