1. 程式人生 > >源碼學習(一)——模擬Spring MVC

源碼學習(一)——模擬Spring MVC

webapp lan conf 依賴 xtend .com inf pre 執行

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

源碼學習(一)——模擬Spring MVC