Introduction
Spring MVC is a powerful web framework that implements the Model-View-Controller pattern.In this article,I'll explore the implementation of a simplified Spring MVC framework through my miniSpring project,which captures the essential features of Spring MVC while maintaining clarity and simplicity.
src/com/yaruyng/web/ ├── servlet/ │ ├── DispatcherServlet.java │ ├── HandlerMapping.java │ ├── HandlerAdapter.java │ ├── ModelAndView.java │ ├── ViewResolver.java │ └── View.java ├── method/ ├── context/ └── RequestMapping.java
The Front Controller:DispatcherServlet
The DispatcherServlet acts as the front controller in our MVC implements:
public class DispatcherServlet extends HttpServlet { private WebApplicationContext webApplicationContext; private HandlerMapping handlerMapping; private HandlerAdapter handlerAdapter; private ViewResolver viewResolver; @Override public void init(ServletConfig config) throws ServletException { super.init(config); this.parentApplicationContext = (WebApplicationContext) this.getServletContext() .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); this.sContextConfigLocation = config.getInitParameter("contextConfigLocation"); this.webApplicationContext = new AnnotationConfigWebApplicationContext( sContextConfigLocation, this.parentApplicationContext ); Refresh(); } protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerMethod handlerMethod = null; ModelAndView mv = null; // 1. Get handler for request handlerMethod = this.handlerMapping.getHandler(processedRequest); if(handlerMethod == null) { return; } // 2. Execute handler with adapter HandlerAdapter ha = this.handlerAdapter; mv = ha.handle(processedRequest, response, handlerMethod); // 3. Render view render(request, response, mv); } }
Key features of the Dispatcher:
- Initializes the web application context
- Sets up handler mapping,adapter, and view resolver
- Processes incoming requests through the doDispatch method
- Coordinates between different components of the MVC framework
Request Mapping
The @RequestMapping annotation is used to map web requests to handler methods:
@Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { String value() default ""; }
This simple yet powerful annotation allows for:
- Method-level request mapping
- URL pattern matching
- Runtime processing of mapping
Model and View Handling
The ModelAndView class represents both the model data and view information:
public class ModelAndView { private Object view; private Map<String, Object> model = new HashMap<>(); public ModelAndView(String viewName, Map<String, ?> modelData) { this.view = viewName; if(modelData != null) { addAllAttributes(modelData); } } public void addAttribute(String attributeName, Object attributeValue) { model.put(attributeName, attributeValue); } public ModelAndView addObject(String attributeName, Object attributeValue) { addAttribute(attributeName, attributeValue); return this; } // Other methods... }
This implementation:
- Combines view information with model data
- Provides flexible constructors fro different use cases
- Offers convenient methods for adding attributes
View Resolution
The view resolution process is handled the ViewResolver interface and its implementation:
public interface ViewResolver { View resolveViewName(String viewName) throws Exception; }
The actual rendering is performed by the View interface:
public interface View { void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception; }
Request Processing Flow
The request processing flow in miniSpring MVC follows these steps:
- Request Reception
protected void service(HttpServletRequest request, HttpServletResponse response) { request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.webApplicationContext); try { doDispatch(request, response); } catch (Exception e) { throw new RuntimeException(e); } }
- Handler Mapping
handlerMethod = this.handlerMapping.getHandler(processedRequest);
- Handler Execution
mv = ha.handle(processedRequest, response, handlerMethod);
- View Rendering
protected void render(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { if(mv == null) { response.getWriter().flush(); response.getWriter().close(); return; } String sTarget = mv.getViewName(); Map<String, Object> modelMap = mv.getModel(); View view = resolveViewName(sTarget, modelMap, request); view.render(modelMap, request, response); }
Integration with IoC Container
The MVC framework integrates with the IoC container through the WebApplicationContext:
protected void initHandlerMappings(WebApplicationContext wac) { try { this.handlerMapping = (HandlerMapping) wac.getBean(HANDLER_MAPPING_BEAN_NAME); } catch (BeansException e) { e.printStackTrace(); } }
This integration provides:
- Automatic bean management
- Dependency injection for controllers
- Configuration management
Example Usage
Here's how to use the miniSpring MVC framework:
@RequestMapping("/hello") public ModelAndView handleRequest(HttpServletRequest request) { String message = "Hello, World!"; ModelAndView mv = new ModelAndView("hello"); mv.addObject("message", message); return mv; }
And the corresponding configuration:
<bean class="com.yaruyng.web.servlet.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello">helloController</prop> </props> </property> </bean>
Performance Considerations
The implementation includes several performance optimizations:
- Single Front Controller: All request go through a single servlet
- Handler Caching: Handler methods are cached after first resolution
- View Caching: Resolved views are cached for reuse
- Efficient Request Processing: Minimal object creation per request
Extension Points
The framework provides several extension points:
- Custom Handler Mappings: Implement HandlerMapping interface
- Custom View Resolvers: Implement ViewResolver interface
- Custom Handler Adapters: Implement HandlerAdapter interface
- Custom Views: Implement View interface
Conclusion
This implementation of Spring MVC demonstrates:
- The power of the front controller pattern
- Clean separation of concerns through MVC
- Flexible handling of requests and responses
- Integration with IoC container
- Extensible architecture Key takeaways:
- Understanding Spring MVC's internal structure
- How different components work together
- The importance of clean architecture
- Extension points for customization
The miniSpring MVC implementation provides a solid foundation for understanding how Spring MVC works internally while maintaining simplicity and clarity.
Top comments (0)