《架構(gòu)探險 從零開始寫Java Web框架》筆記

《架構(gòu)探險 從零開始寫Java Web框架》筆記

第二章牵寺,為Web應(yīng)用添加業(yè)務(wù)功能

需求分析與系統(tǒng)設(shè)計

這一章書中舉了一個簡單的例子悍引,完全基于Servlet API,實(shí)現(xiàn)顧客信息的增刪改查帽氓。系統(tǒng)分為四層:model(模型層), view(視圖層), controller(控制器層), service(服務(wù)層)吗铐。模型層定義了Customer JavaBean;視圖層存放JSP視圖杏节;這里比標(biāo)準(zhǔn)的MVC架構(gòu)多了一個服務(wù)層唬渗,作為銜接控制器層與數(shù)據(jù)庫之間的橋梁》苡妫控制器層調(diào)用服務(wù)層镊逝,獲取指定的Bean或BeanList.

由于一個Servlet只能處理對一個路徑的請求:

@WebServlet("/customer_list")
public class CustomerListServlet extends HttpServlet {
    init(); doGet(); doPost()...
}

所以必定還要寫CustomerShowServlet,CustomerCreateServlet嫉鲸,CustomerEditServlet撑蒜,CustomerEditServlet等等,隨著業(yè)務(wù)需求的不斷擴(kuò)展玄渗,Servlet的數(shù)量勢必不斷增多座菠,將大大增加維護(hù)工作量。所以藤树,后面框架的作用之一就是浴滴,一個請求路徑對應(yīng)一個方法,而不是一個類岁钓,這樣就可以將上面Customer相關(guān)的業(yè)務(wù)邏輯都集中到一個CustomerController中升略。

第三章,搭建輕量級Java Web框架

確定目標(biāo)

我們的目標(biāo)是打造一個輕量級MVC框架屡限,而Controller是MVC的核心品嚣。我們想要的是這樣的Controller代碼:

/**
 * 處理客戶管理相關(guān)請求
 * /
@Controller
public class CustomerController {
    @Inject
    private CustomerService customerService;

    @Action("get:/customer_list")
    public View index(Param param) {
        List<Customer> customerList = customerService.getCustomerList();
        return new View("customer_list.jsp").addModel("customerList", customerList);
    }

    @Action("post:/customer_create")
    public Data createSubmit(Param param) {
        Map<String, Object> fieldMap = param.getMap();
        boolean result = customerService.createCustomer(fieldMap);
        return new Data(result);
    }
}

通過Controller注解來定義Controller類,在該類中钧大,可通過Inject注解定義一個Service成員變量翰撑,這就是“依賴注入”。此外啊央,有一系列被Action注解所定義的方法眶诈,在這些Action方法中,調(diào)用了Service的方法來完成具體的業(yè)務(wù)邏輯劣挫。若返回View對象压固,則表示JSP頁面;若返回Data對象坎炼,則表示一個JSON數(shù)據(jù)拦键。

開發(fā)一個類加載器

我們需要開發(fā)一個“類加載器”來加載該基礎(chǔ)包名下的所有類芬为,比如使用了某注解的類蟀悦,或?qū)崿F(xiàn)了某接口的類日戈,再或者繼承了某父類的所有子類等浙炼。

Tomcat等Java Web服務(wù)器又被稱作“Servlet容器”弯屈。我們編寫的Servlet并不需要我們自己去手動加載恋拷、實(shí)例化梅掠,而是由框架自動實(shí)現(xiàn)。發(fā)現(xiàn)并加載類文件就是第一步酪我。

public static Class<?> loadClass(String className, boolean isInitialized) {
    Class<?> cls;
    try {
        cls = Class.forName(className, isInitialized, Thread.currentThread().getContextClassLoader());
    } catch (ClassNotFoundException e) {
        ... 
    }
    return cls;
}

定義注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
    
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
    String value();
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {

}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {

}

結(jié)合cls.isAnnotationPresent(Controller.class/Service.class)方法就可以加載并識別出包下所有被@Controller/@Service注解的類都哭。

實(shí)現(xiàn)Bean容器

加載了類之后欺矫,下一步就是通過反射來實(shí)例化對象穆趴,并將這些對象全部放到一個Map<Class<?>, Object>中遇汞,即所謂“Bean容器”空入。

通過Class對象實(shí)例化對象很簡單:

cls.newInstance();

然后放進(jìn)“Bean容器”中:BEAN_MAP.put(beanClass, obj);(Bean類與Bean實(shí)例的映射關(guān)系)

反射能做到的事情:實(shí)例化一個類(Class<?>對象);獲取一個類的所有屬性化戳、方法点楼,并設(shè)置屬性值、調(diào)用方法藏斩。

// 獲取所有的屬性却盘;
for (Field field : emailBeanClass.getDeclaredFields()) {
    System.out.println(field.getName());
    // field.set(obj, value); // obj是該屬性所屬的對象黄橘;
}

// 獲取所有方法塞关;
for (Method method : emailBeanClass.getMethods()) {
    System.out.println(method.getName());
    // method.invoke(obj, Object... args)
}

實(shí)現(xiàn)依賴注入功能

我們在Controller中定義了Service屬性帆赢,并在Action方法中調(diào)用Service的方法线梗。那么仪搔,如何實(shí)例化Service屬性呢?

不是開發(fā)者通過new的方式來實(shí)例化偏陪,而是通過框架自身來實(shí)例化笛谦,像這類實(shí)例化過程昌阿,稱為IoC(Inversion of Control宝泵,控制反轉(zhuǎn))】蛲控制不是由開發(fā)者決定的椰弊,而是反轉(zhuǎn)給框架了。一般的贤重,我們將控制反轉(zhuǎn)稱為DI(Dependency Injection清焕,依賴注入),可以理解為將某各類依賴的成員注入到這個類中滚停。

在上面的步驟中键畴,我們加載了所有的類起惕,通過反射實(shí)例化咏删,并放到Bean容器中饵婆。這里,我們可以遍歷所有的Bean定義(即Bean容器的鍵集合草穆,Class<?>對象)悲柱,然后遍歷Bean類定義的所有成員變量些己,看其是否帶有@Inject注解段标,若有,則通過反射蛇更,(從Bean容器中取出對應(yīng)Service類實(shí)例并)設(shè)置該成員變量的值派任,即完成了依賴注入。

加載Controller

前面我們將Customer相關(guān)的所有Servlet代碼都集中到一個CustomerController類中师逸,每個請求對應(yīng)一個Action方法篓像;那么皿伺,我們的框架如何加載這個Controller類呢?

我們需要創(chuàng)建一個ControllerHelper類心傀,讓它來處理如下邏輯:

通過ClassHelper脂男,我們可以獲取所有定義了Controller注解的類宰翅,可以通過反射獲取該類中所有帶有Action注解的方法汁讼,獲取Action注解中的請求表達(dá)式阔墩,進(jìn)而獲取請求方法與請求路徑啸箫,封裝一個請求對象(Request)與處理對象(Handler),最后將Request與Handler建立一個映射關(guān)系蝉娜,放入一個Action Map中召川,并提供一個可根據(jù)請求方法與請求路徑獲取處理對象的方法胸遇。

class Request {
    private String requestMethod; // 請求方法;
    private String requestPath; // 請求路徑坛增;
    ...
}

class Handler {
    private Class<?> controllerClass; // 該方法所屬的Controller類收捣;
    // 通過反射調(diào)用Method方法的時候必須提供該方法所屬的對象,所以這里記錄下該方法所屬的類楣颠,然后可以通過Bean容器找到Bean對象童漩;
    private Method actionMethod; // Action方法矫膨;
    ...
}

加載Controller類的步驟:

  1. 遍歷Bean容器期奔,找出所有@Controller注解的類呐萌;
  2. 遍歷Controller類的方法,找出所有@Action注解的Action方法罗晕;
  3. 解析請求方法與請求路徑小渊,構(gòu)成Request對象茫叭;Class<?>類定義與Method方法構(gòu)成Handler對象杂靶;
  4. 將Request與Handler的映射放進(jìn)ACTION_MAP中;

請求轉(zhuǎn)發(fā)器

以上過程都是在為這一步做準(zhǔn)備垛吗。我們現(xiàn)在需要編寫一個Servlet怯屉,讓它來處理所有請求。從HttpServletRequest對象中獲取請求方法與請求路徑赌躺,通過ControllerHelper#getHandler獲取Handler對象(通過Handler對象獲取Controller類羡儿,進(jìn)而通過Bean容器獲取Controller實(shí)例對象)掠归;從HttpServletRequest對象中取出請求參數(shù),構(gòu)成Param對象(一個Map<String, Object>)肤粱;調(diào)用Handler對象對應(yīng)的Action方法领曼,返回View或Data悯森;若返回值是View類型的視圖對象绪撵,則返回一個JSP頁面音诈;若是Data對象细溅,則返回一個JSON數(shù)據(jù)儡嘶。

public class View {
    private String path; // 視圖路徑蹦狂;
    private Map<String, Object> model; // 模型數(shù)據(jù);
    ...
    
    public View addModel(String key, Object value) {
        model.put(key, value);
        return this;
    }
}

以下便是MVC框架中最核心的DispatcherServlet類窜骄,代碼如下:

@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) {
        // 獲取請求方法與請求路徑邻遏;
        String requestMethod = request.getMethod().toLowerCase();
        String requestPath = request.getPathInfo();
        // 獲取Handler准验,即Action處理器糊饱;
        Handler handler = ControllerHelper.getHandler(requestMethod, requestPath);
        if (handler == null) {...}
        // 獲取Controller類及其Bean實(shí)例;
        Class<?> controllerClass = handler.getControllerClass();
        Object controllerBean = BeanHelper.getBean(controllerClass);
        // 創(chuàng)建請求參數(shù)Map矫废;
        Map<String, Object> paramMap = new HashMap<>();
        ...// request.getParameterNames(); request.getParameter(paramName);
        Param param = new Param(paramMap);
        // 調(diào)用Action方法蓖扑;
        Method actionMethod = handler.getActionMethod();
        Object result = actionMethod.invoke(controllerBean, param);
        // 處理Action方法返回值台舱;
        if (result instanceof View) {
            // 返回JSP頁面竞惋;
            View view = (View) result;
            String path = view.getPath();
            if (path.startsWith("/")) {
                response.sendRedirect(request.getContextPath + path);
            } else {
                Map<String, Object> model = view.getModel();
                for (Map.Entry<String, Object> entry : model.entrySet()) {
                    request.setAttribute(entry.getKey(), entry.getValue());
                }
                request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path)
                        .forward(request, response);
            }
        } else if (result instanceof Data) {
            Object model = ((Data) request).getModel();
            String json = JsonUtil.toJson(model);
            response.getWriter().write(json);
            response.getWriter().close();
        }
    }
}

另外拆宛,我們是通過一系列的Helper類來初始化MVC框架的浑厚,即框架的工作主要是在各種Helper類中完成;而Helper類則集中到一起通過一個入口程序來加載它們物蝙,實(shí)際上是執(zhí)行它們的靜態(tài)塊诬乞。

public final class HelperLoader {
    public static void init() {
        Class<?>[] classList = {
                ClassHelper.class,
                BeanHelper.class,
                IocHelper.class,
                ControllerHelper.class
        };
        for (Class<?> cls : classList) {
            ClassUtil.loadClass(cls.getName());
        }
    }
}

總結(jié)

在本章中震嫉,我們搭建了一個簡單的MVC框架牡属,定義了一系列注解:通過Controller注解來定義Controller類湃望;通過Inject注解來實(shí)現(xiàn)依賴注入痰驱;通過Action注解來定義Action方法担映。通過一系列的Helper類來初始化MVC框架蝇完;通過DispatcherServlet來處理所有的請求矗蕊;根據(jù)請求方法與請求路徑來調(diào)用具體的Action方法傻咖,判斷Action方法的返回值,若為View類型警检,則跳轉(zhuǎn)到JSP頁面(或轉(zhuǎn)發(fā)請求)扇雕,若為Data類型窥摄,則返回JSON數(shù)據(jù)崭放。

使框架具備AOP特性

代理

代理,或稱為Proxy。意思就是你不用去做道伟,別人代替你去處理使碾。它在程序開發(fā)中起到了非常重要的作用票摇,比如AOP,就是針對代理的一種應(yīng)用盆色。

靜態(tài)代理
public interface HelloInterface {
    void say(String name);
}

public class HelloImpl implements HelloInterface {
    @Override
    public void say(String name) {
        System.out.println("Hello! " + name);
    }
}

public class HelloProxy implements HelloInterface {
    private HelloInterface hello;
    
    public HelloProxy(HelloInterface hello) {
        this.hello = hello; // 傳入被代理的對象;
    }

    @Override
    public void say(String name) {
        before();
        hello.say(name);
        after();
    }
    private void before() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println(After);
    }
}

public static void main(String[] args) {
    HelloInterface hello = new HelloImpl();
    HelloInterface helloProxy = new HelloProxy(hello);
    helloProxy.say("Smith");
}

這里摩梧,代理類必須實(shí)現(xiàn)與被代理類相同的接口仅父,兩者高度耦合笙纤。

JDK動態(tài)代理

代理類與被代理類分離组力。

public class DynamicProxy implements InvocationHandler { // 代理類無需實(shí)現(xiàn)任何其他接口忿项;
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target; // 傳入被代理的對象轩触;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }
    ...
}

public static void main(String[] args) {
    HelloInterface hello = new HelloImpl();
    DynamicProxy dynamicProxy = new DynamicProxy(hello);
    // “生成”代理對象;
    HelloInterface helloProxy = (HelloInterface) Proxy.newProxyInstance(
            hello.getClass().getClassLoader(),
            hello.getClass().getInterfaces(),
            dynamicProxy
    );
    helloProxy.say("Smith");
}
CGlib動態(tài)代理

JDK動態(tài)代理有一個“Are You Kidding Me”的缺點(diǎn):被代理類必須實(shí)現(xiàn)接口伐弹。若沒有實(shí)現(xiàn)任何接口惨好,或接口里沒有任何方法日川,則代理類生成的是一個“空對象”矩乐,或“空類”——動態(tài)代理是動態(tài)生成了類的(可以用代理對象的getClass().getName()方法驗(yàn)證)散罕,這個生成類實(shí)現(xiàn)了與被代理類相同的接口——也僅僅是實(shí)現(xiàn)這些接口,被代理類接口之外的成員方法是不會出現(xiàn)在生成類中的职抡。也就是說缚甩,JDK動態(tài)代理是基于接口的代理。

Spring岳遥、Hibernate等框架都使用了名為CGlib(Code Generation lib)的動態(tài)代理工具裕寨。它能在運(yùn)行期間動態(tài)生成字節(jié)碼,也就是動態(tài)生成代理類了捻艳。

public class CGLibProxy implements MethodInterceptor {
    public <T> T getProxy(Class<T> cls) {
        return (T) Enhancer.create(cls, this);
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj, args);
        after();
        return result;
    }
    ...
}

public static void main(String[] args) {
    CGLibProxy cgLibProxy = new CGLibProxy();
    Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class); // 看這里认轨,參數(shù)由之前的對象變成了類月培;
    helloProxy.say("Jack");
}

CGlib個我們提供的是方法級別的代理杉畜,也可以理解為對方法的攔截(這不就是傳說中的“方法攔截器”嗎?)纯续。

與JDK動態(tài)代理不同的是灭袁,這里不需要提供任何接口信息,對誰都可以生成動態(tài)代理對象倦炒。

AOP

什么是AOP

AOP软瞎,Aspect-Oriented Programming铜涉,面向切面編程芒划。

切面是AOP中的一個術(shù)語旭旭,表示從業(yè)務(wù)邏輯中分離出來的“橫切邏輯”页滚,比如性能監(jiān)控裹驰、日志記錄片挂、權(quán)限控制等,這些功能都可以從核心的業(yè)務(wù)邏輯中分離出去沪饺。也就是說整葡,通過AOP可以解決代碼耦合問題讥脐,讓職責(zé)更單一。

Spring AOP

前置增強(qiáng)俱萍、后置增強(qiáng)鼠次、環(huán)繞增強(qiáng)芋齿,拋出增強(qiáng);

引入增強(qiáng):上面都是對方法的增強(qiáng)赦役,叫Weaving(織入)掂摔;而對類的增強(qiáng)叫Introduction(引入)乙漓。

// 定義一個新接口释移;
public interface Apology {
    void saySorry(String name);
}

// 引入增強(qiáng)類;
public class GreetingIntroAdvice extends DelegatingIntroductionIntercepter implements Apology {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        return super.invoke(invocation);
    }

    @Override
    public void saySorry(String name) {
        System.out.println("Sorry, " + name);
    }
}

這就是引入增強(qiáng)帶給我們的新特性涩蜘,也就是“接口動態(tài)實(shí)現(xiàn)”功能。

Spring AOP:切面

之前談到的AOP框架其實(shí)可以將它理解為一個攔截器框架粤策,但這個攔截器似乎非常武斷误窖。比如說霹俺,它攔截了一個類吭服,那么它就攔截了這個類中的所有方法。而我們常常需要在代碼中對所攔截的方法名加以判斷艇棕,才能過濾出我們需要攔截的方法,這種做法確實(shí)不太優(yōu)雅北苟。于是打瘪,Spring AOP引入了一個“切面(Advisor)”的概念來解決這個問題闺骚。

切面封裝了增強(qiáng)和切點(diǎn)(攔截匹配條件)僻爽。

開發(fā)AOP框架

略。

ThreadLocal簡介

ThreadLocal敦捧,線程本地變量兢卵。其實(shí)就是一個容器秽荤,用于存放線程的局部變量

先看ThreadLocal的用法:

public static void main(String[] args) {
    CGLibProxy cgLibProxy = new CGLibProxy();
    Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class); // 看這里,參數(shù)由之前的對象變成了類雁乡;
    helloProxy.say("Jack");
}

public class Sequence {
    private ThreadLocal<Integer> numberContainer = new ThreadLocal<>() {
        @Override
        protected Integer initialValue() {
            return 0; // 設(shè)置ThreadLocal變量的初始值踱稍;
        }
    }
    
    public int getNumber() {
        numberContainer.set(numberContainer.get() + 1);
        return numberContainer.get();
    }

    public static void main(String[] args) {
        Sequence sequence = new Sequence();
        new ClientThread(sequence).start();
        new ClientThread(sequence).start();
        new ClientThread(sequence).start();
    }
}

output:
Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
...
自己實(shí)現(xiàn)ThreadLocal
public class MyThreadLocal<T> {
    private Map<Thread, T> container = Collections.synchronizedMap(new HashMap<>());
    protected T initialValue() {
        return null;
    }
    public void set(T value) {
        container.put(Thread.currentThread(), value);
    }
    public T get() {
        if (!container.containsKey(Thread.currentThread())) {
            container.put(Thread.currentThread(), initialValue());
        }
        return container.get(Thread.currentThread());
    }
    public void remove() {
        container.remove(Thread.currentThread());
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末珠月,一起剝皮案震驚了整個濱河市啤挎,隨后出現(xiàn)的幾起案子庆聘,更是在濱河造成了極大的恐慌伙判,老刑警劉巖黑忱,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甫煞,死亡現(xiàn)場離奇詭異抚吠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蕊玷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門垃帅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贸诚,“玉大人酱固,你說我怎么就攤上這事运悲。” “怎么了希停?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵宠能,是天一觀的道長违崇。 經(jīng)常有香客問我亦歉,道長肴楷,這世上最難降的妖魔是什么荠呐? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任呵恢,我火速辦了婚禮渗钉,結(jié)果婚禮上钞钙,老公的妹妹穿的比我還像新娘鳄橘。我一直安慰自己,他們只是感情好芒炼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布瘫怜。 她就那樣靜靜地躺著,像睡著了一般本刽。 火紅的嫁衣襯著肌膚如雪鲸湃。 梳的紋絲不亂的頭發(fā)上赠涮,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機(jī)與錄音暗挑,去河邊找鬼笋除。 笑死,一個胖子當(dāng)著我的面吹牛炸裆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播听系,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼毕源,長吁一口氣:“原來是場噩夢啊……” “哼址愿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起娘纷,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤遏插,失蹤者是張志新(化名)和其女友劉穎涩堤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體白魂,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敬锐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冤灾。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡移宅,死狀恐怖盏浇,靈堂內(nèi)的尸體忽然破棺而出绢掰,到底是詐尸還是另有隱情,我是刑警寧澤班挖,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布双揪,位于F島的核電站,受9級特大地震影響疯趟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜姨夹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蓬豁。 院中可真熱鬧,春花似錦蟆技、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庇谆。三九已至串述,卻和暖如春新蟆,著一層夾襖步出監(jiān)牢的瞬間吮螺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工泉蝌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梨与,地道東北人呻粹。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓轧飞,卻偏偏與公主長得像制妄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理毁兆,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • spring mvc 工作機(jī)制(原理): DispatcherServlet主要用作職責(zé)調(diào)度工作煮寡,本身主要用于控制...
    java大濕兄閱讀 1,887評論 5 24
  • 今天很累,比較少,只有兩朵
    小瑤妹妹閱讀 293評論 1 1
  • 親愛的艾艾貼: 結(jié)緣艾艾貼,是一個同事的介紹枷踏,從此對艾灸的熱愛變一發(fā)不可收拾下梢。 三年前和周緣老師學(xué)小兒推拿,上課前...
    giguala閱讀 372評論 1 2