導航:首頁 > 源碼編譯 > 文章源碼帶介面

文章源碼帶介面

發布時間:2023-11-29 11:44:02

『壹』 求個藍奏雲直連解析介面,或者是源碼

介面和源碼我都有。

源碼我不知道有沒有用,因為沒php環境,不過以前測試過是可以用的!

1,介面地址:放個圖片你們自己看。

2,源碼地址 :就是上面這個介面的源碼

<?php

functionMloocCurl($url,$method,$ifurl,$post_data){
$UserAgent='Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/63.0.3239.132Safari/537.36';#設置ua
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_USERAGENT,$UserAgent);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
if($method=="post"){
curl_setopt($curl,CURLOPT_REFERER,$ifurl);
curl_setopt($curl,CURLOPT_POST,1);
curl_setopt($curl,CURLOPT_POSTFIELDS,$post_data);
}
$response=curl_exec($curl);
curl_close($curl);
return$response;
}
if(!empty($_GET['url'])){
$url=$_GET['url'];
#第一步
$ruleMatchDetailInList="~ifr2"sname="[sS]*?"ssrc="/(.*?)"~";
preg_match($ruleMatchDetailInList,MloocCurl($url,null,null,null),$link);
$ifurl="https://www.lanzous.com/".$link[1];
#第二步
$ruleMatchDetailInList="~=s'(.*?)';[Ss]*?=s'(.*?)'[Ss]*?=s'(.*?)'[Ss]*?=s'(.*?)'~";
preg_match($ruleMatchDetailInList,MloocCurl($ifurl,null,null,null),$segment);
#第三步
#post提交的數據
$post_data=array(
"action"=>$segment[1],
"file_id"=>$segment[2],
"t"=>$segment[3],
"k"=>$segment[4]
);
$obj=json_decode(MloocCurl("https://www.lanzous.com/ajaxm.php","post",$ifurl,$post_data));#json解析
if($obj->dom==""){#判斷鏈接是否正確
echo"鏈接有誤!";
}else{
$downUrl=$obj->dom."/file/".$obj->url."/&type=down/";
if(!empty($_GET['type'])){
$type=$_GET['type'];
if($type=="down"){
header('Location:'.$downUrl);#直接下載
}else{
header('Location:'.$downUrl);#直接下載
}
}else{
header('Location:'.$downUrl);#直接下載
}
}
}else{
$result_url=str_replace("index.php","","//".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']."");
echo"藍奏雲直連下載";
echo"<br/>";
/*echo"直接下載:"."<ahref='".$result_url."&type=down'target='_blank'>".$result_url."&type=down</a>";
echo"<br/>";
echo"輸出直鏈:"."<ahref='".$result_url."'target='_blank'>".$result_url."</a>";*/
}
?>

『貳』 源代碼怎麼使用

問題一:網站源碼怎麼使用 一般下載的網站源碼,都有後台管理系統的。沒必要在本地修改。
你直接去不復制上傳到你的空間上去。進入後台添加文章類的管理。你想做動態的話要看你的源碼支持不支持。

問題二:源碼怎麼使用 下個VC++6.0 或者vs2008 以上的c/c++編譯
打開那個後綴為.cpp的文件
然後編譯運行連接 vc6中按ctrl+F5 vs2008中 先按F7 再按F5
就會產生.exe的可執行程序了

問題三:得到C語言源代碼後怎樣使用? 如果是「.cpp」文件並且有VC++的環境,可直接雙擊文件打開或者先打開編譯環境,在新建一個控制台下的源文件,然後,選擇file菜單下的open找到你的文件導入,然後編譯運行;如果是其他格式的,如txt文件,也可先打開編譯環境,新建一個控制台下的源文件,然後直接復制粘貼進去,然後編譯運行;
便已運行的操作如圖:

問題四:css代碼怎麼用 CSS代碼主要是用來修飾HTML的 現在網站前台開發時 HTML DOM CSS javaSCRIPT 頁面的哪個部分應該怎麼呈現 字體多大 什麼顏色 等等 都是用CSS來調試的

問題五:網上下載的源代碼怎麼用啊 一般來說,網上下載源代碼的時候,需要先弄清楚源代碼的編譯環境。最理想的情況就是下載你所需編譯環境的代碼。當然,如果沒有適合你編譯環境的代碼,你可以先用源代碼編寫時候的環境來打開,然後再把需要的代碼拷貝到自己的環境下。

問題六:知道了軟體的源代碼,有什麼用,怎麼用啊? 源代碼(也稱源程序),是指一系列人類可讀的計算機語言指令。
在現代程序語言中,源代碼可以是以書籍或者磁帶的形式出現,但最為常用的格式是文本文件,這種典型格式的目的是為了編譯出計算機程序。計算機源代碼的最終目的是將人類可讀的文本翻譯成為計算機可以執行的二進制指令,這種過程叫做編譯,通過編譯器完成。
作用 :
源代碼主要功用有如下2種作用:
生成目標代碼,即計算機可以識別的代碼。
對軟體進行說明,即對軟體的編寫進行說明。為數不少的初學者,甚至少數有經驗的程序員都忽視軟體說明的編寫,因為這部分雖然不會在生成的程序中直接顯示,也不參與編譯。但是說明對軟體的學習、分享、維護和軟體復用都有巨大的好處。因此,書寫軟體說明在業界被認為是能創造優秀程序的良好習慣,一些公司也硬性規定必須書寫。
需要指出的是,源代碼的修改不能改變已經生成的目標代碼。如果需要目標代碼做出相應的修改,必須重新編譯。

問題七:這個代碼怎麼用。。。 這是網路發帖的腳本,使用成功的前提是你已經用網路賬號登陸,並且在某個你想發帖的貼吧有發帖許可權
使用方法時,直接賦值粘貼到瀏覽器的地址欄回車即可。有些瀏覽器可能稍有不同,例如chrome中你可能需要在javascript的控制台中鍵入這些代碼
我需要提醒你的是:你貼的這個代碼的作用是把我愛你重復發表999次,因為這個行為而被封號的風險你要自己想清楚,或者你可以在其中嵌入延遲代碼,當然那又是另外的事情了。

問題八:這個代碼屬於什麼代碼,要如何使用??? Calibre is a famous open-source ebook software, we you pasted here is some codes of its python version.
If all you want is to use the software, download link is below:
calibre-ebook/
If you wanna contribute to it, you may 'git' it:
git clone git:github/kovidgoyal/calibre.git
Well, to modify the source, you need to learn python or C first, of course ;)

問題九:怎麼用網頁中的源代碼下載視頻? 看是哪個網站了,如果是下載鏈接直接右擊另存為就OK了。要是網站的源代碼可能需要下載播放器

問題十:VB程序源碼如何使用 你需要安裝vb6.0開發軟體
如果安裝了,就可以直接打開源碼測試了,後綴名是vbp,(就是vb的工程文件)
如果沒有安裝vb6.0,還想打開源碼看程序,那就右擊 用記事本 打開後綴名為frm的文件,他是vb的窗口文件,源碼都在他裡面
一般得源碼是沒有生成exe可執行文件的,那樣文件太多,太大,浪費空間
如果你自己想生成exe可執行文件,那就vb6.0得文件菜單中把文件保存成exe可執行文件就可以了,非常簡單
好運!

『叄』 MyBatis­Plus快速入門源碼筆記共享,拿走吧你

為什麼要學習它呢?

答:MyBatisPlus可以節省我們大量工作時間,所有的CRUD代碼它都可以自動化完成!

優點:
1. 易於上手和掌握。
2. sql寫在xml里,便於統一管理和優化。
3. 解除sql與程序代碼的耦合。
4. 提供映射標簽,支持對象與資料庫的orm欄位關系映射
5. 提供對象關系映射標簽,支持對象關系組建維護
6. 提供xml標簽,支持編寫動態sql。

MyBatis Plus(簡稱 MP)是一個 MyBatis的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。

就像 魂斗羅 中的 1P、2P,基友搭配,效率翻倍。

特性:

無侵入 :只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑。

損耗小 :啟動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作 強大的 CRUD 操作 :內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求 支持 Lambda 形式調用 :通過 Lambda 表達式,方便地編寫各類查詢條件,無需再擔心欄位寫錯。

支持組件自動生成 :支持多達 4 種主鍵策略(內含分布式唯一 ID 生成器 Sequence),可自由配置,完美解決主鍵問題。

支持 ActiveRecord 模式 :支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可進行強大的 CRUD 操作。

支持自定義全局通用操作 :支持全局通用方法注入( Write once, use anywhere )。

內置代碼生成器 :採用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用 內置分頁插件 :基於 MyBatis 物理分頁,開發者無需關心具體操作,配置好插件之後,寫分頁等同於普通 List查詢。

分頁插件支持多種資料庫 :支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種資料庫。

內置性能分析插件 :可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢。

內置全局攔截插件 :提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規則,預防誤操作。

1.1 、引入mybatis-plus相關maven依賴


引入mybatis-plus在spring boot中的場景啟動器


ps:切記不可再在pom.xml文件中引入mybatis與mybatis-spring的maven依賴,這一點,mybatis-plus的官方文檔中已經說明的很清楚了.

1.2、創建數據表

(1)SQL語句



(2) 數據表結構

1.3、 創建java bean

根據數據表新建相關實體類

1 package com.example.demo.pojo



1.4、 配置application.proprties

數據源使用druid



ps:在進行crud實驗之前,簡單對mybatis與mybatis-plus做一個簡單的對比

2.1、mybatis與mybatis-plus實現方式對比

(1)提出問題: 假設我們已存在一張 tbl_employee 表,且已有對應的實體類 Employee,實現 tbl_employee 表的 CRUD操作我們需要做什麼呢?

(2)實現方式: 基於 Mybatis 需要編寫 EmployeeMapper 介面,並手動編寫 CRUD 方法 提供 EmployeeMapper.xml 映射文件,並手動編寫每個方法對應的 SQL 語句. 基於 Mybatis-plus 只需要創建 EmployeeMapper 介面, 並繼承BaseMapper 介面.這就是使用 mybatis-plus 需要完成的所有操作,甚至不需要創建 SQL 映射文件。

2.2、BaseMapper介面介紹

(1)如何理解核心介面BaseMapper?

在使用Mybatis-Plus時,核心操作類是BaseMapper介面,其最終也是利用的Mybatis介面編程的實現機制,其默認提供了一系列的增刪改查的基礎方法,並且開發人員對於這些基礎操作不需要寫SQL進行處理操作(Mybatis提供的機制就是需要開發人員在mapper.xml中提供sql語句),那樣我們可以猜測肯定是Mybatis-Plus完成了BaseMapper介面提供的方法的SQL語句的生成操作。

(2)BaseMapper介面為我們定義了哪些方法?

BaseMapper介面源碼:





(3) mybatis-plus中常用的註解 1


由於我們的數據表名於實體類的類名不一致,並且實體類於數據表還存在欄位名不對應的情況,因此我們需要引入mybatis-plus的註解.



編寫EmployeeMapper介面繼承BaseMapper介面



准備考試環境:



(1)插入



(2)修改



控制台列印出的sql語句

如果我們不設置實體類的email與gender屬性,結果是怎樣的呢?



控制台sql語句:

顯然,mybatis-plus為我們做了非空判斷,空值的話,默認不更新對應的欄位.想一想,這是不是類似於mybatis中的動態sql呢?

這種處理效果又會帶來什麼好處呢?

(3)查詢



selectById方法



selectBatchIds方法



ps:發現該方法底層使用的竟然是sql的in關鍵字

selectByMap方法



(4)刪除



3、不得不提的條件構造器---Wrapper

3.1.wrapper及其子類介紹

(1)Wrapper :條件構造抽象類,最頂端父類,抽象類中提供3個方法以及其他方法.

『肆』 如何高效閱讀源代碼

下面是之前寫的一篇文章:《如何快速閱讀源碼》

本文探討在需要了解一個開源項目時,如何快速的理清開源項目的代碼邏輯!

以下是個人認為行之有效的方法:

本文以Mybatis為例來進行演示!

先「跑起來」

程序界有個老傳統,學習新技術時都是從「Hello World」開始的!無論是學習新語言時,列印「Hello World」;還是學習新框架時編寫個demo!那為什麼這里的「跑起來」要打個引號呢?

實際上,當你想要閱讀一個開源項目的源碼時,絕大部分情況下,你已經能夠使用這個開源項目了!所以這里的「跑起來」就不是寫個「Hello World」,也不是能跑起來的程序了!而是能__在你的腦子里「跑起來」__!什麼意思?

Mybatis你會用了吧?那麼請問Mybatis是如何執行的呢?仔細想想,你能否用完整的語句把它描述出來?

這里是Mybatis的官方入門文章!你是如何看這篇文章的?讀一遍就行了嗎?還是跟著文章跑一遍就夠了嗎?從這篇文章里你能獲得多少信息?

我們來理一下:

回答出了上面這些問題!你也就基本能在腦子里把Mybatis「跑起來」了!之後,你才能正真的開始閱讀源碼!

當你能把一個開源項目「跑起來」後,實際上你就有了對開源項目最初步的了解了!就像「 書的索引 」一樣!基於這個索引,我們一步步的進行拆解,來細化出下一層的結構和流程,期間可能需要深入技術細節,考量實現,考慮是否有更好的實現方案!也就是說後面的三步並不是線性的,而是__不斷交替執行__的一個過程!最終就形成一個完整的源碼執行流程!

自頂向下拆解

繼續通過Mybatis來演示(限於篇幅,我只演示一個大概流程)!我們現在已經有了一個大概的流程了:

雖說每個點都可以往下細化,但是也分個輕重緩急!

很明顯,SqlSession去執行 sql才是Mybatis的核心!我們先從這個點入手!

首先,你當然得先下載Mybatis的源碼了(請自行下載)!

我們直接去看SqlSession!它是個介面,裡面有一堆執行sql的方法!

這里只列出了一部分方法:

SqlSession就是通過這些方法來執行sql的!我們直接看我們常用的,也是Mybatis推薦的用法,就是基於Mapper的執行!也就是說「SqlSession通過Mapper來執行具體的sql」!上面的流程也就細化成了:

那SqlSession是如何獲取Mapper的呢?Mapper又是如何執行sql的呢?

深入細節

我們來看SqlSession的實現!SqlSession有兩個實現類SqlSessionManager和DefaultSqlSession!通過IDE的引用功能可以查看兩個類的使用情況。你會發現SqlSessionManager實際並沒有使用!而DefaultSqlSession是通過DefaultSqlSessionFactory構建的!所以我們來看DefaultSqlSession是如何構建Mapper的!

它直接委託給了Configuration的getMapper方法!

Configuration又委託給了MapperRegistry類的getMapper方法!

在MapperRegistry類的getMapper中:

在這里knowMappers是什麼?MapperProxyFactory又是什麼?mapperProxyFactory.newInstance(sqlSession)具體做了什麼?

其實很簡單,knowMappers是個Map,裡麵包含了class與對應的MapperProxyFactory的對應關系!MapperProxyFactory通過newInstance來構建對應的Mapper(實際上是Mapper的代理)!

快接近真相了,看mapperProxyFactory.newInstance(sqlSession)里的代碼:

這里幹了什麼?

最終實際還是委託給了sqlSession去執行具體的sql!後面具體怎麼實現的就自行查看吧!

延伸改進

現在我們的流程大概是這樣的一個過程:

現在我們大概知道了:

那麼,

這個問題列表可以很長,可以按個人需要去思考並嘗試回答!可能最終這些問題已經和開源項目本身沒有什麼關系了!但是你思考後的收獲要比看源碼本身要多得多!

再循環

一輪結束後,可以再次進行:

不斷的拆解->深入->改進,最終你能__通過一個開源項目,學習到遠比開源項目本身多得多的知識__!

最重要的是,你的流程是完整的。無論是最初的大致流程:

還是到最終深入的細枝末節,都是個完整的流程!

這樣的好處是,你的時間能自由控制:

而不像debug那樣的方式,需要一下子花費很長的時間去一步步的理流程,費時費力、收效很小,而且如果中斷了就很難繼續了!

總結

本文通過梳理Mybatis源碼的一個簡單流程,來講述一個個人認為比較好的閱讀源碼的方式,並闡述此方法與傳統debug方式相比的優勢。

閱讀源碼是每個優秀開發工程師的必經之路,那麼這篇文章就來講解下為什麼要閱讀源碼以及如何閱讀源碼。

首先來說下為什麼要讀源碼,有學習源碼的必要嗎?

為什麼要閱讀源碼?

關於為什麼閱讀和學習源碼,我個人認為可能有以下幾點:

(一)吊打面試官,應對面試

為了找到更好的工作,應對面試,因為在面試中肯定會問到源碼級別的問題,比如:為什麼 HashMap 是線程不安全的?

如果你沒有閱讀過源碼,面試官可能會對回答的結果不滿意,進而導致面試結果不太理想,但如果你對源碼有所研究,並能夠很好地問答面試官的問題,這可能就是你的加分點,可以形成自己獨特的競爭力,吊打面試官,升職加薪不是夢。

(二)解決問題(bug)

在開發過程中,我們或多或少會遇到 bug,比如:在 foreach 循環里進行元素的 remove/add 操作,為啥有可能會報 異常?

我們可以先在 Google、Stack Overflow 以及對應項目的 Issues 里看有沒有類似問題以及解決辦法,如果沒有的話,我們只能通過閱讀源碼的方式去解決了。如果我們對相關源碼有所涉獵,就可以快速定位到問題所在。

(三)提升編程能力

和閱讀一本好書一樣,閱讀源碼就是和編程大牛面對面交流的機會,在許多優秀的開源項目中,它們的編碼規范和架構設計都是很棒的,另外在設計上也使用了大量的設計模式,通過閱讀和學習源碼,能夠快速提升我們的編碼水平,以及對設計模式有更深的理解。

同時,在我們閱讀完一個源碼後,可以觸類旁通,能夠快速地對其他框架的源碼進行閱讀和學習,減少時間成本。

除了上述提到的原因之外,可能還有許多,在這里就不一一贅述了,那麼在確定了要閱讀源碼之後,就讓我們看下如何閱讀源碼吧!

如何閱讀源碼?

如何閱讀源碼取決於你為什麼要讀源碼,比如:

下面大概說下閱讀源碼的幾點建議:

在閱讀之前,可以先從開源項目的官網上看它的架構設計和功能文檔,了解這個項目的 整體架構、模塊組成以及各個模塊之間的聯系

如果沒有對應的項目文檔,可以根據代碼的模塊進行梳理,以形成對項目的初步了解,或者 查看已有的源碼解析文章或者書籍 ,在閱讀源碼之前,了解項目的架構和思路會使閱讀源碼事半功倍。

在了解一個類的時候,可以使用 ctrl+F12 來查看類中的成員變數和方法。

可以通過 IDEA 的 Diagrams 功能去了解一個類的繼承關系。

多打 斷點調試 ,斷點追蹤源碼是很好的閱讀源碼的方式,可以先通過 debug 了解下調用邏輯,都和哪些類有關聯,有大致了解後再通過 debug 了解整體代碼的功能實現,各個類都起到了什麼作用,有沒有涉及到設計模式等。

另外,優秀的開源項目中肯定會有許多地方應用到了 設計模式 ,建議在閱讀源碼之前,需要對常用的設計模式有大致的了解,不然閱讀源碼的效率會大大降低。

如果遇到讀不懂某部分源碼的時候,可以先跳過,之後再回來看,如果屬於搞不懂這部分就茶不思飯不想的人,可以在網上找是否有該部分源碼的解析或者文檔,也可以自己通過 源碼注釋和測試用例 去閱讀學習。

一般優秀的開源項目都會有 單元測試 ,可以通過對應類的單元測試去了解方法的含義和用法,加深對源碼邏輯的理解。

在閱讀源碼的時候,可以在代碼上加上 注釋和總結 ,同時還可以畫出 時序圖和類圖 ,這樣對閱讀源碼有很大的幫助,可以很清楚地知道類之間的調用關系和依賴關系,也方便以後回顧,重新閱讀。

在這里推薦大家一個 IDEA 插件 SequenceDiagram,可以根據源碼生成調用時序圖,便於閱讀源碼。

剛開始閱讀源碼,不建議直接看框架源碼,可以先從 jdk 源碼看起:

jdk 源碼也是非常龐大的,可以分模塊來閱讀,下面是建議的閱讀順序:

其他包下的代碼也可以做下了解,JDK源碼閱讀筆記:https://github.com/wupeixuan/JDKSourceCode1.8

再有了一定的源碼閱讀經驗後,可以再去學習 Spring、Spring Boot、Dubbo、Spring Cloud 等框架的源碼。

總結

主要介紹了為什麼讀源碼以及如何讀源碼,供大家參考,每個人都有適合自己的閱讀源碼的方式,希望可以在學習中去摸索出一套屬於自己的方式。

閱讀源碼不是一蹴而就的,這是持久戰,只要你能夠堅持下來,肯定受益匪淺。閱讀源碼的過程比較枯燥,可以在社群里一起討論學習,這樣可能效率更高些。

沒看過源代碼,都不好意思出來說了,最近剛好在看一些,來說一個。

先看使用 https://element.eleme.cn/#/zh-CN/component/installation


先看一下這個庫是做什麼用的,然後提供了哪些功能。

看GitHub https://github.com/elemefe


一般會看下項目最新的情況,然後沒有關閉的issue,看下wiki,大家在討論什麼。

再看代碼


clone 一份到本地,然後先看下目錄結構,然後根據文檔看幾個簡單的組件的時候,一邊看掘金上的分析,一邊自己看下實現。


e le

餓了么這個框架代碼結構還是很清楚的,基本上每個組件都是分開的,所以你只要看其他的一個文件夾就行。然後一些工具的都在src文件夾。



要學會看issue,一般開源的項目都有人會來提建議,有些是bug,有些是功能,你可以看看自己是否有能力去解決,如果可以的話,你可以去fork代碼,然後自己修改,再提pr。

我最近恰好找摸索出一個梳理遺留系統架構的技巧:自底向上 找到一個典型的切面 沿著調用和回調的路徑 在代碼中添加結構化注釋(比如eclipse中加//TAG 流程A1.1 甲->>乙),這樣便得到了一個code地圖,並且在tasks視圖中看起來很直觀(看起來跟書的目錄一樣)可快速跳轉。將目錄到有道雲筆記的markdown序列圖中 就自動生成了一個序列圖。

我覺得這基本上就是可縮放的可視化架構地圖了,對維護一個比較亂和龐大的遺留系統非常有幫助,定位代碼 修改維護都方便多了。

1、需要過硬的基礎知識,這個前提。不然基本語法、常用的模式都不曉得怎麼讀。

2、多參考 歷史 版本和更新變化,好的源碼都是反復迭代出來的精華,開始就讀精華是很不明智的,所以看看版本更新說明,版本的 歷史 演變。就想人一樣是怎樣進化過來的。

3、參考別人閱讀注釋,想必在你讀源碼之前也有人讀過了源碼,並且總結,注釋。和分享原理,可供你參考,畢竟每個人讀一篇文章,理解的東西是有差異化的。

4、直接買書,有些作品直接出書就是源碼精解

5、找個大神給你慢慢分析,這個最快。娓娓道來,直接面授比啥都強。缺點是,你容易跟著他的思維走下去。

我覺得閱讀代碼就不應該高效,而應該像看小說一樣,看的過程就像是在和作者交流,有趣才是看代碼的動力。

畫圖,看數據走向,邏輯走向

先弄清楚這些代碼實現了哪些功能,然後從主線開始往下看,好的代碼光看變數和介面名稱就能明白是什麼意思?扒出源碼實現的整體框架邏輯,然後再對自己感興趣的模塊進行剖析,還是從整體把握,細節深入,慢慢地整個框架就被豐滿了。

接下來是思考為什麼要如此設計,這樣設計的好處是什麼?如果是你來做應該怎麼設計,把你覺得源碼缺點的地方進行仔細研究,了解裡面是否包含自己不清楚的細節,避免遺漏。

接下來就是根據代碼改造或者是調試錯誤,對於源碼中遇到的不理解的地方一定要弄明白,有的確實是畫蛇添足,有的有獨特的作用。

多多學習,對每一種主流框架銘記於心,對主流設計模式了如指掌,萬變不離其宗,源碼看多了,跟看一個電視機遙控器的操作說明一樣。

1、一邊閱讀代碼一邊寫注釋。這是我用過的最好的方法,對代碼理解得更深入,看一些重要代碼或者特別難懂的代碼時挺有用。更何況,注釋也是一種文檔嘛。

2、一邊閱讀代碼一邊繪制UML。這個方法適用於類之間的關系較復雜和調用層次較深的情況,我一般都是先繪制順序圖,然後為順序圖中的類繪制關系圖。

3、通過Debug來跟蹤程序的主要執行過程,這樣就可以分清主次了,閱讀的時候更有針對性。

4、類的快速閱讀。先弄清楚它在繼承鏈中的位置,看看它的內部狀態,也就是成員變數,一般來說,類的對外介面都是對成員變數的訪問、加工、代理等,然後看看它的對外介面,也就是公有成員函數,識別核心的一個或多個函數,這時候你應該可以大概了解這個類的職責或作用了。可能這個類是某個設計模式中的一個組成部分,所以,設計模式的掌握對代碼的快速閱讀也是很有幫助的。

5、帶著問題去閱讀。比如想了解android中的消息機制,那麼看看Looper、Handler、MessegeQueue這幾個類就可以了,其他的不要去看,要不然就跑題了。

下面列幾個閱讀源碼時所處的情景,在特定場景下用哪些方法: 不太熟悉業務邏輯,還不是很清楚它是幹啥的,可以用3、5。 代碼量很大,有幾十萬行,甚至百萬行,可以用2、3、5。 你無法看見程序的運行過程,比如沒有用戶界面,也有可能是無法運行的,可以用3、5。 設計復雜,用了大量的設計模式,調用鏈很深,可以用1、2、3、4、5。 時間有限,沒有那麼多時間讓你看源碼,可以用3、5。

畫出邏輯流程圖,先了解整體流程,再詳解具體函數

『伍』 「高並發」兩種非同步模型與深度解析Future介面-

大家好,我是冰河~~

本文有點長,但是滿滿的干貨,以實際案例的形式分析了兩種非同步模型,並從源碼角度深度解析Future介面和FutureTask類,希望大家踏下心來,打開你的IDE,跟著文章看源碼,相信你一定收獲不小!

在Java的並發編程中,大體上會分為兩種非同步編程模型,一類是直接以非同步的形式來並行運行其他的任務,不需要返回任務的結果數據。一類是以非同步的形式運行其他任務,需要返回結果。

1.無返回結果的非同步模型

無返回結果的非同步任務,可以直接將任務丟進線程或線程池中運行,此時,無法直接獲得任務的執行結果數據,一種方式是可以使用回調方法來獲取任務的運行結果。

具體的方案是:定義一個回調介面,並在介面中定義接收任務結果數據的方法,具體邏輯在回調介面的實現類中完成。將回調介面與任務參數一同放進線程或線程池中運行,任務運行後調用介面方法,執行回調介面實現類中的邏輯來處理結果數據。這里,給出一個簡單的示例供參考。

便於介面的通用型,這里為回調介面定義了泛型。

回調介面的實現類主要用來對任務的返回結果進行相應的業務處理,這里,為了方便演示,只是將結果數據返回。大家需要根據具體的業務場景來做相應的分析和處理。

任務的執行類是具體執行任務的類,實現Runnable介面,在此類中定義一個回調介面類型的成員變數和一個String類型的任務參數(模擬任務的參數),並在構造方法中注入回調介面和任務參數。在run方法中執行任務,任務完成後將任務的結果數據封裝成TaskResult對象,調用回調介面的方法將TaskResult對象傳遞到回調方法中。

到這里,整個大的框架算是完成了,接下來,就是測試看能否獲取到非同步任務的結果了。

在測試類中,使用Thread類創建一個新的線程,並啟動線程運行任務。運行程序最終的介面數據如下所示。

大家可以細細品味下這種獲取非同步結果的方式。這里,只是簡單的使用了Thread類來創建並啟動線程,也可以使用線程池的方式實現。大家可自行實現以線程池的方式通過回調介面獲取非同步結果。

2.有返回結果的非同步模型

盡管使用回調介面能夠獲取非同步任務的結果,但是這種方式使用起來略顯復雜。在JDK中提供了可以直接返回非同步結果的處理方案。最常用的就是使用Future介面或者其實現類FutureTask來接收任務的返回結果。

使用Future介面往往配合線程池來獲取非同步執行結果,如下所示。

運行結果如下所示。

FutureTask類既可以結合Thread類使用也可以結合線程池使用,接下來,就看下這兩種使用方式。

結合Thread類的使用示例如下所示。

運行結果如下所示。

結合線程池的使用示例如下。

運行結果如下所示。

可以看到使用Future介面或者FutureTask類來獲取非同步結果比使用回調介面獲取非同步結果簡單多了。注意:實現非同步的方式很多,這里只是用多線程舉例。

接下來,就深入分析下Future介面。

1.Future介面

Future是JDK1.5新增的非同步編程介面,其源代碼如下所示。

可以看到,在Future介面中,總共定義了5個抽象方法。接下來,就分別介紹下這5個方法的含義。

取消任務的執行,接收一個boolean類型的參數,成功取消任務,則返回true,否則返回false。當任務已經完成,已經結束或者因其他原因不能取消時,方法會返回false,表示任務取消失敗。當任務未啟動調用了此方法,並且結果返回true(取消成功),則當前任務不再運行。如果任務已經啟動,會根據當前傳遞的boolean類型的參數來決定是否中斷當前運行的線程來取消當前運行的任務。

判斷任務在完成之前是否被取消,如果在任務完成之前被取消,則返回true;否則,返回false。

這里需要注意一個細節:只有任務未啟動,或者在完成之前被取消,才會返回true,表示任務已經被成功取消。其他情況都會返回false。

判斷任務是否已經完成,如果任務正常結束、拋出異常退出、被取消,都會返回true,表示任務已經完成。

當任務完成時,直接返回任務的結果數據;當任務未完成時,等待任務完成並返回任務的結果數據。

當任務完成時,直接返回任務的結果數據;當任務未完成時,等待任務完成,並設置了超時等待時間。在超時時間內任務完成,則返回結果;否則,拋出TimeoutException異常。

2.RunnableFuture介面

Future介面有一個重要的子介面,那就是RunnableFuture介面,RunnableFuture介面不但繼承了Future介面,而且繼承了java.lang.Runnable介面,其源代碼如下所示。

這里,問一下,RunnableFuture介面中有幾個抽象方法?想好了再說!哈哈哈。。。

這個介面比較簡單run()方法就是運行任務時調用的方法。

3.FutureTask類

FutureTask類是RunnableFuture介面的一個非常重要的實現類,它實現了RunnableFuture介面、Future介面和Runnable介面的所有方法。FutureTask類的源代碼比較多,這個就不粘貼了,大家自行到java.util.concurrent下查看。

(1)FutureTask類中的變數與常量

在FutureTask類中首先定義了一個狀態變數state,這個變數使用了volatile關鍵字修飾,這里,大家只需要知道volatile關鍵字通過內存屏障和禁止重排序優化來實現線程安全,後續會單獨深度分析volatile關鍵字是如何保證線程安全的。緊接著,定義了幾個任務運行時的狀態常量,如下所示。

其中,代碼注釋中給出了幾個可能的狀態變更流程,如下所示。

接下來,定義了其他幾個成員變數,如下所示。

又看到我們所熟悉的Callable介面了,Callable介面那肯定就是用來調用call()方法執行具體任務了。

看一下WaitNode類的定義,如下所示。

可以看到,WaitNode類是FutureTask類的靜態內部類,類中定義了一個Thread成員變數和指向下一個WaitNode節點的引用。其中通過構造方法將thread變數設置為當前線程。

(2)構造方法

接下來,是FutureTask的兩個構造方法,比較簡單,如下所示。

(3)是否取消與完成方法

繼續向下看源碼,看到一個任務是否取消的方法,和一個任務是否完成的方法,如下所示。

這兩方法中,都是通過判斷任務的狀態來判定任務是否已取消和已完成的。為啥會這樣判斷呢?再次查看FutureTask類中定義的狀態常量發現,其常量的定義是有規律的,並不是隨意定義的。其中,大於或者等於CANCELLED的常量為CANCELLED、INTERRUPTING和INTERRUPTED,這三個狀態均可以表示線程已經被取消。當狀態不等於NEW時,可以表示任務已經完成。

通過這里,大家可以學到一點:以後在編碼過程中,要按照規律來定義自己使用的狀態,尤其是涉及到業務中有頻繁的狀態變更的操作,有規律的狀態可使業務處理變得事半功倍,這也是通過看別人的源碼設計能夠學到的,這里,建議大家還是多看別人寫的優秀的開源框架的源碼。

(4)取消方法

我們繼續向下看源碼,接下來,看到的是cancel(boolean)方法,如下所示。

接下來,拆解cancel(boolean)方法。在cancel(boolean)方法中,首先判斷任務的狀態和CAS的操作結果,如果任務的狀態不等於NEW或者CAS的操作返回false,則直接返回false,表示任務取消失敗。如下所示。

接下來,在try代碼塊中,首先判斷是否可以中斷當前任務所在的線程來取消任務的運行。如果可以中斷當前任務所在的線程,則以一個Thread臨時變數來指向運行任務的線程,當指向的變數不為空時,調用線程對象的interrupt()方法來中斷線程的運行,最後將線程標記為被中斷的狀態。如下所示。

這里,發現變更任務狀態使用的是UNSAFE.putOrderedInt()方法,這個方法是個什麼鬼呢?點進去看一下,如下所示。

可以看到,又是一個本地方法,嘿嘿,這里先不管它,後續文章會詳解這些方法的作用。

接下來,cancel(boolean)方法會進入finally代碼塊,如下所示。

可以看到在finallly代碼塊中調用了finishCompletion()方法,顧名思義,finishCompletion()方法表示結束任務的運行,接下來看看它是如何實現的。點到finishCompletion()方法中看一下,如下所示。

在finishCompletion()方法中,首先定義一個for循環,循環終止因子為waiters為null,在循環中,判斷CAS操作是否成功,如果成功進行if條件中的邏輯。首先,定義一個for自旋循環,在自旋循環體中,喚醒WaitNode堆棧中的線程,使其運行完成。當WaitNode堆棧中的線程運行完成後,通過break退出外層for循環。接下來調用done()方法。done()方法又是個什麼鬼呢?點進去看一下,如下所示。

可以看到,done()方法是一個空的方法體,交由子類來實現具體的業務邏輯。

當我們的具體業務中,需要在取消任務時,執行一些額外的業務邏輯,可以在子類中覆寫done()方法的實現。

(5)get()方法

繼續向下看FutureTask類的代碼,FutureTask類中實現了兩個get()方法,如下所示。

沒參數的get()方法為當任務未運行完成時,會阻塞,直到返回任務結果。有參數的get()方法為當任務未運行完成,並且等待時間超出了超時時間,會TimeoutException異常。

兩個get()方法的主要邏輯差不多,一個沒有超時設置,一個有超時設置,這里說一下主要邏輯。判斷任務的當前狀態是否小於或者等於COMPLETING,也就是說,任務是NEW狀態或者COMPLETING,調用awaitDone()方法,看下awaitDone()方法的實現,如下所示。

接下來,拆解awaitDone()方法。在awaitDone()方法中,最重要的就是for自旋循環,在循環中首先判斷當前線程是否被中斷,如果已經被中斷,則調用removeWaiter()將當前線程從堆棧中移除,並且拋出InterruptedException異常,如下所示。

接下來,判斷任務的當前狀態是否完成,如果完成,並且堆棧句柄不為空,則將堆棧中的當前線程設置為空,返回當前任務的狀態,如下所示。

當任務的狀態為COMPLETING時,使當前線程讓出CPU資源,如下所示。

如果堆棧為空,則創建堆棧對象,如下所示。

如果queued變數為false,通過CAS操作為queued賦值,如果awaitDone()方法傳遞的timed參數為true,則計算超時時間,當時間已超時,則在堆棧中移除當前線程並返回任務狀態,如下所示。如果未超時,則重置超時時間,如下所示。

如果不滿足上述的所有條件,則將當前線程設置為等待狀態,如下所示。

接下來,回到get()方法中,當awaitDone()方法返回結果,或者任務的狀態不滿足條件時,都會調用report()方法,並將當前任務的狀態傳遞到report()方法中,並返回結果,如下所示。

看來,這里還要看下report()方法啊,點進去看下report()方法的實現,如下所示。

可以看到,report()方法的實現比較簡單,首先,將outcome數據賦值給x變數,接下來,主要是判斷接收到的任務狀態,如果狀態為NORMAL,則將x強轉為泛型類型返回;當任務的狀態大於或者等於CANCELLED,也就是任務已經取消,則拋出CancellationException異常,其他情況則拋出ExecutionException異常。

至此,get()方法分析完成。注意:一定要理解get()方法的實現,因為get()方法是我們使用Future介面和FutureTask類時,使用的比較頻繁的一個方法。

(6)set()方法與setException()方法

繼續看FutureTask類的代碼,接下來看到的是set()方法與setException()方法,如下所示。

通過源碼可以看出,set()方法與setException()方法整體邏輯幾乎一樣,只是在設置任務狀態時一個將狀態設置為NORMAL,一個將狀態設置為EXCEPTIONAL。

至於finishCompletion()方法,前面已經分析過。

(7)run()方法與runAndReset()方法

接下來,就是run()方法了,run()方法的源代碼如下所示。

可以這么說,只要使用了Future和FutureTask,就必然會調用run()方法來運行任務,掌握run()方法的流程是非常有必要的。在run()方法中,如果當前狀態不是NEW,或者CAS操作返回的結果為false,則直接返回,不再執行後續邏輯,如下所示。

接下來,在try代碼塊中,將成員變數callable賦值給一個臨時變數c,判斷臨時變數不等於null,並且任務狀態為NEW,則調用Callable介面的call()方法,並接收結果數據。並將ran變數設置為true。當程序拋出異常時,將接收結果的變數設置為null,ran變數設置為false,並且調用setException()方法將任務的狀態設置為EXCEPTIONA。接下來,如果ran變數為true,則調用set()方法,如下所示。

接下來,程序會進入finally代碼塊中,如下所示。

這里,將runner設置為null,如果任務的當前狀態大於或者等於INTERRUPTING,也就是線程被中斷了。則調用()方法,接下來,看下()方法的實現。

可以看到,()方法的實現比較簡單,當任務的狀態為INTERRUPTING時,使用while()循環,條件為當前任務狀態為INTERRUPTING,將當前線程佔用的CPU資源釋放,也就是說,當任務運行完成後,釋放線程所佔用的資源。

runAndReset()方法的邏輯與run()差不多,只是runAndReset()方法會在finally代碼塊中將任務狀態重置為NEW。runAndReset()方法的源代碼如下所示,就不重復說明了。

(8)removeWaiter()方法

removeWaiter()方法中主要是使用自旋循環的方式來移除WaitNode中的線程,比較簡單,如下所示。

最後,在FutureTask類的最後,有如下代碼。

關於這些代碼的作用,會在後續深度解析CAS文章中詳細說明,這里就不再探討。

至此,關於Future介面和FutureTask類的源碼就分析完了。

好了,今天就到這兒吧,我是冰河,我們下期見~~

閱讀全文

與文章源碼帶介面相關的資料

熱點內容
安卓耳塞失靈怎麼辦 瀏覽:763
華三交換機保存命令 瀏覽:603
命令方塊怎麼調鍵盤 瀏覽:841
不把密碼存在伺服器上怎麼辦 瀏覽:398
怎麼讓指令方塊的命令消失 瀏覽:543
用單片機做plc 瀏覽:404
雲伺服器進入子目錄命令 瀏覽:795
伺服器機櫃如何配電 瀏覽:578
怎麼刪除iphone資源庫里的app 瀏覽:940
pdf魚 瀏覽:648
單片機pcf8591什麼作用 瀏覽:805
sql命令學院 瀏覽:283
加密軟體在電腦那個盤 瀏覽:988
android獲取外部存儲 瀏覽:573
怎麼查自己家的伺服器地址 瀏覽:858
編程c語言工作好不好 瀏覽:569
單片機焊接地怎麼連接 瀏覽:694
游戲源碼怎麼抓 瀏覽:216
程序員幫大家引走怪物 瀏覽:16
手機網頁小游戲源碼 瀏覽:513