ssm框架requestmapping找不到_从MVC原理开始手敲一个MVC框架,带你体会当大神的乐趣...
每一个程序员,在刚入行时学的第一个框架应该就是ssm了,其他的各种学习框架都是后期在工作中,随着业务的不断复杂,在工作和bug中不断成长起来的,但是最经典的应该还是最一开始的时候ssm框架吧
当时刚学习这个时候,就觉得,好牛啊,这样就可以实现一个网站,这群大神是怎么做到的啊,嘿嘿嘿,不知道大家当时有没有这样的问题产生,所以今天就带大家来搭建一个简单的mvc框架,从原理讲起,也能帮助大家更好的理解底层源码
好了,话不多说,我们来看一下
Springmvc基本原理流程
SpringMvc本质上就是对Servlet的封装。
因为创建一个Maven项目,然后在pom文件中增加一个依赖:
<dependency><groupId>javax.servletgroupId><artifactId>servlet-apiartifactId><version>2.5version>
<scope>providedscope>dependency>
2,创建DispatcherServlet,并注册到web.xml中
package com.dxh.edu.mvcframework.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 DxhDispatcherServlet extends HttpServlet {/** * 接收处理请求 */@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); }@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}}
web.xml:
span style="border-width: 0px;border-style: initial;border-color: initial;">web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Applicationdisplay-name><servlet><servlet-name>dxhmvcservlet-name><servlet-class>com.dxh.edu.mvcframework.servlet.DxhDispatcherServletservlet-class><init-param><param-name>contextConfigLocationparam-name><param-value>springmvc.propertiesparam-value>init-param>servlet><servlet-mapping><servlet-name>dxhmvcservlet-name><url-pattern>/*url-pattern>servlet-mapping>web-app>
2,注解开发
因为要使用到注解,所以首先要自定义几个注解:
这里就不赘述如何自定义注解了,详情请看:https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
Controller注解:
@Documented@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DxhController { String value() default "";}
Service注解:
@Documented@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DxhService { String value() default "";}
RequestMapping注解:
@Documented@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface DxhRequestMapping { String value() default "";}
Autowired注解:
@Documented@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DxhAutowired { String value() default "";}
编写测试代码:
测试代码我们放在同项目中的com.dxh.demo包中:
package com.dxh.demo.controller;import com.dxh.demo.service.IDemoService;import com.dxh.edu.mvcframework.annotations.DxhAutowired;import com.dxh.edu.mvcframework.annotations.DxhController;import com.dxh.edu.mvcframework.annotations.DxhRequestMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@DxhController@DxhRequestMapping("/demo")public class DemoController {@DxhAutowired private IDemoService demoService;/** * URL:/demo/query */@DxhRequestMapping("/query") public String query(HttpServletRequest request, HttpServletResponse response, String name){return demoService.get(name); }}
package com.dxh.demo.service;public interface IDemoService {String get(String name);}
package com.dxh.demo.service.impl;import com.dxh.demo.service.IDemoService;import com.dxh.edu.mvcframework.annotations.DxhService;@DxhService("demoService")public class IDemoServiceImpl implements IDemoService {@Override public String get(String name) {System.out.println("Service实现类中的Name:"+ name);return name; }}
目录结构:
3,编写自定义DispatcherServlet中的初始化流程:
在创建好的DxhDispatcherServlet中重写init()方法,并在init方法中做初始化配置:
加载配置文件 springmvc.properties
扫描相关的类——扫描注解
初始化Bean对象(实现IOC容器,基于注解)
实现依赖注入
构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系
@Overridepublic void init(ServletConfig config) throws ServletException {//1. 加载配置文件 springmvc.properties String contextConfigLocation = config.getInitParameter("contextConfigLocation"); doLoadConfig(contextConfigLocation);//2. 扫描相关的类——扫描注解 doScan("");//3. 初始化Bean对象(实现IOC容器,基于注解) doInstance();//4. 实现依赖注入 doAutoWired();//5. 构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系 initHandleMapping(); System.out.println("MVC 初始化完成");//6. 等待请求进入处理请求}
以及5个空方法,这篇文章自定义MVC框架其实就是需要对这5个步骤的编写。
//TODO 5,构造一个映射器private void initHandleMapping() {}//TODO 4,实现依赖注入private void doAutoWired() {}//TODO 3,IOC容器private void doInstance() {}//TODO 2,扫描类private void doScan(String scanPackage) {}//TODO 1,加载配置文件private void doLoadConfig(String contextConfigLocation) {}
3.1 加载配置文件
首先在resource目录中创建一个配置文件——springmvc.properties
表示要扫描com.dxh.demo下的所有注解。然后在web.xml中进行配置:
这样,就可以通过config.getInitParameter("contextConfigLocation")获得这个路径。
在DxhDispatcherServlet中定义一个属性,我们把加载后的配置文件中的信息,存储在Properties 中
private Properties properties = new Properties();;
//1,加载配置文件private void doLoadConfig(String contextConfigLocation) {//根据指定路径加载成流: InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);try { properties.load(resourceAsStream); } catch (IOException e) { e.printStackTrace(); }}
3.2 扫描相关的类,扫描注解
上一步骤,我们已经把需要扫描的包存在Properties中,所以这里需要取出:
//2. 扫描相关的类——扫描注解doScan(properties.getProperty("scanPackage"));
把扫描到的类型的全类名存在一个List中缓存起来,等待使用,在DxhDispatcherServlet中定义一个list:
//缓存扫描到的类的全类名private List classNames = new ArrayList<>();
从配置文件中我们得到了一个需要扫描的包名(com.dxh.demo),我们需要根据classPath+包名,来得到它实际上在磁盘上存的路径,然后递归,直到把所有的该包下(包括子包...)所有的类文件(.class结尾)。然后存在在List classNames中。
//2,扫描类//scanPackage :com.dxh.demo package--->磁盘的文件夹(File)private void doScan(String scanPackage) {//1.获得classPath路径String clasPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();//2.拼接,得到scanPackage在磁盘上的路径String scanPackagePath= clasPath + scanPackage.replaceAll("\\.","/"); File pack = new File(scanPackagePath); File[] files = pack.listFiles();for (File file : files) {if (file.isDirectory()){ //子 package//递归 doScan(scanPackage+"."+file.getName()); //com.dxh.demo.controller }else if(file.getName().endsWith(".class")){String className = scanPackage + "." + file.getName().replace(".class", ""); classNames.add(className); } }}
3.3 初始化Bean对象(实现IOC容器,基于注解)
上一步骤我们把扫描到的类的全类名放到了,list中,那么本次步骤需要遍历整个list:
遍历List,依次得到所有的全类名
通过反射得到类对象
根据类对象判断有没有注解,并区分controller和servicecontroller,它的id此处不做过多处理,不取value了,用类的首字母小写作为id,保存到IOC容器中。service,service层往往是有接口的,再以接口名为id再存入一份bean到ioc,便于后期根据接口类型注入
完成
代码实现:
//IOC容器private Map<String,Object> ioc = new HashMap<>();
//3,IOC容器//基于classNames缓存的类的全限定类名,以及反射技术,完成对象创建和管理private void doInstance() {if (classNames.size()==0) return;try{for (int i = 0; i < classNames.size(); i++) { String className = classNames.get(i); //com.dxh.demo.controller.DemoController//反射 Class> aClass = Class.forName(className);//区分controller ,区分serviceif (aClass.isAnnotationPresent(DxhController.class)){//controller的id此处不做过多处理,不取value了,用类的首字母小写作为id,保存到IOC容器中 String simpleName = aClass.getSimpleName();//DemoController String lowerFirstSimpleName = lowerFirst(simpleName); //demoController Object bean = aClass.newInstance(); ioc.put(lowerFirstSimpleName,bean); }else if (aClass.isAnnotationPresent(DxhService.class)){ DxhService annotation = aClass.getAnnotation(DxhService.class);//获取注解的值 String beanName = annotation.value();//指定了id就以指定的id为准if (!"".equals(beanName.trim())){ ioc.put(beanName,aClass.newInstance()); }else{//没有指定id ,首字母小写 String lowerFirstSimpleName = lowerFirst(aClass.getSimpleName()); ioc.put(lowerFirstSimpleName,aClass.newInstance()); }//service层往往是有接口的,再以接口名为id再存入一分bean到ioc,便于后期根据接口类型注入 Class>[] interfaces = aClass.getInterfaces();for (Class> anInterface : interfaces) {//以接口的类名作为id放入。 ioc.put(anInterface.getName(),aClass.newInstance()); } }else {continue; } } }catch (Exception e){ e.printStackTrace(); }}
3.4 实现依赖注入:
上一步骤把所有需要加载的bean,存入了ioc Map中,此时,我们就需要遍历这个map然后依次得到每个bean对象,然后判断对象中有没有被@****DxhAutowired修饰的属性。
遍历ioc这个map,得到每个对象
获取对象的字段(属性)信息
判断字段是否被@DxhAutowired修饰
判断@DxhAutowired有没有设置value值有,直接从ioc容器中取出,然后设置属性。无,需要根据当前字段的类型注入(接口注入)
代码实现:
//4,实现依赖注入private void doAutoWired() {if (ioc.isEmpty()){return;}//1,判断容器中有没有被@DxhAutowried注解的属性,如果有需要维护依赖注入关系for (Map.Entry entry: ioc.entrySet()){//获取bean对象中的字段信息 Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();for (Field declaredField : declaredFields) {if (!declaredField.isAnnotationPresent(DxhAutowired.class)){continue; }//有该注解: DxhAutowired annotation = declaredField.getAnnotation(DxhAutowired.class); String beanName = annotation.value(); //需要注入的bean的Idif ("".equals(beanName.trim())){//没有配置具体的beanId,需要根据当前字段的类型注入(接口注入) IDemoService beanName = declaredField.getType().getName(); }//开启赋值 declaredField.setAccessible(true);try {//字段调用,两个参数:(哪个对象的字段,传入什么) declaredField.set(entry.getValue(),ioc.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); } } }}
3.5 构造一个handleMapping处理器映射器
构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系****。
手写MVC框架最关键的环节
假设有一个:
那么如何通过/demo/query定位到 DemoController类中的query这个方法 ?
之前我们所有被@DxhController(自定义Controller注解)的类,都存在了ioc 这个map中。
我们可以遍历这个map,得到每个bean对象
然后判断是否被@DxhController所修饰(排除@DxhService所修饰的bean)
然后判断是否被@DxhRequestMapping所修饰,有的话,就取其value值,作为baseUrl
然后遍历该bean对象中的所有方法,得到被@DxhRequestMapping修饰的方法。得到其value值,作为methodUrl。
baseUrl + methodUrl = url
我们把url和当前method绑定起来,存在map中,也就是建立了url和method建立映射关系。代码实现:
//handleMapping ,存储url和method直接的映射关系private Map<String,Object> handleMapping = new HashMap<>();
//5,构造一个映射器,将url和method进行关联private void initHandleMapping() {if (ioc.isEmpty()){return;}for (Map.Entry entry: ioc.entrySet()){//获取ioc中当前遍历对象的class类型 Class> aClass = entry.getValue().getClass();//排除非controller层的类if (!aClass.isAnnotationPresent(DxhController.class)){continue; } String baseUrl = "";if (aClass.isAnnotationPresent(DxhRequestMapping.class)){//Controller层 类上 注解@DxhRequestMapping中的value值 baseUrl = aClass.getAnnotation(DxhRequestMapping.class).value(); }//获取方法 Method[] methods = aClass.getMethods();for (Method method : methods) {//排除没有@DxhRequestMapping注解的方法if (!method.isAnnotationPresent(DxhRequestMapping.class)){continue;}//Controller层 类中方法上 注解@DxhRequestMapping中的value值 String methodUrl = method.getAnnotation(DxhRequestMapping.class).value(); String url = baseUrl+methodUrl;//建立url和method之间的映射关系,用map缓存起来 handleMapping.put(url,method); } }}
4,测试一下:
到目前位置,还没有完全写完,但是不妨碍我们测试一下看看刚才写的那部分内容有没有什么问题:
完整的pom文件:
<?xml version="1.0" encoding="UTF-8"?><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.0modelVersion><groupId>com.dxh.edugroupId><artifactId>mvcartifactId><version>1.0-SNAPSHOTversion><packaging>warpackaging><name>mvc Maven Webappname><url>http://www.example.comurl><properties><project.build.sourceEncoding>UTF-8project.build.sourceEncoding><maven.compiler.source>11maven.compiler.source><maven.compiler.target>11maven.compiler.target>properties><dependencies><dependency><groupId>junitgroupId><artifactId>junitartifactId><version>4.12version><scope>testscope>dependency><dependency><groupId>javax.servletgroupId><artifactId>servlet-apiartifactId><version>2.5version>
<scope>providedscope>dependency>dependencies><build><plugins><plugins>
<plugin><groupId>org.apache.maven.pluginsgroupId><artifactId>maven-compiler-pluginartifactId><version>3.2version><configuration><source>11source><target>11target><encoding>utf-8encoding>
<compilerArgs><arg>-parametersarg>compilerArgs>configuration>plugin> <plugin><groupId>org.apache.tomcat.mavengroupId><artifactId>tomcat7-maven-pluginartifactId><version>2.2version><configuration><port>8080port><path>/path>configuration>plugin>plugins>build>project>
pom文件中加入了一个tomcat插件,并设置端口为8080,因此我们通过tomcat启动项目:
启动完成后,打开浏览器url中输入:
http://localhost:8080/demo/query
浏览器中什么都没返回(我们的代码还没真正的完成,尚未编写处理请求步骤),同时控制台中打印了MVC初始化完成,可以认为,目前的代码没有明显的缺陷。我们继续~~~~~
5,改造initHandleMapping()
5.1 为什么改造?
DxhDispatcherServlet这个类继承了HttpServlet,并重写了doGet和doPost方法,在doGet中调用了doPost方法,当我们使用反射调用方法时(method.invoke(......))发现少了一部分参数:
因此我们要改造initHandleMapping(),修改url和method的映射关系(不简简单单的存入map中)。
5.2 新建Handler类
package com.dxh.edu.mvcframework.pojo;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.regex.Pattern;public class Handler {//method.invoke(obj,)需要private Object controller;private Method method;//spring中url支持正则private Pattern pattern;//参数的顺序,为了进行参数绑定 ,Key 参数名, Value 代表第几个参数private Map paramIndexMapping;public Handler(Object controller, Method method, Pattern pattern) {this.controller = controller;this.method = method;this.pattern = pattern;this.paramIndexMapping = new HashMap<>(); }//getset方法这里省略,实际代码中需要...}
在Handler类中编写了4个属性:
private Object controller:method.invoke(obj,)需要
private Method method:与url绑定的方法
private Pattern pattern:可以通过正则匹配,也可以直接写String url。
private Map paramIndexMapping:参数的顺序,为了进行参数绑定 ,Key 参数名, Value 代表第几个参数
5.3 修改initHandleMapping()
首先,就不能直接通过Map的得方式进行关系映射了,使用一个list,泛型是刚才创建的Handler。
//handleMapping ,存储url和method直接的映射关系// private Map handleMapping = new HashMap<>();private List handlerMapping = new ArrayList<>();
改动前,改动后代码对比:
改动后的initHandleMapping():
//5,构造一个映射器,将url和method进行关联private void initHandleMapping() {if (ioc.isEmpty()){return;}for (Map.Entry entry: ioc.entrySet()){//获取ioc中当前遍历对象的class类型 Class> aClass = entry.getValue().getClass();//排除非controller层的类if (!aClass.isAnnotationPresent(DxhController.class)){continue; } String baseUrl = "";if (aClass.isAnnotationPresent(DxhRequestMapping.class)){//Controller层 类上 注解@DxhRequestMapping中的value值 baseUrl = aClass.getAnnotation(DxhRequestMapping.class).value(); }//获取方法 Method[] methods = aClass.getMethods();for (Method method : methods) {//排除没有@DxhRequestMapping注解的方法if (!method.isAnnotationPresent(DxhRequestMapping.class)){continue;}//Controller层 类中方法上 注解@DxhRequestMapping中的value值 String methodUrl = method.getAnnotation(DxhRequestMapping.class).value(); String url = baseUrl+methodUrl;//把method所有信息以及url封装为Handler Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url));//处理计算方法的参数位置信息 Parameter[] parameters = method.getParameters();for (int i = 0; i < parameters.length; i++) { Parameter parameter = parameters[i];//不做太多的参数类型判断,只做:HttpServletRequest request, HttpServletResponse response和基本类型参数if (parameter.getType()==HttpServletRequest.class||parameter.getType()==HttpServletResponse.class){//如果时request和response对象,那么参数名称存 HttpServletRequest 和 HttpServletResponse handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),i); }else{ handler.getParamIndexMapping().put(parameter.getName(),i); } } handlerMapping.add(handler); } }}
6, 请求处理开发 doPost():
上一步骤,我们配置了 uri和method的映射关系,并封装到了Handler中存入list,那么接下来,就要通过HttpServletRequest,取出uri,然后找到具体的Handler:
通过HttpServletRequest取出uri找到具体的Handler
得到将调用方法的参数的数组
根据上述数组长度创建一个新的数组(参数数组,传入反射调用的)
通过req.getParameterMap()得到前台传来的参数parameterMap
遍历parameterMap
通过StringUtils.join方法把name=1&name=2格式的参数变为name[1,2] (需要commons-lang依赖)
参数匹配并设置
private Handler getHandler(HttpServletRequest req) {if (handlerMapping.isEmpty()){return null;} String url = req.getRequestURI();//遍历 handlerMappingfor (Handler handler : handlerMapping) { Matcher matcher = handler.getPattern().matcher(url);if (!matcher.matches()){continue;}return handler; }return null;}
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {//根据uri获取到能够处理当前请求的Handler(从handlerMapping中(list)) Handler handler = getHandler(req);if (handler==null){ resp.getWriter().write("404 not found");return; }//参数绑定//该方法所有参数得类型数组 Class>[] parameterTypes = handler.getMethod().getParameterTypes();//根据上述数组长度创建一个新的数组(参数数组,传入反射调用的)Object[] paramValues = new Object[parameterTypes.length];//以下就是为了向参数数组中设值,而且还得保证参数得顺序和方法中形参顺序一致。Map<String,String[]> parameterMap = req.getParameterMap();//遍历request中所有的参数 ,(填充除了request、response之外的参数)for (Map.Entry<String,String[]> entry: parameterMap.entrySet()){//name=1&name=2 name[1,2]String value = StringUtils.join(entry.getValue(), ",");// 如同 1,2//如果参数和方法中的参数匹配上了,填充数据if (!handler.getParamIndexMapping().containsKey(entry.getKey())){continue;}//方法形参确实有该参数,找到它得索引位置,对应得把参数值放入paramValues Integer index = handler.getParamIndexMapping().get(entry.getKey());//把前台传递过来的参数值,填充到对应得位置去 paramValues[index] = value; } Integer requestIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName()); paramValues[requestIndex] = req; Integer responseIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName()); paramValues[responseIndex] = resp;//最终调用handler得method属性try {Object invoke = handler.getMethod().invoke(handler.getController(), paramValues);//简单操作,把方法返回的数据以字符串的形式写出resp.getWriter().write(invoke.toString()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
7,测试:
打开浏览器,url中输入:http://localhost:8080/demo/query?name=lisi
返回:
控制台中打印出:
OK完成~
而这一些都是基于对于spring底层原理有一定程度的理解上进行的,当你完整实现这个项目之后,你就能够对于spring有一个全新的理解
点个在看 你最好看
往期推荐
终于有人把Java8和Spring5完美合体了,业界堪称神迹
腾讯强推Redis成长手册!原理+应用+集群+拓展+源码五飞
阿里要求其程序员必须精通的并发编程笔记:原理+模式+应用
饿了么架构师发布“绝版”Java并发实现原理:JDK源码剖析
不吹不擂,10年架构师公开分享SQL工作笔记,5字真言总结到位
由浅入深吃透容器云+微服务+K8S+MQ+阿里云内部实施手册
ssm框架requestmapping找不到_从MVC原理开始手敲一个MVC框架,带你体会当大神的乐趣...相关推荐
- ssm框架requestmapping找不到_框架学习,就是介么简单
框架学习 程序员凯小白 最近实训ssm框架,SSM框架,是Spring + Spring MVC + MyBatis的缩写,这个是继SSH之后,目前比较主流的Java EE企业级框架,适用于搭建各种大 ...
- 【RPC框架、RPC框架必会的基本知识、手写一个RPC框架案例、优秀的RPC框架Dubbo、Dubbo和SpringCloud框架比较】
一.RPC框架必会的基本知识 1.1 什么是RPC? RPC(Remote Procedure Call --远程过程调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络的技术. ...
- 手写一个RPC框架,理解更透彻(附源码)
作者:烟味i www.cnblogs.com/2YSP/p/13545217.html 一.前言 前段时间看到一篇不错的文章<看了这篇你就会手写RPC框架了>,于是便来了兴趣对着实现了一遍 ...
- 面试官让我手写一个RPC框架
如今,分布式系统大行其道,RPC 有着举足轻重的地位.Dubbo.Thrift.gRpc 等框架各领风骚,学习RPC是新手也是老鸟的必修课.本文带你手撸一个rpc-spring-starter,深入学 ...
- 一个connection对象可以创建一个或一个以上的statement对象_从 0 开始手写一个 Mybatis 框架,三步搞定...
来自:开源中国,作者:我叫刘半仙 链接:https://my.oschina.net/liughDevelop/blog/1631006 MyBatis框架的核心功能其实不难,无非就是动态代理和jdb ...
- python pygame模块怎么写游戏_使用 Python 和 Pygame 模块构建一个游戏框架
这系列的第一篇通过创建一个简单的骰子游戏来探究 Python.现在是来从零制作你自己的游戏的时间. 在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏 ...
- 从0开始手写一个 SpringMVC 框架,向高手进阶!
Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面.如果不看Spring的源码,你将会失去一次和大师学习的机会:它的代码规范,设 ...
- 手撸一个RPC框架——傻瓜式教程(一)
RPC框架-傻瓜式教程(一) 前言,太久没写博客了,有点手生,总结一下自己对RPC框架的学习过程 首先我们知道RPC的全名是,全程服务调用,我们用它来做什么,简单地说就是客户端通过接口调用服务端的函数 ...
- 自己手写一个Mybatis框架(简化)
继上一篇手写SpringMVC之后,我最近趁热打铁,研究了一下Mybatis.MyBatis框架的核心功能其实不难,无非就是动态代理和jdbc的操作,难的是写出来可扩展,高内聚,低耦合的规范的代码.本 ...
最新文章
- 使用 PowerShell 创建 Linux 虚拟机
- python爬虫新手项目-33个Python爬虫项目实战(推荐)
- em算法详细例子及推导_EM算法详解(例子+推导)
- careercup-数组和字符串1.7
- python初学篇笔记_Python学习笔记(基础篇)
- 4-数组、指针与字符串1.4-动态内存分配
- python 内建函数basestring笔记
- 支离破碎的 Android
- 山西煤炭职业技术学院计算机信息管理,山西煤炭职业技术学院计算机信息系
- 2006毕业设计Delphi篇(二)
- php UUID 分布式生成用不重复的随机数方法
- 杰控组态软件的“远程连接服务”使用要点
- pillow生成企业营业执照
- 成品app直播源码,fragment切换 常用写法
- 太突然!北大方正破产了!负债3029亿元!
- 修改计算机管理员administrator的密码
- 干货丨时序数据库DolphinDB脚本语言的混合范式编程
- java 文件上传乱码_java上传txt文件,出现中文乱码
- 解决Android Studio不提示控件的XML属性
- Python编程:通过百度地图接口抓取机构的地址和电话信息