手写SpringMVC

SpringMVC的入门程序

快速创建springmvc项目加入的属性。
archetypeCatalog
internal
在这里插入图片描述

入门案例的执行流程

  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件
  2. 开启了注解扫描,那么HelloController对象就会被创建。
  3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法
  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
  5. Tomcat服务器渲染页面,做出响应。

在这里插入图片描述

/**

前端控制器也是用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) {}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值