最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

java中的反射

2022-02-08 15:34 作者:迪巴哥沒(méi)八哥  | 我要投稿

一、什么是反射

談java反射前我們先來(lái)說(shuō)說(shuō)物理界的“反射”,第一次見(jiàn)反射這個(gè)詞語(yǔ),估計(jì)還是從初中物理中看到的,我們先來(lái)看看物理界中反射的定義。


我們可以細(xì)讀這一句:在分界面上改變傳播方向又返回原來(lái)物質(zhì)的現(xiàn)象。

從這句話我們可以得知,通過(guò)反射我么可以獲取物質(zhì)的一些屬性與特質(zhì),同然,在java中反射也具有這樣的功能。

java中的反射是指在運(yùn)行過(guò)程中,對(duì)任意一個(gè)類,都能知道類的所有屬性與方法;對(duì)任意一個(gè)對(duì)象,能夠調(diào)用它任意一個(gè)方法與屬性;這種動(dòng)態(tài)獲取信息和動(dòng)態(tài)調(diào)用對(duì)象的方法就叫做java語(yǔ)言的反射機(jī)制。

接下來(lái)代碼演示:

//正常調(diào)用
ZhangSan zhangSan = new ZhangSan();
zhangSan.setAge(30);
zhangSan.setNickName("法外狂徒");
System.out.println("ZhangSan:"+zhangSan);

//使用反射調(diào)用
Class c = Class.forName("pojo.ZhangSan");
Method setAge = c.getMethod("setAge", Integer.class);
Constructor constructor = c.getConstructor();
Object o = constructor.newInstance();
setAge.invoke(o,18);
Method getAge = c.getMethod("getAge");
System.out.println("ZhangSan:"+getAge.invoke(o));

查看輸出演示:


上面兩段代碼產(chǎn)生的效果是一樣的,不同是正常調(diào)用的這段代碼是直接new對(duì)象,而反射調(diào)用是用類反射調(diào)用。

所以什么是反射?

反射是在運(yùn)行時(shí)知道要操作的類是什么,并且在運(yùn)行時(shí)獲取類的完整構(gòu)造,并調(diào)用相應(yīng)方法。

可能這時(shí)有小伙伴就要問(wèn)了,我直接正常調(diào)用他不香嗎,為啥要廢大力氣去用反射。


八哥其實(shí)也有這樣的疑惑,當(dāng)我百思不得其解時(shí),望向了窗外的一縷反射過(guò)來(lái)的陽(yáng)光,原來(lái)反射他就是一面鏡子,不用管本體在哪,只要由鏡子反射過(guò)來(lái)就可以了,我不用刻意去尋找本體,大道至簡(jiǎn),突然想起了馬斯克說(shuō)的一切皆歸于物理。



二、為什么要用反射

現(xiàn)在我們說(shuō)說(shuō)為啥要用到反射,反射的好處什么。我們先來(lái)講講跟反射相關(guān)的技術(shù)點(diǎn),最開(kāi)始我們學(xué)數(shù)據(jù)庫(kù)連接jdbc的時(shí)候就用到過(guò)。

先看看沒(méi)有用反射的數(shù)據(jù)庫(kù)連接方式

方式一:

//1.注冊(cè)驅(qū)動(dòng)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

//2.建立連接
//方法一 參數(shù)一:協(xié)議+訪問(wèn)數(shù)據(jù)庫(kù),參數(shù)二:用戶名,參數(shù)三:密碼
connection = DriverManager.getConnection("jdbc:mysql://localhost/student", "root", "password");

//3.創(chuàng)建statement,跟數(shù)據(jù)庫(kù)打交道一定需要這個(gè)對(duì)象
st = connection.createStatement()

再來(lái)看看用反射方法實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接的

方式二:

//獲取properties中的url
String url = prop.getProperty("jdbc.url");
//獲取用戶名
String username = prop.getProperty("jdbc.username");
//獲取密碼
String password = prop.getProperty("jdbc.password");

從上面的對(duì)比我們就可以看出兩種方式的區(qū)別。

方式一需要在業(yè)務(wù)代碼層面輸入用戶名和密碼,一旦有配置的變動(dòng)與修改需要自己去修改代碼,然后重新發(fā)版上線,這種方法不方便而且成本高。試想一下如果員工A離職了,員工B接受A的代碼shi山,如果配置都是在業(yè)務(wù)代碼層面的,B去查找修改時(shí)會(huì)很不方便。

方式二就顯得比較優(yōu)雅一點(diǎn),將配置與代碼解耦合,所有的配置寫(xiě)在properties文件里,這樣如果有配置變動(dòng),我們只需要在properties里修改配置就行了。


三、java中用到的反射

在java中很多地方用到了反射。比如動(dòng)態(tài)代理與spring的事務(wù)底層都用到了反射。

spring事務(wù)基本原理:

spring事務(wù)本質(zhì)是數(shù)據(jù)庫(kù)對(duì)事務(wù)的的支持,沒(méi)數(shù)據(jù)庫(kù)事務(wù)支持,Spring無(wú)法提供事務(wù)功能。

以前我們純jdbc操作的時(shí)候如果用到事務(wù),可按照如下步驟進(jìn)行:

  1. 獲取連接 Connection con=DriverManager.getConnection();

  2. 開(kāi)啟事務(wù) con.setAutoCommit(true/false);

  3. 執(zhí)行CRUD

  4. 提交事務(wù)回滾 con.commit();

  5. 關(guān)閉連接 conn.close();

后來(lái)交給spring進(jìn)行事務(wù)管理后,不用寫(xiě)步驟2與4的代碼,而是由Spring自動(dòng)完成。Spring是怎么在CRUD前后開(kāi)啟與關(guān)閉事務(wù)的呢?下面簡(jiǎn)單介紹下:

  1. 配置文件開(kāi)啟注解驅(qū)動(dòng),相關(guān)類與方法通過(guò)注解 @Transactional 標(biāo)識(shí)。

  2. spring啟動(dòng)會(huì)解析相關(guān)bean,此時(shí)查看相關(guān)注解類與方法,并且為這些類與方法生成代理,根據(jù)@Transactional 相關(guān)參數(shù)進(jìn)行配置

  3. 真正數(shù)據(jù)庫(kù)層的事務(wù)提交與回滾通過(guò)binlog或者redo log實(shí)現(xiàn)。


聲明式事務(wù):

Spring支持聲明式事務(wù),使用注解選擇需要使用事務(wù)的方法,使用@Transactional注解在方法上表明方法需要事務(wù)支持,基于AOP的實(shí)現(xiàn)操作。

AOP代理的兩種實(shí)現(xiàn):
  • jdk是代理接口,私有方法不會(huì)存在接口里,因此不會(huì)攔截到。

  • cglib是子類,private方法不會(huì)出現(xiàn)在子類,不會(huì)被攔截。


Java動(dòng)態(tài)代理

具體有如下四步驟:

  1. 實(shí)現(xiàn)invocationHandler接口創(chuàng)建自己的調(diào)用處理器

  2. 通過(guò)Proxy類指定ClassLoader對(duì)象與interface創(chuàng)建動(dòng)態(tài)代理類

  3. 反射機(jī)制獲得動(dòng)態(tài)代理類構(gòu)造函數(shù),唯一參數(shù)類型調(diào)用處理器接口類型。

  4. 構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類實(shí)例,構(gòu)造時(shí)調(diào)用處理器對(duì)象作為參數(shù)傳入。

CGLIB代理

  • cglib封裝了asm,運(yùn)行期間動(dòng)態(tài)生成class

  • cglib用于AOP,jdk的proxy基于接口,cglib沒(méi)限制。


原理區(qū)別

java動(dòng)態(tài)代理是利用反射機(jī)制生成一個(gè)實(shí)現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來(lái)處理。而cglib動(dòng)態(tài)代理是利用asm開(kāi)源包,對(duì)代理對(duì)象類的class文件加載進(jìn)來(lái),通過(guò)修改其字節(jié)碼生成子類來(lái)處理。

  1. 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,默認(rèn)情況下會(huì)采用JDK的動(dòng)態(tài)代理實(shí)現(xiàn)AOP

  1. 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,可以強(qiáng)制使用CGLIB實(shí)現(xiàn)AOP

  1. 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)了接口,必須采用CGLIB庫(kù),spring會(huì)自動(dòng)在JDK動(dòng)態(tài)代理和CGLIB之間轉(zhuǎn)換

如果是類內(nèi)部方法直接不是走代理,這個(gè)時(shí)候可以通過(guò)維護(hù)一個(gè)自身實(shí)例的代理。


java中的反射的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
宁安市| 沈阳市| 皋兰县| 文登市| 金平| 达拉特旗| 衢州市| 蓬安县| 涟水县| 丰城市| 石河子市| 得荣县| 潢川县| 稻城县| 界首市| 甘泉县| 垣曲县| 临漳县| 哈尔滨市| 谢通门县| 湟中县| 容城县| 昭苏县| 承德县| 灵山县| 库尔勒市| 于田县| 荥经县| 申扎县| 梓潼县| 孝昌县| 团风县| 南川市| 墨脱县| 宜州市| 崇左市| 绵阳市| 开远市| 桐乡市| 太康县| 邳州市|