陸敏技說Spring

前些天更新的《陸敏技說Spring》一文姐浮,小伙伴們的反映非常好窖壕,有很多找我們的老師索要配套視頻的钠糊,時隔好幾天,小編今天接著上次的未完待續(xù)粘昨,給大家送干貨了哦~~ 結(jié)尾處有我們老師的聯(lián)系方式垢啼,可以索要配套視頻哦。

此文為原創(chuàng)张肾,禁止非法轉(zhuǎn)載膊夹。

正文:

1.3.反射的原理

我們講完了IOC和DI了,但是其實對反射還是接觸到了一點皮毛“坪疲現(xiàn)在放刨,讓我們深入的了解下反射。不過尸饺,要了解反射的原理进统,還得首先了解一些關(guān)于類型加載的基礎(chǔ)知識。

我們知道運行java代碼的是虛擬機jvm浪听。那么java代碼本身是怎么進(jìn)入到j(luò)vm并且被jvm所識別的呢螟碎。 代碼本身本身編譯之后變成class文件,class文件進(jìn)入jvm會被一種叫做類加載器的組件先處理一遍迹栓。被類加載器處理過后的類型掉分,會變成一些被jvm認(rèn)識的元數(shù)據(jù),它們包括:構(gòu)造函數(shù)克伊、屬性和方法等酥郭。 負(fù)責(zé)反射的那些類型也認(rèn)識這些元數(shù)據(jù),并可以動態(tài)修改或者操作這些元數(shù)據(jù)愿吹。即不从,對于java中的任意一個類,反射類都能知道和調(diào)用這個類的所有屬性和方法犁跪,包括私有屬性和方法(這就厲害了椿息,說好的封裝呢,說好的private不能被訪問坷衍,在反射類這里統(tǒng)統(tǒng)無效G抻拧)

除此之外,反射甚至允許我們動態(tài)生成類型枫耳,也即我們壓根在原來的代碼中沒有一個叫做User的類型乏矾,但是利用反射基礎(chǔ),卻能動態(tài)生成一個User類型,再通過類加載器加載到j(luò)vm中妻熊。

1.3.1. 類加載器

既然說到類加載器,那我們就先來看看類加載器仑最。類裝載器具體來說就是解析類的節(jié)碼文件并構(gòu)造出類在JVM內(nèi)部表現(xiàn)形式(元數(shù)據(jù))的組件扔役。類裝載器加載一個類型,經(jīng)歷了如下步驟:

1:裝載:查找和導(dǎo)入Class文件警医;

2:鏈接:執(zhí)行校驗亿胸、準(zhǔn)備和解析步驟,其中解析步驟是可以選擇的:

校驗:檢查載入Class文件數(shù)據(jù)的正確性预皇;

準(zhǔn)備:給類的靜態(tài)變量分配存儲空間侈玄;

解析:將符號引用轉(zhuǎn)成直接引用;

3:初始化:對類的靜態(tài)變量吟温、靜態(tài)代碼塊執(zhí)行初始化工作序仙。

類加載器默認(rèn)有三個,它們分別負(fù)責(zé)不同類型的java類的加載:

(1)Bootstrap ClassLoader 根類加載器

也被稱為引導(dǎo)類加載器鲁豪,負(fù)責(zé)Java核心類的加載比如System,String等在JDK中JRE的lib目錄下rt.jar文件中的那些類型潘悼。

(2)Extension ClassLoader 擴(kuò)展類加載器

負(fù)責(zé)JRE的擴(kuò)展目錄中jar包的加載。這些類型在JDK中JRE的lib目錄下ext目錄下爬橡。

(3)System ClassLoader 系統(tǒng)類加載器

負(fù)責(zé)在JVM啟動時加載來自java命令的class文件治唤,以及classpath環(huán)境變量所指定jar包和類路徑下那些類型。

這三個類裝載器之間存在父子層級關(guān)系糙申,即根裝載器是ExtClassLoader的父裝載器宾添,ExtClassLoader是AppClassLoader的父裝載器。

我們可以通過代碼得到類加載器的原型柜裸,如下:

public class ClassLoaderTest {?

public static void main(String[] args) {?

? ? ClassLoader loader = ClassLoaderTest.class.getClassLoader();?

? ? System.out.println("current loader:"+loader);?

? ? System.out.println("parent loader:"+loader.getParent());?

? ? System.out.println("top loader:"+loader.getParent(). getParent());? ? ? }?

}

結(jié)果:

current loader:sun.misc.Launcher$AppClassLoader@4e0e2f2a

parent loader:sun.misc.Launcher$ExtClassLoader@2a139a55

top loader:null

注意缕陕,根加載器在java中無法訪問,所以是null疙挺。

1.3.2. 反射能做什么

利用反射榄檬,我們主要可以做這些事情,

在運行時構(gòu)造任意一個類的對象衔统;

在運行時獲得任意一個類的信息鹿榜,包括所具有的成員變量和方法;

在運行時調(diào)用任意一個對象的方法锦爵;

生成動態(tài)代理舱殿。

構(gòu)造任意一個對象:

? ? Class class1 = null;

? ? Class class2 = null;

? ? Class class3 = null;

? ? // 獲取類型的三種方式,有了類型后就可以newInstance()了

? ? class1 = Class.forName("com.zuikc.dao.mysql.UserDaoImpl");

? ? class2 = new UserDaoImpl().getClass();

? ? class3 = UserDaoImpl.class;

? ? System.out.println("類名稱? " + class1.getName() + "類對象:" + class1.newInstance());

? ? System.out.println("類名稱? " + class2.getName() + "類對象:" + class2.newInstance());

? ? System.out.println("類名稱? " + class3.getName() + "類對象:" + class3.newInstance());

注意险掀,如果類有構(gòu)造方法沪袭,則可以這樣調(diào)用(這里,我們使用User類):

? ? Class class1 = Class.forName("com.zuikc.bean.User");

? ? // 第一種方法樟氢,不調(diào)用有參構(gòu)造器冈绊,所以直接newInstance

? ? User user = (User) class1.newInstance();

? ? user.setAge(20);

? ? user.setName("baobao");

? ? System.out.println(user);

? ? // 第二種方法侠鳄,先獲取全部的構(gòu)造器,看看它們有什么參數(shù)

? ? Constructor cons[] = class1.getConstructors();

? ? // 查看每個構(gòu)造方法需要的參數(shù)

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

? ? ? ? Class clazzs[] = cons[i].getParameterTypes();

? ? ? ? System.out.print("cons[" + i + "] (");

? ? ? ? for (int j = 0; j < clazzs.length; j++) {

? ? ? ? ? ? if (j == clazzs.length - 1)

? ? ? ? ? ? ? ? System.out.print(clazzs[j].getName());

? ? ? ? ? ? else

? ? ? ? ? ? ? ? System.out.print(clazzs[j].getName() + ",");

? ? ? ? }

? ? ? ? System.out.println(")");

? ? }

? ? // 調(diào)用有參構(gòu)造器來創(chuàng)造對象

? ? user = (User) cons[0].newInstance(20, "Rollen");

? ? System.out.println(user);

? ? user = (User) cons[1].newInstance("Rollen");

? ? System.out.println(user);

為保證代碼的完整性死宣,同時給出Bean伟恶,

package com.zuikc.bean;

public class User {

public User() {

? ? super();

}

public User(String name) {

? ? super();

? ? this.name = name;

}

public User(int age, String name) {

? ? super();

? ? this.age = age;

? ? this.name = name;

}

private String name;

private int age;

public String getName() {

? ? return name;

}

public void setName(String name) {

? ? this.name = name;

}

public int getAge() {

? ? return age;

}

public void setAge(int age) {

? ? this.age = age;

}

@Override

public String toString() {

? ? return "User [name=" + name + ", age=" + age + "]";

}

}

獲取類的信息,包括所具有的成員變量和方法:

? ? Class clazz = Class.forName("com.zuikc.dao.mysql.UserDaoImpl");

? ? System.out.println("===============本類的field===============");

? ? Field[] field = clazz.getDeclaredFields();

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

? ? ? ? int mo = field[i].getModifiers();

? ? ? ? String priv = Modifier.toString(mo);

? ? ? ? Class type = field[i].getType();

? ? ? ? System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");

? ? }

? ? System.out.println("==========實現(xiàn)的接口或者父類的public field==========");

? ? Field[] filed1 = clazz.getFields();

? ? for (int j = 0; j < filed1.length; j++) {

? ? ? ? int mo = filed1[j].getModifiers();

? ? ? ? String priv = Modifier.toString(mo);

? ? ? ? Class type = filed1[j].getType();

? ? ? ? System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");

? ? }

? ? System.out.println("==========實現(xiàn)的接口或者父類的方法==========");

? ? Method method[] = clazz.getMethods();

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

? ? ? ? Class returnType = method[i].getReturnType();

? ? ? ? Class para[] = method[i].getParameterTypes();

? ? ? ? int temp = method[i].getModifiers();

? ? ? ? System.out.print(Modifier.toString(temp) + " ");

? ? ? ? System.out.print(returnType.getName() + "? ");

? ? ? ? System.out.print(method[i].getName() + " ");

? ? ? ? System.out.print("(");

? ? ? ? for (int j = 0; j < para.length; ++j) {

? ? ? ? ? ? System.out.print(para[j].getName() + " " + "arg" + j);

? ? ? ? ? ? if (j < para.length - 1) {

? ? ? ? ? ? ? ? System.out.print(",");

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? Class exce[] = method[i].getExceptionTypes();

? ? ? ? if (exce.length > 0) {

? ? ? ? ? ? System.out.print(") throws ");

? ? ? ? ? ? for (int k = 0; k < exce.length; ++k) {

? ? ? ? ? ? ? ? System.out.print(exce[k].getName() + " ");

? ? ? ? ? ? ? ? if (k < exce.length - 1) {

? ? ? ? ? ? ? ? ? ? System.out.print(",");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? System.out.print(")");

? ? ? ? }

? ? ? ? System.out.println();

? ? }

}

調(diào)用任意方法毅该,

? ? Class clazz = Class.forName("com.zuikc.dao.mysql.UserDaoImpl");

? ? // 調(diào)用方法博秫,第二個參數(shù)指參數(shù)的類型

? ? Method method = method = clazz.getMethod("getUserByName", String.class);

? ? Object? o = method.invoke(clazz.newInstance(), "baobao");

? ? User user = (User)o;

? ? System.out.println(user.getName());

調(diào)用任意屬性:

? ? Class clazz = Class.forName("com.zuikc.dao.mysql.UserDaoImpl");

? ? Object obj = clazz.newInstance();

? ? // 可以直接對 private 的屬性賦值

? ? Field field = clazz.getDeclaredField("propretyname");

? ? field.setAccessible(true);

? ? field.set(obj, "some value");

? ? System.out.println(field.get(obj));

實現(xiàn)動態(tài)代理。注意眶掌,關(guān)于動態(tài)代理挡育,是下一小節(jié)我們將要重點介紹的內(nèi)容。在此處先略過朴爬。

1.4.動態(tài)代理的現(xiàn)實意義

我們說反射可以被用于動態(tài)代理即寒,現(xiàn)在我們先不管動態(tài)代理是什么,按照我們最課程(zuikc.com)授課模式召噩,我們先來看該技術(shù)產(chǎn)生的現(xiàn)實意義蒿叠。

1.4.1. 為什么需要動態(tài)代理

首先,我們的程序已經(jīng)撰寫完畢了◎汲#現(xiàn)在市咽,我們的產(chǎn)品經(jīng)理跑過來說,最近發(fā)生了一些安全上的事故抵蚊,所以我們要加入一個功能施绎,記錄某些關(guān)鍵的操作是誰在什么時候操作的。

簡單來說贞绳,比如谷醉,任何人訪問getUserByName,我們都需要記錄是誰冈闭,在什么時候訪問俱尼,甚至如果是在一個web程序的話,我們還要記錄訪問者的遠(yuǎn)程ip地址萎攒。

一種做法是遇八,我們進(jìn)入getUserByName中去修改代碼,把記錄日志這個事情完成一下耍休。但是技術(shù)總監(jiān)說刃永,不行,既有的服務(wù)層以下的代碼都已經(jīng)經(jīng)過嚴(yán)格測試羊精,不能再侵入代碼斯够,我們必須在既有代碼的外層來加入這些新功能。

于是,思路來了:我們還是按照原有流程執(zhí)行代碼读规,但是執(zhí)行到UserDao的getUserByName時候抓督,我們通過技術(shù)手段替換掉UserDao這個對象,轉(zhuǎn)而調(diào)用UserDaoProxy對象束亏,在這個proxy中铃在,也有一個getUserByName方法,在這個方法里面我們添加新代碼枪汪,同時還調(diào)用老方法,這樣就完美解決了即不修改老方法怔昨,也增加了新功能雀久。

當(dāng)然,這里面的關(guān)鍵點趁舀,就是“通過技術(shù)手段替換掉UserDao這個對象赖捌,轉(zhuǎn)而調(diào)用UserDaoProxy對象”。這個技術(shù)手段矮烹,就叫做:動態(tài)代理。

1.4.2. 代理的最簡單實現(xiàn)

那怎么來生成代理對象,它的形式可以如:

? ? UserDao proxy= 根據(jù)UserDaoImpl來生成代理對象;

? ? proxy.getUserByName("baobao");

好求泰,現(xiàn)在的關(guān)鍵就是讓我們來解決“根據(jù)UserDaoImpl來生成代理對象”备畦。

其實在JDK中的反射包中,正好有一個類java.lang.reflect.Proxy有一個newProxyInstance方法是用來專門生成代理對象的:

static object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

第一個參數(shù)仁期,是要被代理的那個類的ClassLoader桑驱,那怎么得到這個ClassLoader?好辦跛蛋,直接調(diào)用 被代理的類型.getClass().getClassLoader()熬的;

第二個參數(shù),接受的是一個類型的參數(shù)赊级,即我們的UserDaolIml這個類型一共實現(xiàn)了幾個接口押框。那怎么得到這個接口數(shù)組呢,也好辦理逊,Class類型有一個方法getInterfaces()就是用來得到類型所實現(xiàn)的接口數(shù)組的橡伞。

第三個參數(shù),是要傳入一個InvocationHandler的類型晋被。我們發(fā)現(xiàn)InvocationHandler是一個接口骑歹,所以我們得首先實現(xiàn)一個InvocationHandler的實現(xiàn)類。這個實現(xiàn)類實現(xiàn)InvocationHandler中聲明好的一個方法墨微,叫做:

Object invoke(Object proxy, Method method, Object[] args)

看好了道媚,可以說這就很關(guān)鍵了,Proxy被設(shè)計為,我們看上去是在執(zhí)行proxy的getUserByName方法最域,其實是執(zhí)行了proxy的invoke方法谴分,那這是怎么做到的呢:

1:首先,proxy能夠執(zhí)行另外一個類(InvocationHandler實現(xiàn)類)的方法镀脂,那proxy首先得持有這個類不是嗎牺蹄,所以我們才發(fā)現(xiàn)Porxy.newProxyInstance的第三個參數(shù)就是InvocationHandler類型。即創(chuàng)建代理類的時候薄翅,就會把InvocationHandler實現(xiàn)類作為方法參數(shù)傳遞給代理類沙兰;

2:其次,執(zhí)行任何代理類方法翘魄,jvm都會首先引導(dǎo)到執(zhí)行invoke方法鼎天,比如執(zhí)行g(shù)etUserByName,其實已經(jīng)被強制為執(zhí)行invoke方法了暑竟,我們可以在invoke方法斋射,通過反射對原方法為所欲為! 讓我們看看最簡單的invoke方法吧:

package com.zuikc.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class InvocationHandlerImpl implements InvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

? ? System.out.println("被代理的方法要開始執(zhí)行了……");

? ? Object temp = method.invoke(被代理的類的實例, args);

? ? System.out.println("被代理的方法執(zhí)行完畢了……");

? ? return temp;

}

} invoke自帶了參數(shù)但荤,被代理的類的原方法的元數(shù)據(jù)信息作為Method參數(shù)被傳遞起來的罗岖。我們可以對它為所欲為意味著:我們想怎么執(zhí)行它就怎么執(zhí)行它,甚至還可以選擇不執(zhí)行它腹躁。

注意桑包,被代理的方法是獲取到了,但是為了運行它纺非,可不還得有被代理的類的對象本身嗎(上文中捡多,紅色的部分)?既然需要它铐炫,我們就在InvocationHandlerImpl的構(gòu)造器中傳給它就行了垒手,于是,上面的代碼變成了:

package com.zuikc.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class InvocationHandlerImpl implements InvocationHandler {

private Object obj = null;

public? InvocationHandlerImpl(Object obj) {

? ? this.obj = obj;

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

? ? System.out.println("方法開始執(zhí)行了~~");

? ? System.out.print("? 被截獲的方法為:" + method.getName() + "\t參數(shù)為:");

? ? for (Object arg : args) {

? ? ? ? System.out.print(arg + "\t");

? ? }

? ? System.out.println();

? ? Object temp = method.invoke(this.obj, args);

? ? System.out.println("方法執(zhí)行完畢倒信,返回~~");

? ? return temp;

}

}

經(jīng)過本次改造科贬,客戶端調(diào)用原來的代碼,由:

? ? UserDaoImpl userDaoImpl = new UserDaoImpl();

? ? userDaoImpl.getUserByName("baobao");

變成了被動態(tài)代理的:

? ? UserDaoImpl userDao = new UserDaoImpl();

? ? InvocationHandlerImpl handler = new InvocationHandlerImpl(userDao);

? ? UserDao proxy= (UserDao)Proxy.newProxyInstance(

? ? ? ? ? ? userDao.getClass().getClassLoader(),

? ? ? ? ? ? userDao.getClass().getInterfaces(),

? ? ? ? ? ? handler);

? ? proxy.getUserByName("baobao");

其輸出為:

方法開始執(zhí)行了~~

被截獲的方法為:getUserByName? 參數(shù)為:baobao?

方法執(zhí)行完畢鳖悠,返回~~

1.4.3. 面向切面編程

“代理的最簡單實現(xiàn)”這一小節(jié)中所表現(xiàn)出現(xiàn)的開發(fā)思想就被定義為:面向切面編程(AOP)榜掌。 代理是實現(xiàn)AOP的技術(shù)手段。


未完待續(xù)……

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乘综,一起剝皮案震驚了整個濱河市憎账,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卡辰,老刑警劉巖胞皱,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪意,死亡現(xiàn)場離奇詭異,居然都是意外死亡反砌,警方通過查閱死者的電腦和手機雾鬼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴树,“玉大人策菜,你說我怎么就攤上這事【票幔” “怎么了又憨?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锭吨。 經(jīng)常有香客問我蠢莺,道長,這世上最難降的妖魔是什么耐齐? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任浪秘,我火速辦了婚禮蒋情,結(jié)果婚禮上埠况,老公的妹妹穿的比我還像新娘。我一直安慰自己棵癣,他們只是感情好辕翰,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著狈谊,像睡著了一般喜命。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上河劝,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天壁榕,我揣著相機與錄音,去河邊找鬼赎瞎。 笑死牌里,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的务甥。 我是一名探鬼主播牡辽,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼敞临!你這毒婦竟也來了态辛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挺尿,失蹤者是張志新(化名)和其女友劉穎奏黑,沒想到半個月后炊邦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡攀涵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年铣耘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片以故。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜗细,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怒详,到底是詐尸還是另有隱情炉媒,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布昆烁,位于F島的核電站吊骤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏静尼。R本人自食惡果不足惜白粉,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鼠渺。 院中可真熱鬧鸭巴,春花似錦、人聲如沸拦盹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽普舆。三九已至恬口,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沼侣,已是汗流浹背祖能。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛾洛,地道東北人养铸。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像雅潭,于是被迫代替她去往敵國和親揭厚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法扶供,類相關(guān)的語法筛圆,內(nèi)部類的語法,繼承相關(guān)的語法椿浓,異常的語法太援,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理闽晦,服務(wù)發(fā)現(xiàn),斷路器提岔,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • JAVA面試題 1仙蛉、作用域public,private,protected,以及不寫時的區(qū)別答:區(qū)別如下:作用域 ...
    JA尐白閱讀 1,154評論 1 0
  • 據(jù)《2016大學(xué)生就業(yè)質(zhì)量研究》公布的一組數(shù)據(jù)表明荠瘪,當(dāng)前,我國大學(xué)生就業(yè)形勢嚴(yán)峻赛惩。當(dāng)年高校畢業(yè)生有765萬人哀墓,創(chuàng)歷...
    于小魚_sy閱讀 369評論 0 0
  • 剛在朋友圈群聊時季惯,又有人說被騙了吠各! 可是十年過去了,騙子依舊在騙勉抓,人們依舊在罵贾漏。真的是騙子年年有,今年特別多琳状。 今...
    塔塔西城閱讀 834評論 2 2