手写实现SpringMVC (注解式开发)

手写实现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. 测试

  1. 创建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();
        }

    }
}

  1. 创建service
@MyService("UserServiceImpl")
public class UserServiceImpl implements UserService {


    public String getUser(String name) {

        return "service provide success ";
    }
}

  1. 成功服务

猜你喜欢

转载自www.cnblogs.com/windyCoding/p/12821867.html