欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

手写SpringMVC

程序员文章站 2022-07-15 11:21:57
...
/**

前端控制器也是用java语言编写,主要用来处理网络请求
势必会集成HttpServlet j2ee规范
https://v.qq.com/x/page/c0393ws95u5.html
@WebServlet注解将DispatcherServlet(*控制器)交给容器进行管理,servlet3.0的注解 
*/ 
@WebServlet(“/DispatcherServlet”) 
public class DispatcherServlet extends HttpServlet { 
//放扫描我们基包下面的bean的权限定类名 
private List packNames = new ArrayList(); 
//将注解参数信息和实例一一对应 注册到容器 
private Map<String,Object> instanceMaps = new HashMap<String,Object>(); 
//构建方法链容器,这里说明spring比struts更加轻量级,因为struts是基于类级别的,而spring拿到url在方法上执行。 
private Map<String,Method> handlerMaps = new HashMap<String,Object>();
public void init() throws ServletException {
    //拿到spring.xml配置全包扫描的基础包 Resource
    try {
    String basePackName = confiUtils.getBasePackgName("E/**/spring.xml");
    System.out.println("basePackName" + basePackName);
    //全自动扫描基包功能实现
    scanBase(basePackName);
    //这里就是找每个Bean的实例,注册到我们的容器上下文
    foundBeansInstance();
    //注入实例, 通过Spring 定义的注解注入实例
    springIoc();
    //handlerMapping
    handlerMapping();
    } catch(Exception e) {}
}
//处理方法执行链
private void handlerMapping() throws Exception {
    if(instanceMaps.size() == 0 ){
        return;
    }
    //对url请求,然后找到相应的handler进行处理
    for(Map.Entry<String,Object> entry : instanceMaps.entrySet()) {
       if(entry.getValue().getClass.isAnnotationPresent(Controller.class)) {
            Controller controllerAnnotation = entry.getValue().getClass.isAnnotationPresent(Controller.class);
            //执行方法链接classUrl/MethodUrl
            String classUrl = controllerAnnotation.value();
            //通过字节码对象里面方法对象拿到方法对象上面的注解参数
            Method [] methods = entry.getValue().getClass.getMethods();
            for(Method method : methods) {
                if(method.isAnnotationPresent(RequestMapping.class )) {
                    String methodUrl = (RequestMapping)method.getAnnotation(RequestMapping.class).value();
                    handlerMaps.put("/"+ classUrl + "/" + methodUrl, method);
                } else {
                    continue;
                }
            }
       }
    }


}
//将上下文实例注入到bean对象中,代码耦合完全分离开
private void springIoc() throws Exception {
    if(instanceMaps.size() == 0 ){
        return;
    }
    for(Map.Entry<String,Object> entry : instanceMaps.entrySet()) {
        Field [] fieldNames = entry.getValue().getClass().getDeclaredFields();
        for(Field fieldName : fieldNames) {
            if(fieldName.isAnnotationPresent(Qualifier.class)) {
                String qualiferParamString = ((Qualifier)fieldName.getAnnotation(Qualifier.class )).value();
                //让私有化的属性也能注入实例
                field.setAccessible(true);
                field.set(entry.getValue(), instanceMaps.get(qualiferParamString));
            } else {
                continue;
            }
        }
    }
}
/**
*将扫描到bean实例注册到上下文中
*/
private void foundBeansInstance(){
    if(packNames.size() == 0 ){
        return;
    }
    //className 文件名称  带有文件扩展名.class
    for(String className : packNames) {
        //反射拿到字节码对象 然后拿到实例
        Class ccName = Class.forName(className.replace(".class",""))
        //思想 是拿业务Bean 实例 判断字节码对象是否含有Controller类型
        if(ccName.isAnnotationPresent(Controller.class)) {
            //拿到控制层的注解对象
            Controller controllerAnnotationObject =(Controller)ccName.getAnnotation(Controller.class);
            String controllerParmString = controllerAnnotationObject.value();
            //拿控制层的实例
            Object controllerInstance = ccName.newInstance();
            //找到实例并注册到容器
            instanceMaps.put(controllerParmString, controllerInstance);
        } else if(ccName.isAnnotationPresent(Service.class)) {
            //拿到server的注解对象
            Service serverAnnotationObject =(Service)ccName.getAnnotation(Service.class);
            String serverParmString = serverAnnotationObject.value();
            //拿server的实例
            Object serverInstance = ccName.newInstance();
            //找到server实例并注册到容器
            instanceMaps.put(serverParmString, serverInstance);

        } else {
            continue;
        }
    }
}
//全自动扫描基包功能实现,源于源码
private void scanBase(String basePackName) {
    //basePackName: com.dongnao=>com/dongnao
    URL url = this.getClass().getClassLoader().getResource("/"+replacePath(basePackName));
    String pathFile = url.getFile();
    File file = new File(pathFile);
    String [] files = file.list();
    for(String path : files) {
        File eachFile = new File(pathFile+path);
        //代表eachFile只是一个目录
        if(eachFile.isDirectory()) {
            //递归 以com.dongnao.annotation为条件
            scanBase(basePackName+"."+eachFile.getName());

        } else if(eachFile.isFile()) {
            packNames.add(basePackName+"."+eachFile.getName());
            System.out.println("spring容器扫描到的类有:"+basePackName+"."+eachFile.getName());
        }
    }

}

private String replacePath(String basePackName) {
    return basePackName.replaceAll("\\.","/");
}

protected void doGet(HttpServletRequest req, HttpServletResponse resp) thorws ServletExceptoin, IOException {
    doPost(req, resp);
}

protected void doGet(HttpServletRequest req, HttpServletResponse resp) thorws ServletExceptoin, IOException {
    String uri = req.getRequestURI();
    String projectName = req.getContextPath();
    //这里拿到请求链接 classUrl + MethodUrl
    String methodUriString = uri.replace(projectName,"");
    Method method = handlerMaps.get(methodUrl);
    PrintWriter outPrintWriter = resp.getWriter();
    if(method == null ){
        outPrintWriter.writer("您访问的资源不存在,请检查访问路径!");

    }
    //localhost:8000/Projectname/dongnao/insert
    String className = uri.split("/")[2];
    DongNaoController dnObj = (DongNaoController)instanceMaps.get(className);
    //aop
    try{
    method.invoke(obj,new Object[]{req,resp,null})
    }catch(Exception e) {}
}
}
相关标签: Spring

上一篇: 2

下一篇: SpringMVC手写