跟我一起造輪子 手寫springmvc

  作為java程序員而晒,項目中使用到的主流框架多多少少和spring有關(guān)聯(lián),在面試的過程難免會問一些spring springmvc spring boot的東西螃壤,比如設(shè)計模式的使用抗果、 怎么實現(xiàn)springioc?怎么實現(xiàn)springmvc諸如此類的問題,今天我們就來探尋spring mvc的實現(xiàn)奸晴,然后自己實現(xiàn)一個簡單的spring mvc

一.了解spring mvc的基本運行流程

 ps:?網(wǎng)上一大堆關(guān)于springmvc的詳細講解冤馏,在這里就不累贅了


  小結(jié):spring mvc的核心是DispatcherServlet,DispatcherServlet繼承于HttpServlet寄啼,可以說spring mvc是基于Servlet的一個實現(xiàn)逮光,DispatcherServlet負責(zé)協(xié)調(diào)和組織不同組件以完成請求處理并返回響應(yīng)的工作,實現(xiàn)了MVC模式辕录。


二.?梳理簡單SpringMVC的設(shè)計思路

1. 初始化容器?

1.1?讀取配置文件

          1.1.1.加載配置文件信息到DispatcherServlet

1.2??根據(jù)配置掃描包睦霎、初始化容器和組件

          1.2.1.根據(jù)配置信息遞歸掃描包

          1.2.2.把包下的類實例化 并且掃描注解

          1.2.3.根據(jù)類的方法和注解,初始化HandlerMapping

2. 處理業(yè)務(wù)請求

2.1?處理請求業(yè)務(wù)

2.2.1 首先拿到請求URI?

       ? ???2.2.2 根據(jù)URI走诞,在HandlerMapping中查找和URI對應(yīng)的Handler

       ? ? ? ? 2.2.3 根據(jù)Handler里面的method中的參數(shù)名稱和http中的請求參數(shù)匹配,填充method參數(shù)蛤高,反射調(diào)用


三.?沒時間解釋了蚣旱,快上車

 ps :環(huán)境基于maven idea tomat(端口8080) servlet


  1.搭建一個基本web項目,并導(dǎo)入idea配置servlet 和javassist pom依賴 如下

創(chuàng)建命令: mvn archetype:generate -DgroupId=com.adminkk -DartifactId=adminkk-mvc -DpackageName=com.adminkk -Dversion=1.0

?pom依賴

? 4.0.0? com.adminkk? adminkk-mvc? 1.0-SNAPSHOT? ? ? ? ? ? ? ? ? ? org.apache.maven.plugins? ? ? ? maven-compiler-plugin? ? ? ? ? ? ? ? ? 8? ? ? ? ? 8? ? ? ? ? ? ? ? ? ? ? war? adminkk-mvc? http://maven.apache.org</url>? ? UTF-8? ? ? ? ? ? ? junit? ? ? junit? ? ? 3.8.1? ? ? test? ? ? ? ? ? ? ? ? ? ? javax.servlet? ? ? ? javax.servlet-api? ? ? ? 3.0.1? ? ? ? provided? ? ? ? ? ? ? ? ? ? asm? ? ? asm? ? ? 3.3.1? ? ? ? ? ? ? ? ? org.javassist? ? ? javassist? ? ? 3.23.1-GA? ? ?



2.創(chuàng)建mvc的注解?Controller?RequestMapping 和統(tǒng)一異常處理類戴陡、方法參數(shù)工具類ParameterNameUtils  ?

package com.adminkk.annotation;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)public@interface Controller {

? ? publicString value()default"";

? ? publicString description()default"";

}


package com.adminkk.annotation;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)public@interface RequestMapping {

? ? publicString value()default"";

? ? publicString method()default"";

? ? publicString description()default"";

}

package com.adminkk.exception;

public? final? class MvcException extends RuntimeException{

? ? public MvcException() {

? ? ? ? super();

? ? }

? ? public MvcException(String message) {

? ? ? ? super(message);

? ? }

}

package com.adminkk.tools;importjavassist.*;import javassist.bytecode.CodeAttribute;import javassist.bytecode.LocalVariableAttribute;import javassist.bytecode.MethodInfo;import java.lang.reflect.Method;publicfinalclass ParameterNameUtils {

? ? publicfinalstaticString[] getParameterNamesByJavassist(finalClass clazz,final Method method) {

? ? ? ? ClassPool pool = ClassPool.getDefault();

? ? ? ? try {

? ? ? ? ? ? CtClass ctClass = pool.get(clazz.getName());

? ? ? ? ? ? CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName());

? ? ? ? ? ? // 使用javassist的反射方法的參數(shù)名MethodInfo methodInfo = ctMethod.getMethodInfo();

? ? ? ? ? ? CodeAttribute codeAttribute = methodInfo.getCodeAttribute();

? ? ? ? ? ? LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute

? ? ? ? ? ? ? ? ? ? .getAttribute(LocalVariableAttribute.tag);

? ? ? ? ? ? if(attr !=null) {

? ? ? ? ? ? ? ? String[] rtv =new String[ctMethod.getParameterTypes().length];

? ? ? ? ? ? ? ? intlen = ctMethod.getParameterTypes().length;

? ? ? ? ? ? ? ? // 非靜態(tài)的成員函數(shù)的第一個參數(shù)是thisintpos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;

? ? ? ? ? ? ? ? for(inti = 0; i < len; i++) {

? ? ? ? ? ? ? ? ? ? rtv[i] = attr.variableName(i + pos);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return rtv;

? ? ? ? ? ? }

? ? ? ? } catch (NotFoundException e) {

? ? ? ? ? ? System.out.println("獲取異常"+ e.getMessage());

? ? ? ? }

? ? ? ? returnnewString[0];

? ? }

}



3.創(chuàng)建?HandlerMapping類 主要是兩個方法? doInit初始化?doService處理請求 相關(guān)代碼如下

package com.adminkk.handler;import com.adminkk.scan.FileScaner;import com.adminkk.scan.Scaner;import com.adminkk.scan.XmlScaner;import com.adminkk.tools.ParameterNameUtils;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.PrintWriter;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;publicfinalclass HandlerMapping {

? ? privatestaticfinalMap handlerMapping =newHashMap();

? ? privatestaticfinalList scaners =newArrayList<>(2);

? ? static {

? ? ? ? scaners.add(new XmlScaner());

? ? ? ? scaners.add(new FileScaner());

? ? }

? ? publicstaticvoidscanPackage(String scanUrl)throws RuntimeException, IllegalAccessException, InstantiationException, ClassNotFoundException {

? ? ? ? for (Scaner scaner : scaners) {

? ? ? ? ? ? scaner.doScane(scanUrl);

? ? ? ? }

? ? }

? ? publicstaticvoiddoInit(String scanUrl)throws IllegalAccessException, ClassNotFoundException, InstantiationException {

? ? ? ? scanPackage(scanUrl);

? ? }

? ? publicstaticvoid doService(HttpServletRequest request, HttpServletResponse response) {

? ? ? ? String requestURI = request.getRequestURI();

? ? ? ? System.out.println("請求地址是="+ requestURI);

? ? ? ? Handler handler = handlerMapping.get(requestURI);

? ? ? ? if(handler ==null){

? ? ? ? ? ? System.out.println("請求地址是="+ requestURI+" 沒有配置改路徑");

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? Method method = handler.getMethod();

? ? ? ? Object instance = handler.getInstance();

? ? ? ? response.setCharacterEncoding("UTF-8");

? ? ? ? //response.setContentType("application/json; charset=utf-8");PrintWriter writer =null;

? ? ? ? try {

? ? ? ? ? ? //這里是簡單的解析 可以像springmvc那樣解析處理Map parameterMap = request.getParameterMap();

? ? ? ? ? ? String[] parameters = ParameterNameUtils.getParameterNamesByJavassist(instance.getClass(),method);

? ? ? ? ? ? Object[]? parameter =new Object[parameters.length];

? ? ? ? ? ? if(parameters !=null&& parameters.length > 0){

? ? ? ? ? ? ? ? for(inti = 0; i < parameters.length; i++) {

? ? ? ? ? ? ? ? ? ? finalString simpleName = parameters[i];

? ? ? ? ? ? ? ? ? ? StringBuilder parameterSb =new? StringBuilder();

? ? ? ? ? ? ? ? ? ? finalString[] parameterStr = parameterMap.get(simpleName);

? ? ? ? ? ? ? ? ? ? if(parameterStr !=null){

? ? ? ? ? ? ? ? ? ? ? ? for(intj = 0; j < parameterStr.length; j++) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? parameterSb.append(parameterStr[j]);

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? parameter[i] = parameterSb.toString();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? writer = response.getWriter();

? ? ? ? ? ? String result = (String) method.invoke(instance,parameter);

? ? ? ? ? ? writer.print(result);

? ? ? ? } catch (Exception e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? System.out.println("請求地址是="+ requestURI+" 執(zhí)行異常");

? ? ? ? ? ? writer.print("業(yè)務(wù)執(zhí)行異常");

? ? ? ? }finally {

? ? ? ? ? ? writer.flush();

? ? ? ? ? ? writer.close();

? ? ? ? }

? ? }

? ? publicstatic Handler addHandlerMapping(String url,Handler handler) {

? ? ? ? return handlerMapping.put(url,handler);

? ? }

? ? publicstatic Handler getHandlerMapping(String url) {

? ? ? ? return handlerMapping.get(url);

? ? }

}

?掃描包

package com.adminkk.scan;publicinterface Scaner {

? ? voiddoScane(String scanUrl)throws IllegalAccessException, InstantiationException, ClassNotFoundException;

}

package com.adminkk.scan;

import com.adminkk.exception.MvcException;

import com.adminkk.factory.BeanPostProcessor;

import com.adminkk.factory.MvcBeanPostProcessor;

import com.adminkk.factory.ServiceBeanPostProcessor;

import com.adminkk.handler.HandlerMapping;

import javassist.ClassClassPath;

import javassist.ClassPool;

import java.io.File;

import java.util.ArrayList;

import java.util.List;

public final? class FileScaner implements Scaner{

public FileScaner() {

}

public static final List beanPostProcessorList = new ArrayList<>();

static {

beanPostProcessorList.add(new MvcBeanPostProcessor());

beanPostProcessorList.add(new ServiceBeanPostProcessor());

}

@Override

public void doScane(String scanUrl) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

if(scanUrl == null || scanUrl.length() == 0){

throw new MvcException("容器基礎(chǔ)掃描路徑為空塞绿,請檢查參數(shù)配置");

}

String baseUrl = HandlerMapping.class.getResource("/").getPath();

String codeUrl = scanUrl.replaceAll("\\.", "/");

String path =? baseUrl + codeUrl;

File file = new File(path);

if(file == null || !file.exists()){

throw new MvcException("找不到對應(yīng)掃描路徑,請檢查參數(shù)配置");

}

recursionRedFile(scanUrl,file);

}

//遞歸讀取文件

private? void recursionRedFile(String scanUrl,File file) throws MvcException, ClassNotFoundException, IllegalAccessException, InstantiationException {

if(!file.exists()){

return;

}

//讀取java文件

if(file.isFile()){

String beanName = scanUrl.replaceAll(".class","");

Class forName = Class.forName(beanName);

//放到Javassist容器里面

ClassPool pool = ClassPool.getDefault();

ClassClassPath classPath = new ClassClassPath(forName);

pool.insertClassPath(classPath);

if(forName.isAnnotation() || forName.isEnum() || forName.isInterface() ){

return;

}

Object newInstance = forName.newInstance();

//前置執(zhí)行

for (int i = 0; i < beanPostProcessorList.size() ; i++) {

BeanPostProcessor beanPostProcessor = beanPostProcessorList.get(i);

beanPostProcessor.postProcessBeforeInitialization(newInstance,beanName);

}

//后置執(zhí)行

for (int i = beanPostProcessorList.size()-1; i > 0? ; i++) {

BeanPostProcessor beanPostProcessor = beanPostProcessorList.get(i);

beanPostProcessor.postProcessAfterInitialization(newInstance,beanName);

}

return;

}

//文件夾下面的文件都遞歸處理

if(file.isDirectory()){

File[] files = file.listFiles();

if(files != null && files.length >0){

for (int i = 0; i < files.length; i++) {

File targetFile = files[i];

recursionRedFile(scanUrl+"."+targetFile.getName(),targetFile);

}

}

}

}

}


package com.adminkk.scan;

public final class XmlScaner implements Scaner{

? ? public XmlScaner() {

? ? }

? ? @Override

? ? public void doScane(String scanUrl) {

? ? ? ? //可自行擴展

? ? }

}

  掃描bean

package com.adminkk.factory;import com.adminkk.exception.MvcException;publicinterface BeanPostProcessor {

? ? Object postProcessBeforeInitialization(Object object, String beanName) throws MvcException;

? ? Object postProcessAfterInitialization(Object object, String beanName) throws MvcException;

}


package com.adminkk.factory;import com.adminkk.annotation.Controller;import com.adminkk.annotation.RequestMapping;import com.adminkk.exception.MvcException;import com.adminkk.handler.Handler;import com.adminkk.handler.HandlerMapping;import java.lang.reflect.Method;publicclassMvcBeanPostProcessorimplements BeanPostProcessor{

? ? //掃描Controller業(yè)務(wù)? ? @Override

? ? publicObject postProcessBeforeInitialization(Object object, String beanName)throws MvcException {

? ? ? ? Class objectClass = object.getClass();

? ? ? ? if(objectClass.getAnnotation(Controller.class) !=null){

? ? ? ? ? ? RequestMapping calssRequestMappingAnnotation = objectClass.getAnnotation(RequestMapping.class);

? ? ? ? ? ? StringBuilder urlSb =new StringBuilder();

? ? ? ? ? ? if(calssRequestMappingAnnotation !=null){

? ? ? ? ? ? ? ? urlSb.append(calssRequestMappingAnnotation.value());

? ? ? ? ? ? }

? ? ? ? ? ? Method[] methods = objectClass.getMethods();

? ? ? ? ? ? if(methods !=null&& methods.length > 0 ){

? ? ? ? ? ? ? ? for(inti = 0; i < methods.length; i++) {

? ? ? ? ? ? ? ? ? ? Method method = methods[i];

? ? ? ? ? ? ? ? ? ? RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);

? ? ? ? ? ? ? ? ? ? if(methodAnnotation !=null){

? ? ? ? ? ? ? ? ? ? ? ? String methodValue = methodAnnotation.value();

? ? ? ? ? ? ? ? ? ? ? ? String url =new StringBuilder().append(urlSb).append(methodValue).toString();

? ? ? ? ? ? ? ? ? ? ? ? Handler handler = HandlerMapping.getHandlerMapping(url);

? ? ? ? ? ? ? ? ? ? ? ? if(handler ==null){

? ? ? ? ? ? ? ? ? ? ? ? ? ? handler =new Handler();

? ? ? ? ? ? ? ? ? ? ? ? ? ? handler.setMethod(method);

? ? ? ? ? ? ? ? ? ? ? ? ? ? handler.setInstance(object);

? ? ? ? ? ? ? ? ? ? ? ? ? ? HandlerMapping.addHandlerMapping(url,handler);

? ? ? ? ? ? ? ? ? ? ? ? }else {

? ? ? ? ? ? ? ? ? ? ? ? ? ? thrownewMvcException("請求路徑"+ url + "已經(jīng)存在容器中");

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return object;

? ? }

? ? @Override

? ? publicObject postProcessAfterInitialization(Object object, String beanName)throws MvcException {

? ? ? ? returnnull;

? ? }

}

package com.adminkk.factory;

import com.adminkk.exception.MvcException;

public class ServiceBeanPostProcessor implements BeanPostProcessor {

? ? @Override

? ? public Object postProcessBeforeInitialization(Object object, String beanName) throws MvcException {

? ? ? ? //可自行擴展

? ? ? ? return null;

? ? }

? ? @Override

? ? public Object postProcessAfterInitialization(Object object, String beanName) throws MvcException {

? ? ? ? //可自行擴展

? ? ? ? return null;

? ? }

}

5.創(chuàng)建?DispatcherServlet

package com.adminkk.servlet;

import com.adminkk.handler.HandlerMapping;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet(name = "DispatcherServlet",loadOnStartup=1,urlPatterns={"/"})

public final? class DispatcherServlet extends HttpServlet {

? ? public static final String BASE_SCAN_URL = "com.adminkk";

? ? //初始化容器

? ? @Override

? ? public void init() throws ServletException {

? ? ? ? doInit();

? ? }

? ? //處理業(yè)務(wù)請求

? ? @Override

? ? protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

? ? ? ? doService(req,resp);

? ? }

? ? private void doService(HttpServletRequest req, HttpServletResponse resp) throws ServletException {

? ? ? ? try {

? ? ? ? ? ? HandlerMapping.doService(req,resp);

? ? ? ? }catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? throw new ServletException(e.getMessage());

? ? ? ? }

? ? }

? ? private void doInit() throws ServletException {

? ? ? ? try {? ?

? ? ? ? ? ? HandlerMapping.doInit(this.BASE_SCAN_URL);

? ? ? ? }catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? throw new ServletException(e.getMessage());

? ? ? ? }

? ? }

}

 好了恤批,目前為止我們就寫好了簡版的springmvc 下面開始測試

package com.adminkk.controller;

import com.adminkk.annotation.Controller;

import com.adminkk.annotation.RequestMapping;

@Controller

@RequestMapping("/mvc")

public class MvcController {

? ? @RequestMapping("/index")

? ? public String index(){

? ? ? ? return? "adminkk-mvc system is running";

? ? }

? ? @RequestMapping("/arg")

? ? public String parameter(String argOne, String argTwo){

? ? ? ? return? "argOne = " + argOne + " argTwo = " + argTwo;

? ? }

}

      訪問地址?http://localhost:8080/mvc/index


      訪問地址: http://localhost:8080/mvc/arg?argOne=argOne&argTwo=argTwo


總結(jié):整體實現(xiàn)簡單的springmvc异吻,設(shè)計上還可以擴展更多,難點在于method 獲取方法上的參數(shù)名稱,由于jdk1.8以前是不支持的诀浪,需要借用第三方工具 比如 asm?javassist黑科技工具包來幫助實現(xiàn)棋返,spring-core使用的是LocalVariableTableParameterNameDiscoverer底層是調(diào)用asm,我們這里使用的是javassist。延用這套思路還可以和spring項目結(jié)合雷猪,寫一個 基于spring的springmvc項目

源代碼 : https://gitee.com/chenchenche/mvc

寫博客不容易睛竣,希望大家多多提建議?

下一篇預(yù)告? ? ?跟我一起造輪子 手寫分布式IM系統(tǒng)(上)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市求摇,隨后出現(xiàn)的幾起案子射沟,更是在濱河造成了極大的恐慌,老刑警劉巖与境,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件验夯,死亡現(xiàn)場離奇詭異,居然都是意外死亡摔刁,警方通過查閱死者的電腦和手機挥转,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來簸搞,“玉大人扁位,你說我怎么就攤上這事〕每。” “怎么了域仇?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寺擂。 經(jīng)常有香客問我暇务,道長,這世上最難降的妖魔是什么怔软? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任垦细,我火速辦了婚禮,結(jié)果婚禮上挡逼,老公的妹妹穿的比我還像新娘括改。我一直安慰自己,他們只是感情好家坎,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布嘱能。 她就那樣靜靜地躺著,像睡著了一般虱疏。 火紅的嫁衣襯著肌膚如雪惹骂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天做瞪,我揣著相機與錄音对粪,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛著拭,可吹牛的內(nèi)容都是我干的纱扭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茫死,長吁一口氣:“原來是場噩夢啊……” “哼跪但!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起峦萎,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤屡久,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爱榔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被环,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年详幽,在試婚紗的時候發(fā)現(xiàn)自己被綠了筛欢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡唇聘,死狀恐怖版姑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迟郎,我是刑警寧澤剥险,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站宪肖,受9級特大地震影響表制,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜控乾,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一么介、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜕衡,春花似錦壤短、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至镶骗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間躲雅,已是汗流浹背鼎姊。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人相寇。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓慰于,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唤衫。 傳聞我的和親對象是個殘疾皇子婆赠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)佳励,斷路器休里,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法赃承,內(nèi)部類的語法妙黍,繼承相關(guān)的語法,異常的語法瞧剖,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home...
    光劍書架上的書閱讀 3,884評論 2 8
  • ?著作權(quán)歸作者所有:來自51CTO博客作者優(yōu)秀android的原創(chuàng)作品拭嫁,如需轉(zhuǎn)載,請注明出處抓于,否則將追究法律責(zé)任 ...
    傳奇內(nèi)服號閱讀 1,076評論 0 9
  • 4月4日晨讀感悟 1做粤、最近在一個喬布斯的采訪視頻,給我的感覺是對于新觀念接受很快捉撮,對生活充滿好奇心怕品,執(zhí)行力很強,確...
    時光的小偷閱讀 51評論 0 0