我在学习Spring的时候,感觉Spring是很难的,通过学习后,发现Spring没有那么难,只有你去学习了,你才会发现,你才会进步

1、手写Spring思路:

分为配置、初始化、运行三个阶段如下图

第一个阶段

配置阶段  web.xml配置,如下图

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><display-name>HandWriting Web Application</display-name><servlet><servlet-name>HandWriting MVC</servlet-name><servlet-class>com.wbg.framework.webmvc.servlet.HandWritingServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>application.properties</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>HandWriting MVC</servlet-name><url-pattern>/*</url-pattern></servlet-mapping>
</web-app>

View Code

 在resources写properties文件

内容是需要扫描的包的路径

scanPackage=com.wbg.demo

第二、三个阶段

1、在初始化前,将注解自定义,我现在写了5个常用的注解,这些注解都是自定仪,如下图:

HandWritingAutowired

package com.wbg.framework.webmvc.annotation;import java.lang.annotation.*;@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandWritingAutowired {String value() default "";
}

View Code

HandWritingController

package com.wbg.framework.webmvc.annotation;import java.lang.annotation.*;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandWritingController {String value() default "";
}

View Code

HandWritingRequestMapping

package com.wbg.framework.webmvc.annotation;import java.lang.annotation.*;@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandWritingRequestMapping {String value() default "";
}

View Code

HandWritingRequestParam

package com.wbg.framework.webmvc.annotation;import java.lang.annotation.*;@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandWritingRequestParam {String value() default "";
}

View Code

HandWritingService

package com.wbg.framework.webmvc.annotation;import java.lang.annotation.*;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandWritingService {String value() default "";
}

View Code

2、初始化阶段  init(ServletConfig config)

继承HttpServlet,重写init

3、运行阶段 doGet、doPost

继承HttpServlet,重写doGet、doPost

我这里创建一个 HandWritingServlet类继承HttpServlet

package com.wbg.framework.webmvc.servlet;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.IOException;public class HandWritingServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}@Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);}
}

View Code

  • 1、加载配置文件 获取web.xml文件的的param-name
  • 2、扫描所有相关联的类 //配置文件的scanPackage = com...
  • 3、初始化所有相关的类,并且将其保存到IOC容器之中
  • 4、执行依赖注入(把加了@Autoidwired注解的字段赋值)
  • 5、构造HandlerMapping,将URL和Method进行关联

运行阶段(doGet/doPost)

  • 1、通过request获得url,然后再去HandlerMapping
  • 2、用反射调用Method
  • 3、response.writer()

代码如下

package com.wbg.framework.webmvc.servlet;import com.wbg.framework.webmvc.annotation.*;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.Method;
import java.net.URL;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class HandWritingServlet extends HttpServlet {//配置文件private Properties contextConfig = new Properties();//存配置文件 scanPackage=com.wbg.demo 下所有的类名private List<String> classNames = new ArrayList<String>();//IOC容器private Map<String, Object> ioc = new HashMap<String, Object>();//保存所有的URL和方法的映射关系private List<Handler> handlerMapping = new ArrayList<Handler>();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) {try {doDispatch(req, resp);} catch (Exception e) {try {resp.getWriter().write("500 =========" + e);} catch (IOException e1) {e1.printStackTrace();}}}/*** 初始化,加载配置* @param config 配置文件*/@Overridepublic void init(ServletConfig config) {System.out.println("======初始化配置文件======");//1、加载配置文件  获取web.xml文件的的param-namedoLoadConfig(config.getInitParameter("contextConfigLocation"));//2、扫描所有相关联的类 //配置文件的scanPackage = com...doScanner(contextConfig.getProperty("scanPackage"));//3、初始化所有相关的类,并且将其保存到IOC容器之中
        doInstance();//4、执行依赖注入(把加了@Autoidwired注解的字段赋值)
        doAutoWired();//-------------------------Spring的核心功能已经完成  IOC  DI注入//5、构造HandlerMapping,将URL和Method进行关联
        initHandlerMapping();System.out.println("=========启动完毕============");}/*** 构造HandlerMapping,将URL和Method进行关联*/private void initHandlerMapping() {if (ioc.isEmpty()) {return;}for (Map.Entry<String, Object> entry : ioc.entrySet()) {Class<?> clazz = entry.getValue().getClass();//如果该类上没有Controller  下一个if (!clazz.isAnnotationPresent(HandWritingController.class)) {continue;}String baseUrl = "";//如果该类上有RequestMapping注解if (clazz.isAnnotationPresent(HandWritingRequestMapping.class)) {HandWritingRequestMapping requestMapping = clazz.getAnnotation(HandWritingRequestMapping.class);//获取RequestMapping注解的值baseUrl = requestMapping.value();}//获取该类的所有方法Method[] methods = clazz.getMethods();for (Method method : methods) {//如果该方法上面没有RequestMapping 下一个if (!method.isAnnotationPresent(HandWritingRequestMapping.class)) {continue;}HandWritingRequestMapping requestMapping = method.getAnnotation(HandWritingRequestMapping.class);//获取RequestMapping注解的值String regex = requestMapping.value();//将 类上、方法上 的RequestMapping 注解相加  得到一个urlregex = (baseUrl + regex).replaceAll("/+", "/");Pattern pattern = Pattern.compile(regex);handlerMapping.add(new Handler(pattern, entry.getValue(), method));System.out.println("handlerMapping:" + regex);}}}/*** 执行依赖注入 将加了AutoWired注解的字段进行赋值* 注入的意思就是把所有IOC容器中加了@Autowired注解的字段全部赋值*/private void doAutoWired() {if (ioc.isEmpty()) {return;}for (Map.Entry<String, Object> entry : ioc.entrySet()) {//获取该类的声明字段 包过私有的字段Field[] fields = entry.getValue().getClass().getDeclaredFields();//循环加入IOC容器for (Field field : fields) {//如果字段不加Autowired注解  下一个if (!field.isAnnotationPresent(HandWritingAutowired.class)) {continue;}//获取这个字段上的Autowired注解HandWritingAutowired autowired = field.getAnnotation(HandWritingAutowired.class);//获取注解上的valueString beanName = autowired.value().trim();//如果为空if ("".equals(beanName)) {//获取这个字段的名字beanName = field.getType().getName();}//如果这个字段是私有的字段,强制访问field.setAccessible(true);try {//赋值
                    field.set(entry.getValue(), ioc.get(beanName));} catch (IllegalAccessException e) {e.printStackTrace();}}}}/*** 初始化所有相关的类* 加了注解的才初始化*/private void doInstance() {if (classNames.isEmpty()) {return;}for (String className : classNames) {try {Class<?> clazz = Class.forName(className);//只有加了注解的  才初始化if (clazz.isAnnotationPresent(HandWritingController.class)) {Object instance = clazz.newInstance();String beanName = lowerFirstClass(clazz.getSimpleName());ioc.put(beanName, instance);} else if (clazz.isAnnotationPresent(HandWritingService.class)) {HandWritingService service = clazz.getAnnotation(HandWritingService.class);//2、自定义命名,优先使用自定义命名String beanName = service.value();//1、默认类名首字母小写if ("".equals(beanName.trim())) {beanName = lowerFirstClass(clazz.getSimpleName());}Object instance = clazz.newInstance();ioc.put(beanName, instance);// 3、自动类型匹配(例如将实现类赋值给接口)Class<?>[] instances = clazz.getInterfaces();for (Class<?> i : instances) {ioc.put(i.getName(), instance);}} else {continue;}} catch (Exception e) {e.printStackTrace();}}}/*** 将字符串的首字母变成小写  利用ASCII转换* @param simpleName* @return*/private String lowerFirstClass(String simpleName) {char[] c = simpleName.toCharArray();c[0] += 32;return String.valueOf(c);}protected void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {Handler handler = getHandler(req);//如果为空  没有这个请求路径if (handler == null) {resp.getWriter().write("=========handWritingSpring=============404==========");return;}try {//获取方法的参数列表Class<?>[] paramTypes = handler.method.getParameterTypes();//保存所有需要自动赋值的参数值Object[] paramValues = new Object[paramTypes.length];//获取方法上的参数Map<String, String[]> params = req.getParameterMap();for (Map.Entry<String, String[]> param : params.entrySet()) {//转换为String 去掉数组[]两边 去掉字符的空白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);}int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());paramValues[reqIndex] = req;int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());paramValues[respIndex] = resp;handler.method.invoke(handler.controller, paramValues);} catch (Exception e) {throw e;}}private Handler getHandler(HttpServletRequest req) throws Exception {if (handlerMapping.isEmpty()) {return null;}String url = req.getRequestURI();String contextPath = req.getContextPath();url = url.replaceAll(contextPath, "").replaceAll("/+", "/");for (Handler handler : handlerMapping) {try {Matcher matcher = handler.pattern.matcher(url);//如果没有匹配上继续下一个匹配if (!matcher.matches()) {continue;}return handler;} catch (Exception e) {throw e;}}return null;}/*** 转换类型Integer* @param type* @param value* @return*/private Object convert(Class<?> type, String value) {if (Integer.class == type) {return Integer.valueOf(value);}return value;}/*** 扫描basePackage路径下所以的类* @param basePackage*/private void doScanner(String basePackage) {//获取路径URL url = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));File dir = new File(url.getFile());for (File file : dir.listFiles()) {//如果是一个文件夹if (file.isDirectory()) {//递归doScanner(basePackage + "." + file.getName());} else {//获取类名String className = basePackage + "." + file.getName().replace(".class", "");//将所有项目所有类存起来
                classNames.add(className);}}}/*** 加载配置文件* @param contextConfigLocation*/private void doLoadConfig(String contextConfigLocation) {InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);try {contextConfig.load(is);} catch (IOException e) {e.printStackTrace();} finally {if (null != is) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}}/*** Handler记录Controller中的RequestMapping和Method对应的关系*/private class Handler {protected Object controller; //保存方法对应的实例protected Method method; //保存映射的方法protected Pattern pattern;  //RequestMapping存的URLprotected Map<String, Integer> paramIndexMapping; //参数顺序/*** 基本参数* @param pattern* @param controller* @param method*/protected Handler(Pattern pattern, Object controller, Method method) {this.pattern = pattern;this.controller = controller;this.method = method;paramIndexMapping = new HashMap<String, Integer>();putParamIndexMapping(method);}/*** 保存RequestParam注解的参数值* @param method 类的方法*/private void putParamIndexMapping(Method method) {//获取方法中加了注解的参数Annotation[][] pa = method.getParameterAnnotations();for (int i = 0; i < pa.length; i++) {for (Annotation annotation : pa[i]) {//如果使用到了HandWritingRequestParam注解if (annotation instanceof HandWritingRequestParam) {//获取该注解的值String paramName = ((HandWritingRequestParam) annotation).value();//如果这个值不为空if (!"".equals(paramName.trim())) {//保存参数
                            paramIndexMapping.put(paramName, i);}}}}//提取方法中的request和response参数Class<?>[] paramsTypes = method.getParameterTypes();for (int i = 0; i < paramsTypes.length; i++) {Class<?> type = paramsTypes[i];if (type == HttpServletRequest.class || type == HttpServletResponse.class) {paramIndexMapping.put(type.getName(), i);}}}}
}

View Code

以上代码完成后Spring就ok了,现在开始使用,我写的demo如下:

1、首先创建接口  DemoService

public interface DemoService {String get(String name);String sum(int a,int b);String remove(String id);
}

2、在类上使用刚刚自定义的注解  @HandWritingService  调用DemoService

@HandWritingService
public class DemoServiceImp implements DemoService {public String get(String name) {return "My name is " + name;}public String sum(int a,int b) {return "a + b = " + (a+b);}public String remove(String id) {return "remove id = " + id;}
}

3、开始写Controll控制器

1、在类上使用 @HandWritingController 相当于 Controlle

    @HandWritingRequestMapping 相当于RequestMapping

2、字段 注入   @HandWritingAutowired  相当于 Autowired

3、方法上使用 @HandWritingRequestMapping("/sum.json") 和类上一样,当然可以写一个注解 GetRequestMapping  get请求

4、参数上使用 @HandWritingRequestParam("name")  相当于 RequestParam

代码如下:

package com.wbg.demo.mvc.action;import com.wbg.demo.service.DemoService;
import com.wbg.framework.webmvc.annotation.HandWritingAutowired;
import com.wbg.framework.webmvc.annotation.HandWritingController;
import com.wbg.framework.webmvc.annotation.HandWritingRequestMapping;
import com.wbg.framework.webmvc.annotation.HandWritingRequestParam;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@HandWritingController
@HandWritingRequestMapping("/demo")
public class DemoAction {@HandWritingAutowiredprivate DemoService demoService;@HandWritingRequestMapping("/query.json")public void query(HttpServletRequest req, HttpServletResponse resp, @HandWritingRequestParam("name")String name){String result =  demoService.get(name);try{resp.getWriter().write(result);}catch (IOException e){e.printStackTrace();}}@HandWritingRequestMapping("/sum.json")public void sum(HttpServletRequest req, HttpServletResponse resp, @HandWritingRequestParam("a") Integer a, @HandWritingRequestParam("b") Integer b){String result =  demoService.sum(a,b);try{resp.getWriter().write(result);}catch (IOException e){e.printStackTrace();}}@HandWritingRequestMapping("/remove.json")public void remove(HttpServletRequest req, HttpServletResponse resp, @HandWritingRequestParam("id") String id){String result =  demoService.remove(id);try{resp.getWriter().write(result);}catch (IOException e){e.printStackTrace();}}
}

View Code

现在启动服务,验证一下,如下图

项目demo:https://github.com/weibanggang/handwritingspring

对你有帮助,麻烦点下星,谢谢

手写Spring+demo+思路相关推荐

  1. 记录一次阿里架构师全程手写Spring MVC

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  2. 十年java架构师分享:我是这样手写Spring的

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  3. 手写 Spring MVC

    学习自<Spring 5核心原理与30个类手写实战>作者 Tom 老师 手写 Spring MVC 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背 ...

  4. JAVA项目代码手写吗_一个老程序员是如何手写Spring MVC的

    见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多 ...

  5. 05. 手写Spring核心框架

    目录 05 手写Spring核心框架 Pt1 手写IoC/DI Pt1.1 流程设计 Pt1.2 基础配置 application.properties pom.xml web.xml Pt1.3 注 ...

  6. 手写 Spring 事务、IOC、DI 和 MVC

    Spring AOP 原理 什么是 AOP? AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率 应用场景:日志记录,性能统计,安全控制,事务处理,异常处理 AOP 底 ...

  7. 从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器

    手写Spring之集成Tomcat与Servlet 写在前面 一.Web服务模型及servlet 1.1 Web服务器 1.2 请求流程 二.实现 三.小结 写在前面 最近学习了一下spring的相关 ...

  8. 手把手教你手写Spring框架

    手写spring准备工作: 新建一个maven工程: 架构 新建类: package com.spring;public class keweiqinApplicationContext {priva ...

  9. 手写Spring DI依赖注入,嘿,你的益达!

    手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...

  10. Qt5.9一个简单的手写界面demo

    本文主要总结一个最简单的手写界面demo,具体代码如下. 1.1新建一个widget工程,不要勾选ui界面.然后分别在widget.h.widget.cpp.main.cpp分别添加如下代码. wid ...

最新文章

  1. HBase数据压缩编码探索
  2. MySQL数据单个数据太大,导入不进去
  3. 文本编辑器创建状态栏
  4. java 容器 线程_JAVA多线程并发容器
  5. 直击Titan图数据库:如何提升25%+的反欺诈检测效率?
  6. wxWidgets:wxPGMultiButton类用法
  7. 在linux中加固mysql_mysql在linux下的安装
  8. 荷兰牛栏 荷兰售价_荷兰研究小组授予的数据共享项目
  9. 基础IO(文件接口、安装内核源码超详细步骤图解、静态库与动态库)
  10. Yum未完成事务问题
  11. linux mutt 使用指南,linux mutt详解
  12. java mysql备份_java调用mysql服务做备份与恢复
  13. CCNA3.0中文版教材
  14. uniapp 打包成微信小程序
  15. [Unity][NGUI]Sprite精灵的Type九宫格切割Sliced没效果
  16. 《把信送给加西亚》读书笔记(摘抄)
  17. Unity的一些特效和粒子特效插件
  18. 信息系统项目管理师Part15-EAI企业应用系统集成
  19. Python 3.0 抢“鲜”体验
  20. centos7 应用笔记: 添加 编辑 Applications 菜单 功能

热门文章

  1. 基于图像gist特征的NWPU-RESISC45数据分类实战
  2. pyspark分类算法之决策树分类器模型实践【decisionTreeClassifier】
  3. VHDL计算机硬件能直接执行吗,第5章 VHDL程序结构.ppt
  4. at shutdown 不起作用_at胎是什么胎
  5. java 有界泛型_JAVA泛型中的有界类型(extends super)
  6. 将Excel数据批量导入到数据库(项目案例)
  7. python语法学习第十天--类与对象
  8. html span设置外边距,行内元素内外边距探究:为何span设置上下margin和padding不起效...
  9. 【mybatis】基础环境搭建
  10. Java中栈和队列的类