手写实现SpringMVC (注解式开发)
一、springmvc设计原理图
二、SpringMVC的前端控制器DispatchServlet
1. 架构图
2. SpringMVC的九大组件(【SpringMVC】9大组件概览)
protected void initStrategies(ApplicationContext context) {
//用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File.
initMultipartResolver(context); private MultipartResolver multipartResolver;
//SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
initLocaleResolver(context); private LocaleResolver localeResolver;
//用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、
//如图片、css样式等。SpringMVC的主题也支持国际化,
initThemeResolver(context); private ThemeResolver themeResolver;
//用来查找Handler的。
initHandlerMappings(context); private List<HandlerMapping> handlerMappings;
//从名字上看,它就是一个适配器。Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。
//如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情,
initHandlerAdapters(context); private List<HandlerAdapter> handlerAdapters;
//其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?
//这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。
initHandlerExceptionResolvers(context); private List<HandlerExceptionResolver> handlerExceptionResolvers;
//有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,
//如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。
initRequestToViewNameTranslator(context); private RequestToViewNameTranslator viewNameTranslator;
//ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。
//View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。
initViewResolvers(context); private List<ViewResolver> viewResolvers;
//用来管理FlashMap的,FlashMap主要用在redirect重定向中传递参数。
initFlashMapManager(context); private FlashMapManager flashMapManager;
}
三、实现Springmvc框架
1. 首先创建一个maven项目,导入相关依赖
<!--Servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
2. WEB-INF下创建一个web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema" xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<display-name>springmvc1</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>com.springmvc.springmvc.servlet.MyDispatchServlet</servlet-class>
<init-param>
<param-name>MyDispatchServlet</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
</web-app>
3. 创建注解
MyAutowired.class
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
}
MyController.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
}
MyRequestMapping.class
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
MyRequestParam.class
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
String value() default "";
}
MyService.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
4. 创建springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:conponent-scan base-package="com.springmvc"/>
</beans>
5. 创建前端控制器MyDispatchServlet.class
public class MyDispatchServlet extends HttpServlet {
List<String> classNames = new ArrayList<String>();
//存放bean
Map<String, Object> beans = new HashMap<String, Object>();
Map<String, Object> handlerMap = new HashMap<String, Object>();
/**
* Get
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
/**
* Post
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//拿路径
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
String path = uri.replace(contextPath, "");
Method method = (Method) handlerMap.get(path);
UserController instance = (UserController) beans.get(path.split("/")[1]);
Object args[] = hand(req, resp, method);
try {
method.invoke(instance, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//策略模式
private static Object[] hand(HttpServletRequest req, HttpServletResponse resp, Method method) {
//拿到当前代执行的方法有哪些参数
Class<?>[] parameterTypes = method.getParameterTypes();
//根据参数的个数,new一个参数的数组,将方法里的所有参数赋值到args
Object[] args = new Object[parameterTypes.length];
int args_i = 0;
int index = 0;
for (Class<?> parameterType : parameterTypes) {
if (ServletRequest.class.isAssignableFrom(parameterType)) {
args[args_i++] = req;
}
if (ServletResponse.class.isAssignableFrom(parameterType)) {
args[args_i++] = resp;
}
Annotation[] annotation = method.getParameterAnnotations()[index];
if (annotation.length > 0) {
for (Annotation annotation1 : annotation) {
if (MyRequestParam.class.isAssignableFrom(annotation1.getClass())) {
MyRequestParam requestParam = (MyRequestParam) annotation1;
args[args_i++] = req.getParameter(requestParam.value());
}
}
}
}
return args;
}
/**
* 初始化
*
* @throws ServletException
*/
@Override
public void init() throws ServletException {
//1、实例化,扫描backpackage,scan
doScan("com.springmvc");
//把扫描出来的.class进行实例化
doInstance();
//注入
doAutowire();
//映射
UrlHandering();
}
private void UrlHandering() {
for (Map.Entry<String, Object> entry : beans.entrySet()) {
Object instance = entry.getValue();
Class<?> aClass = instance.getClass();
if (aClass.isAnnotationPresent(MyController.class)) {
MyRequestMapping requestMapping = aClass.getAnnotation(MyRequestMapping.class);
String classPath = requestMapping.value();
Method[] methods = aClass.getMethods();
classPath = "/" + classPath;
for (Method method : methods) {
if (method.isAnnotationPresent(MyRequestMapping.class)) {
MyRequestMapping mapping = method.getAnnotation(MyRequestMapping.class);
String methodPath = mapping.value();//方法的路径
handlerMap.put(classPath + methodPath, method);
} else {
continue;
}
}
}
}
}
private void doAutowire() {
for (Map.Entry<String, Object> entry : beans.entrySet()) {
Object instance = entry.getValue();
Class<?> aClass = instance.getClass();
if (aClass.isAnnotationPresent(MyController.class)) {
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(MyAutowired.class)) {
MyAutowired annotation = field.getAnnotation(MyAutowired.class);
String value = annotation.value();
Object obj = beans.get(value);
field.setAccessible(true);
try {
field.set(instance, obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
continue;
}
}
} else {
continue;
}
}
}
private void doInstance() {
for (String className : classNames) {
String replace = className.replace(".class", "");
try {
Class<?> clazz = Class.forName(replace);
if (clazz.isAnnotationPresent(MyController.class)) {
Object instance = clazz.newInstance();
MyRequestMapping annotation = clazz.getAnnotation(MyRequestMapping.class);
String key = annotation.value();
beans.put(key, instance);
} else if (clazz.isAnnotationPresent(MyService.class)) {
Object instance = clazz.newInstance();
MyService annotation = clazz.getAnnotation(MyService.class);
String key = annotation.value();
beans.put(key, instance);
} else {
continue;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void doScan(String s) {
String all = s.replaceAll("\\.", "/");
URL url = this.getClass().getClassLoader().getResource("/"+/**/all);
String fileStr = url.getFile();
File file = new File(fileStr);
String[] filesStr = file.list();
for (String path : filesStr) {
File filePath = new File(fileStr + path);
if (filePath.isDirectory()) {
//递归
doScan(s + "." + path);
} else { //.class文件
classNames.add(s + "." + filePath.getName());
}
}
}
}
6. 测试
- 创建UserConroller
@MyController("UserController")
@MyRequestMapping("mvc")
public class UserController {
@MyAutowired("UserServiceImpl")
private UserService userService;
@MyRequestMapping("/user")
public void getUser(HttpServletRequest request, HttpServletResponse response, @MyRequestParam("name") String name) {
String user = userService.getUser(name);
try {
response.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 创建service
@MyService("UserServiceImpl")
public class UserServiceImpl implements UserService {
public String getUser(String name) {
return "service provide success ";
}
}
- 成功服务