源码学习(一)——模拟Spring MVC

1.准备

1.1创建项maven项目,目录如下

1.2 导包

servlet-api: 模拟springmvc采用的是对同一个servlet进行处理

fastjson: JSONObject 是阿里自己封装的一个map,本人习惯使用,非必需

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.rrg</groupId>
  <artifactId>learning-framework</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <dependencies>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
          <version>2.5</version>
      </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.8</version>
    </dependency>

  </dependencies>
</project>

2.自定义SpringMVC注解

2.1 MyMapper

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)    //作用目标 所有对象
@Retention(RetentionPolicy.RUNTIME)    //保留策略    运行期
@Documented
public @interface MyMapper {

    String value() default "";

}

2.2MyService.java

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) //作用目标 所有对象
@Retention(RetentionPolicy.RUNTIME) //保留策略 运行期
@Documented
public @interface MyService {

String value() default "";

}

2.2

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)    //作用目标 所有对象
@Retention(RetentionPolicy.RUNTIME)    //保留策略    运行期
@Documented
public @interface MyController {

    String value() default "";

}

2.3MyController.java

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)    //作用目标 所有对象
@Retention(RetentionPolicy.RUNTIME)    //保留策略    运行期
@Documented
public @interface MyController {

    String value() default "";

}

2.4  MyQulifier.java

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)    //作用目标 字段 即 成员变量
@Retention(RetentionPolicy.RUNTIME)    //保留策略    运行期
@Documented
public @interface MyQulifier {

    String value() default "";

}

2.5 RequestMapping.java

package com.rrg.ssm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})    //作用目标 所有对象 和 方法
@Retention(RetentionPolicy.RUNTIME)    //保留策略    运行期
@Documented
public @interface MyRequestMapping {

    String value() default "";

}

3.模拟业务逻辑

3.1 entity

User.java

package com.rrg.ssm.entity;

public class User {

    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}

3.2 mapper层

UserMapper.java

package com.rrg.ssm.mapper;

import com.rrg.ssm.annotation.MyMapper;
import com.rrg.ssm.entity.User;
/**
 * 用户Mapper
 * @author JIE
 */
@MyMapper("userMapper")
public class UserMapper {

    public User selectById(Integer id){
        System.out.println("【UserMapper】执行查询操作");
        User user = new User("JIE",    22);
        return user;
    }
}

3.3 service层

UserSservice.java

package com.rrg.ssm.service;

import com.rrg.ssm.entity.User;
/**
 * 用户服务接口
 * @author JIE
 */
public interface UserService {

    /**
     * 根据id查找用户
     */
    public User selectById(Integer id);
}

UserServiceImpl.java

package com.rrg.ssm.service.impl;

import com.rrg.ssm.annotation.MyQulifier;
import com.rrg.ssm.annotation.MyService;
import com.rrg.ssm.entity.User;
import com.rrg.ssm.mapper.UserMapper;
import com.rrg.ssm.service.UserService;
/**
 * 用户服务实现类
 * @author JIE
 */
@MyService("userService")
public class UserServiceImpl implements UserService {

    @MyQulifier("userMapper")
    private UserMapper userMapper;

    public User selectById(Integer id) {
        System.out.println("【UserService】执行业务操作");
        return userMapper.selectById(id);
    }

}

3.4 UserController.java

package com.rrg.ssm.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.rrg.ssm.annotation.MyController;
import com.rrg.ssm.annotation.MyQulifier;
import com.rrg.ssm.annotation.MyRequestMapping;
import com.rrg.ssm.entity.User;
import com.rrg.ssm.service.UserService;
/**
 *
 * @author JIE
 *
 */
@MyController("userController")
@MyRequestMapping("/user")
public class UserController {

    @MyQulifier("userService")
    private UserService userService;

    @MyRequestMapping("/get")
    public void getUser(HttpServletRequest request, HttpServletResponse response) {
        User user = userService.selectById(2);
        System.out.println("【UserController】:" + user);
    }
}

4.spring mvc核心

思路:  ①扫描包,将所有文件放到package的一个list里面;

     ②扫描①中的包,找到三层架构的controller,service,mapper并实例化放到map,key为注解上的值就变量名,例如@MyController("userController")                                         map("userController",userController实例化的对象);

     ③建立映射关系,实现@RequestMapping功能,根据类前的注解和方法前的注解,保存到map,key是拦截的地址,value是对应的方法,为后面提供调                                        用method.invoke(userController, req, resp);

     ④注入依赖,DI,根据MyQulifier注解到②的map中找到实体,注入到成员变量 field(obj,obj)

4.1 核心MyDispatcherServlet.java

package com.rrg.ssm.core;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;
import com.rrg.ssm.annotation.MyController;
import com.rrg.ssm.annotation.MyMapper;
import com.rrg.ssm.annotation.MyQulifier;
import com.rrg.ssm.annotation.MyRequestMapping;
import com.rrg.ssm.annotation.MyService;
import com.rrg.ssm.controller.UserController;
/**
 * Spring MVC核心
 * @author JIE
 */
public class MyDispatcherServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private List<String> packageList = new ArrayList<String>();
    private JSONObject instanceJSON = new JSONObject();
    private JSONObject mappingJSON = new JSONObject();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //requestURl=>    http://localhost:8180/learning-again/user/get
        //StringBuffer requestURl = req.getRequestURL();
        //requestURI=>    /learning-again/user/get
        String requestURI = req.getRequestURI();
        //contextPath=>    /learning-again
        String contextPath = req.getContextPath();
        //reqpath=>        /user/get
        String reqpath = requestURI.replace(contextPath, "");
        UserController userController = (UserController) instanceJSON.get("userController");
        Method method = (Method) mappingJSON.get(reqpath);
        try {//拦截请求找到实例对象的方法,并调用
            method.invoke(userController, req, resp);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
         // 包扫描,获取包中的文件
        scanPackage("com.rrg");
        System.out.println("【init】扫描包完成");
        try {
            filterAndInstance();
            System.out.println("【init】实例化(注解)完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 建立映射关系
        handerMap();
        System.out.println("【init】映射完成");
        // 实现注入
        DI();
        System.out.println("【init】属性注入完成");
    }

    /**
     * 扫描字段注解
     */
    private void DI() {
        if(instanceJSON.size() <= 0) {
            return ;
        }
        for (Map.Entry<String, Object> entry : instanceJSON.entrySet()) {
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                if(field.isAnnotationPresent(MyQulifier.class)) {
                    MyQulifier myQulifier = field.getAnnotation(MyQulifier.class);
                    String key = myQulifier.value();
                    field.setAccessible(true);
                    try {
                        field.set(entry.getValue(), instanceJSON.get(key));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * requestMapping
     */
    private void handerMap() {
        for (Map.Entry<String, Object> entry : instanceJSON.entrySet()) {
            if(entry.getValue().getClass().isAnnotationPresent(MyController.class)) {
                MyRequestMapping myRequestMapping = entry.getValue().getClass().getAnnotation(MyRequestMapping.class);
                String classMapping = myRequestMapping.value();
                //取得所有在
                Method[] methods = entry.getValue().getClass().getDeclaredMethods();
                for (Method method : methods) {
                    if(method.isAnnotationPresent(MyRequestMapping.class)) {
                        MyRequestMapping methodRequestMapping = method.getAnnotation(MyRequestMapping.class);
                        String methodMapping = methodRequestMapping.value();
                        mappingJSON.put(classMapping + methodMapping , method);
                    }else {
                        continue;
                    }
                }
            }
        }
    }

    /**
     * 实例化三层架构的实例化
     */
    private void filterAndInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //instanceJSON
        if(packageList.size()<=0) {
            return ;
        }
        for (String filePackage : packageList) {

            Class<?> fileClass = Class.forName(filePackage.replace(".class", "").trim());
            //判断类是否存在注释
            if(fileClass.isAnnotationPresent(MyController.class)) {
                Object newInstance = fileClass.newInstance();
                MyController myController = newInstance.getClass().getAnnotation(MyController.class);
                String key = myController.value();
                instanceJSON.put(key,newInstance);
            }else if(fileClass.isAnnotationPresent(MyService.class)) {
                Object newInstance = fileClass.newInstance();
                MyService myService = newInstance.getClass().getAnnotation(MyService.class);
                String key = myService.value();
                instanceJSON.put(key,newInstance);
            }else if(fileClass.isAnnotationPresent(MyMapper.class)) {
                Object newInstance = fileClass.newInstance();
                MyMapper myMapper = newInstance.getClass().getAnnotation(MyMapper.class);
                String key = myMapper.value();
                instanceJSON.put(key,newInstance);
            }else {
                continue;
            }
        }
    }

    private void scanPackage(String PACKAGE) {
        //    file:/C:/Users/abc/eclipse_0821/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/learning-again/WEB-INF/classes/com/rrg/
        URL url=this.getClass().getClassLoader().getResource("/" + replaceTo(PACKAGE));
        //    /C:/Users/abc/eclipse_0821/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/learning-again/WEB-INF/classes/com/rrg/
        String fileName = url.getFile();

        File file = new File(fileName);
        String[] list = file.list();
        for (String path : list) {
            File eachFile = new File(fileName + path);
            if(eachFile.isDirectory()) {
                scanPackage(PACKAGE + "." + eachFile.getName());
            }else {
                packageList.add(PACKAGE + "." + eachFile.getName());
            }
        }
    }

    /**
     * path中‘.‘转成‘/‘
     */
    private String replaceTo(String path) {
        return path.replaceAll("\\.", "/");
    }
}

4.2  统一处理请求

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>aaaa</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
      <servlet-name>MyDispatcherServlet</servlet-name>
      <servlet-class>com.rrg.ssm.core.MyDispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>MyDispatcherServlet</servlet-name>
      <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

5 测试

DEBUG AS=》 SERVER 访问 http://localhost:8080/user/get,

控制台打印

SUCCESS!

以上的源码借鉴博客  https://www.cnblogs.com/Shock-W/p/6617068.html

原文地址:https://www.cnblogs.com/cookwithme/p/8120448.html

时间: 2024-11-05 21:35:47

源码学习(一)——模拟Spring MVC的相关文章

springMvc源码学习之:spring源码总结

转载自:http://www.cnblogs.com/davidwang456/p/4213652.html spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.annotation, 支持包,提供对java 5注解处理bean样式的支持.org.springframework.beans.factory, 实现spring轻量级IoC容器的核心包.org.

spring源码学习之:spring容器的applicationContext启动过程

Spring 容器像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式进行工作.如果我们将Spring容器比喻为一辆汽车,可以将 BeanFactory看成汽车的发动机,而ApplicationContext则是 整辆汽车,它不但包括发动机,还包括离合器.变速器以及底盘.车身.电气设备等其他组件.在ApplicationContext内,各个组件按部就班. 有条不紊地完成汽车的各项功能. ApplicationContext内部封装 了一个BeanFactory对象

Spring源码学习之:你不知道的spring注入方式

前言 在Spring配置文件中使用XML文件进行配置,实际上是让Spring执行了相应的代码,例如: 使用<bean>元素,实际上是让Spring执行无参或有参构造器 使用<property>元素,实际上是让Spring执行一次setter方法 但Java程序还可能有其他类型的语句:调用getter方法.调用普通方法.访问类或对象的Field等,而Spring也为这种语句提供了对应的配置语法: 调用getter方法:使用PropertyPathFactoryBean 调用类或对象的

【mybatis源码学习】与spring整合Mapper接口执行原理

一.重要的接口 org.mybatis.spring.mapper.MapperFactoryBean MapperScannerConfigurer会向spring中注册该bean,一个mapper接口注册一个 该类是生产MapperProxy对象 org.apache.ibatis.binding.MapperProxy mapper接口的代理类 org.mybatis.spring.SqlSessionInterceptor sqlSession的动态代理类 org.mybatis.spr

spring源码学习(1)——spring整体架构和设计理念

Spring是在Rod Johnson的<Expert One-On-One J2EE Development and Design >的基础上衍生而来的.主要目的是通过使用基本的javabean来完成以前只能用EJB完成的事情降低企业应用的复杂性.这一系列源码学习是基于Spring-4.3.11版本的. 一.Spring的整体架构 如图所示,spring可以被总结为一下几个部分: (1)Core Container 为Spring的核心容器,包含Beans,Core,Context和SpEL

Spring 源码学习(一)

设计伊始       Spring 是为解决企业级应用开发的复杂性而设计,她可以做很多事.但归根到底支撑Spring的仅仅是少许的基本理念,而所有地这些的基本理念都能可以追溯到一个最根本的使命:简化开发.这是一个郑重的承诺,其实许多框架都声称在某些方面做了简化. 而Spring则立志于全方面的简化Java开发.对此,她主要采取了4个关键策略: 1,基于POJO的轻量级和最小侵入性编程: 2,通过依赖注入和面向接口松耦合: 3,基于切面和惯性进行声明式编程: 4,通过切面和模板减少样板式代码: 而

Spring源码学习笔记(1)

SpringMVC源码学习笔记(一) 前言----   最近花了些时间看了<Spring源码深度解析>这本书,算是入门了Spring的源码吧.打算写下系列文章,回忆一下书的内容,总结代码的运行流程.推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的<Spring源码深度解析>这本书,会是个很好的入门.  进入正文,首先贴上SpringMVC的图片(来自https://docs.spring.io/spring/docs/current/spring-framework

Spring源码学习笔记(6)

Spring源码学习笔记(六) 前言-- 最近花了些时间看了<Spring源码深度解析>这本书,算是入门了Spring的源码吧.打算写下系列文章,回忆一下书的内容,总结代码的运行流程.推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的<Spring源码深度解析>这本书,会是个很好的入门. 上一篇中我们梳理到 Spring 加载 XML 配置文件, 完成 XML 的解析工作,接下来我们将进入 Spring 加载 bean 的逻辑. 我们使用 Spring 获取 XML

Spring源码学习笔记(3)

Spring源码学习笔记(三) 前言----     最近花了些时间看了<Spring源码深度解析>这本书,算是入门了Spring的源码吧.打算写下系列文章,回忆一下书的内容,总结代码的运行流程.推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的<Spring源码深度解析>这本书,会是个很好的入门. DispatcherServlet 实现核心功能 和普通的 Servelt 类一样, DispatcherServlet 中的 doGet() 和 doPost() 方法

Spring源码学习的初步体会

Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spring的理解,在业务开发中使用spring更容易和深入,提高了生产率.