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)