手动简单实现springmvc,记录学习

1.dispatcher

继承HttpServlet ,重写 init() , doGet() ,doPost()方法,主要通过 反射

package org.com.dispatcherservlet;


import org.com.annotation.*;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @Author: zx
 * @Date: 
 */
public class MyDsipatcherServlet extends HttpServlet {

    private Properties properties = new Properties();

    private static final String LOCATION = "contextConfigLocation";

    private ServletConfig config;

    /**
     * 存放类名
     */
    private List<String> classNames = new ArrayList<String>();

    /**
     * ioc
     */
    private Map<String , Object> iocMap = new HashMap<>();


    /**
     * url 映射 到控制器
     */
    private Map<String  , Handler> mapping = new HashMap<>();


    /**
     * 控制器
     */
    private class Handler{
        protected Object controller;	//保存方法对应的实例
        protected Method method;		//保存映射的方法
        protected Pattern pattern;     //路径
        protected Map<String,Integer> paramIndexMapping;	//参数顺序 基本传入参数


        public Handler(Object controller, Method method, Pattern pattern) {
            this.controller = controller;
            this.method = method;
            this.pattern = pattern;
            paramIndexMapping = new HashMap<String,Integer>();
            this.putParamIndexMapping(method);
        }

        private void putParamIndexMapping(Method method) {
            //所有参数列
            Parameter[] parameters = method.getParameters();
            //spring自带 查class文件 拿到 入参名称
            LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
            String[] parameterNames = u.getParameterNames(method);
            //参数的名称
            Class<?>[] parameterTypes = method.getParameterTypes();
            int num = 0;
            for (Parameter parameter : parameters) {
                Annotation[] annotations = parameter.getDeclaredAnnotations();
                if(annotations != null && annotations.length > 0 ){
                    for (Annotation annotation : annotations) {
                        Class<? extends Annotation> aClass = annotation.annotationType();
                        //指定参数 并且有设置value
                        if(aClass == MyRequestParam.class){
                            String paramName = ((MyRequestParam) annotation).value();
                            if("" != paramName) paramIndexMapping.put(paramName , num);
                        }
                    }
                }else{
                    paramIndexMapping.put(parameterNames[num], num);
                }
                num++;
            }
        }


        public Object invoke(Object...args) throws InvocationTargetException, IllegalAccessException {
            return method.invoke(this.controller , args);
        }

    }


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req , resp);
        return;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //开始始匹配到对应的方方法
        try {
            doDispatch(req , resp);
        }catch (Exception e){
            e.printStackTrace();
            resp.getWriter().write("500 error");
        }
        return;
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        if(mapping.isEmpty()){ return;}

        Handler handler = doHandler(req, resp);

        if(handler==null){
            resp.getWriter().write("404 Not page");
            return;
        }

        try {
            //获取方法的参数列表
            Map<String, Integer> paramIndexMapping = handler.paramIndexMapping;
            //保存所有需要自动赋值的参数值
            Object [] paramValues = new Object[paramIndexMapping.size()];
            //获取方法的参数类型列表
            Class<?> [] paramTypes = handler.method.getParameterTypes();
            //request参数
            Map<String,String[]> params = req.getParameterMap();
            for (Map.Entry<String, String []> param : params.entrySet()) {
                String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
                //如果找到匹配的对象,则开始填充参数值
                if(!handler.paramIndexMapping.containsKey(param.getKey())){continue;}
                int index = handler.paramIndexMapping.get(param.getKey());
                paramValues[index] = convert(paramTypes[index] , value);
            }

            if(paramIndexMapping.containsKey("request")){
                Integer reqIndex = paramIndexMapping.get("request");
                paramValues[reqIndex]  = req;
            }

            if(paramIndexMapping.containsKey("response")){
                Integer respIndex = paramIndexMapping.get("response");
                paramValues[respIndex]  = resp;
            }
            Object invoke = handler.invoke(paramValues);
            resp.getWriter().write(invoke.toString());
            return;
        }catch (Exception e){
            e.printStackTrace();
            resp.getWriter().write("500 error");
            return;
        }
    }

    private Object convert(Class<?> paramType, String value) {
        if(int.class == paramType){
            return Integer.valueOf(value);
        }
        return value;
    }


    /**
     * 获取handler
     */
    public Handler doHandler(HttpServletRequest req, HttpServletResponse resp){
        String url = req.getRequestURI();
        //上下文路径
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");
        if(mapping.containsKey(url)){
            return mapping.get(url);
        }
        return null;
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

        this.config = servletConfig;
        //加载配置文件
        loadConfig(servletConfig.getInitParameter(LOCATION));
        //扫描类
        scanPackage(properties.getProperty("scanPackage"));
        //初始化扫描到的类
        doInstance();
        //完成依赖注入
        doAutoWired();
        //初始化HandlerMapping
        initHandlerMapping();

        super.init();
        System.out.println("初始化完成-----------------------------------");
    }



    private void initHandlerMapping() {
        //初始化 url映射关系
        for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
            //controller组装映射
            Class<?> aClass = entry.getValue().getClass();
            MyController annotation = aClass.getDeclaredAnnotation(MyController.class);
            if(annotation != null){
                MyRequestMapping baseMapping = aClass.getDeclaredAnnotation(MyRequestMapping.class);
                String baseUrl = baseMapping.value();
                //获取类 url 配置
                //获取Method的url配置
                Method [] methods = aClass.getMethods();
                for (Method method : methods) {
                    //没有加RequestMapping注解的直接忽略
                    if(!method.isAnnotationPresent(MyRequestMapping.class)){ continue; }
                    //映射URL
                    MyRequestMapping methodtMapping = method.getDeclaredAnnotation(MyRequestMapping.class);
                    if(methodtMapping!=null){
                        // 组装url:/baseUrl/methodUrl
                        String regex = ("/" + baseUrl + "/" + methodtMapping.value()).replaceAll("/+", "/");
                        if(!mapping.containsKey(regex)){
                            mapping.put(regex , new Handler(entry.getValue()  ,  method  , Pattern.compile(regex)));
                        }else{
                            throw  new RuntimeException("500 requestMapping conflict");
                        }
                    }
                }
            }
        }
    }

    private void doAutoWired(){
        if(iocMap.isEmpty()){return;}
        for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
            //获取所有字段
            Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
            System.out.println(declaredFields.length);
            for (Field field : declaredFields) {
                //判断字段是否需要注入
                if(!field.isAnnotationPresent(MyAutowired.class)){continue;}
                MyAutowired declaredAnnotation = field.getDeclaredAnnotation(MyAutowired.class);
                String beanName = declaredAnnotation.value();
                if(declaredAnnotation != null){
                    if("".equals(beanName)){
                        beanName = field.getType().getName();
                    }
                }
                try {
                    field.setAccessible(true);
                    field.set(entry.getValue() , iocMap.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void doInstance() {
        //初始化ioc容器
        if(classNames == null || classNames.size() == 0){return;}

        classNames.stream().forEach(e ->{
            try {
                Class<?> aClass = Class.forName(e);
                if(aClass.isAnnotationPresent(MyController.class)){
                    //controller 注解
                    Object iocObject = aClass.newInstance();
                    String beanName =  toLowerFirstCase(e);
                    iocMap.put(beanName , iocObject);
                }else if(aClass.isAnnotationPresent(MyService.class)){
                    //controller 注解
                    Object iocObject = aClass.newInstance();
                    //看是否设置service名称
                    MyService service = aClass.getAnnotation(MyService.class);
                    String beanName = service.value();
                    if("" == beanName.trim() ){
                        beanName =  toLowerFirstCase(e);
                        iocMap.put(beanName , iocObject);
                    }else{
                        //如果自己没设,就按接口类型创建一个实例
                        Class<?>[] interfaces = aClass.getInterfaces();
                        for (Class<?> i : interfaces) {
                            beanName =  toLowerFirstCase(e);
                            iocMap.put(i.getName(), iocObject);
                        }
                    }
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        });
        System.out.println();
    }

    private String toLowerFirstCase(String e) {
        char[] chars = e.toCharArray();
        //大小写字母相差32
        chars[0] += 32;
        return String.valueOf(chars);
    }


    private void scanPackage(String scanPackage) {
        //获取编译后
        URL resource = this.getClass().getClassLoader().getResource("/" +  scanPackage.replaceAll("\\.", "/"));
        File dir = new File(resource.getFile());
        File[] files = dir.listFiles();
        for (File   f : files) {
            if(f.isDirectory()){
                scanPackage(scanPackage + '.' + f.getName() );
            }else{
                String className = f.getName();
                if(className.endsWith(".class")){
                    classNames.add( scanPackage + "." +  className.replace(".class" , "").trim());
                }
            }
        }
    }

    private void loadConfig(String initParameter) {
        InputStream in  = null;
        try {
            in =  this.getClass().getClassLoader().getResourceAsStream(initParameter);
            properties.load(in);
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            try {
                in.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


}

2.注解

package org.com.annotation;

import java.lang.annotation.*;

/**
 * @author zx
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
    String value() default "";
}


/**
 * @author zx
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
    String value() default "";
}

/**
 * @author zx
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
    String value() default "";
}

/**
 * @author zx
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
    String value() default "";
}

/**
 * @author zx
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
    String value() default "";
}


3.controller


/**
 * @Author: zx
 * @Date: 
 */

@MyRequestMapping(value = "/hellow")
@MyController
public class HellowController {

    @MyAutowired
    private HellowService hellowService;


    @MyRequestMapping(value = "/getHellowList")
    public String getHellow(HttpServletRequest request , HttpServletResponse response , @MyRequestParam(value = "name") String name , int age){
        return "My zx";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值