本文由公眾號「Java旅途」整理,設計到的內容由java基礎、資料庫、SSM框架、redis、訊息佇列、spring boot、spring cloud、git及一些前端知識,整理時間為2019-11-19,首發于微信公眾號「Java旅途」,關注微信公眾號「Java旅途」,回復面試領取該pdf版資料,公眾號二維碼如下:

2019年java面試經典100問,進入BAT不是夢,如果該pdf幫助到您,請您傳閱給您的小伙伴,一起復習,共同做一個offer收割機,文章目錄如下:
目錄
- 一、java基礎
- 二、資料庫
- 三、SSM框架
- 四、redis
- 五、訊息佇列
- 六、spring boot
- 七、spring cloud
- 八、其他
一、java基礎
1、面向物件的特征有哪些方面? 【基礎】
答:面向物件的特征主要有以下幾個方面:
1)抽象:抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面,抽象并不打算了解全部問題,而只是選擇其中的一部分,暫時不用部分細節,抽象包括兩個方面,一是程序抽象,二是資料抽象,
2)繼承:繼承是一種聯結類的層次模型,并且允許和鼓勵類的重用,它提供了一種明確表述共性的方法,物件的一個新類可以從現有的類中派生,這個程序稱為類繼承,新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類),派生類可以從它的基類那里繼承方法和實體變數,并且類可以修改或增加新的方法使之更適合特殊的需要,
3)封裝:封裝是把程序和資料包圍起來,對資料的訪問只能通過已定義的界面,面向物件計算始于這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的物件,這些物件通過一個受保護的介面訪問其他物件,
4)多型性:多型性是指允許不同類的物件對同一訊息作出回應,多型性包括引數化多型性和包含多型性,多型性語言具有靈活、抽象、行為共享、代碼共享的優勢,很好的解決了應用程式函式同名問題,
2、int 和Integer 有什么區別? 【基礎】
答:Java 提供兩種不同的型別:參考型別和原始型別(或內置型別);
int 是java 的原始資料型別,Integer 是java 為int 提供的封裝類,
Java 為每個原始型別提供了封裝類:
原始型別: boolean,char,byte,short,int,long,float,double
封裝型別:Boolean,Character,Byte,Short,Integer,Long,Float,Double參考型別和原始型別的行為完全不同,并且它們具有不同的語意,參考型別和原始型別具有不同的特征和用法,它們包括:大小和速度問題,這種型別以哪種型別的資料結構存盤,當參考型別和原始型別用作某個類的實體資料時所指定的預設值,物件參考實體變數的預設值為null,而原始型別實體變數的預設值與它們的型別有關,
3、Math.round(11.5) 等于多少? Math.round(-11.5)等于多少? 【基礎】
答:Math.round(11.5)12 Math.round(-11.5)-11 round 方法回傳與引數最接近的長整數,引數加1/2 后求其floor,
4、編程題: 用最有效率的方法算出2 乘以8 等於幾? 【基礎】
答: 2 << 3,
5、陣列有沒有 length()方法?String 有沒有 length()方法?【基礎】
答:陣列沒有 length()方法,有 length 的屬性,String 有 length()方法,JavaScript 中,獲得字串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆,
6、構造器(constructor)是否可被重寫(override)?【基礎】
答:構造器不能被繼承,因此不能被重寫,但可以被多載,
7、是否可以繼承String 類? 【基礎】
答:String 類是final 類,故不可以繼承,
8、當一個物件被當作引數傳遞到一個方法后,此方法可改變這個物件的屬性,并可回傳變化后的結果,那么這里到底是值傳遞還是參考傳遞? 【基礎】
答:是值傳遞,Java 編程語言只有值傳遞引數,當一個物件實體作為一個引數被傳遞到方法中時,引數的值就是對該物件的參考,物件的內容可以在被呼叫的方法中改變,但物件的參考是永遠不會改變的,
9、String 和StringBuffer 的區別?【基礎】
答:JAVA 平臺提供了兩個類:String 和StringBuffer,它們可以儲存和操作字串,即包含多個字符的字符資料,這個String 類提供了數值不可改變的字串,而這個StringBuffer 類提供的字串進行修改,當你知道字符資料要改變的時候你就可以使用StringBuffer,典型地,你可以使用StringBuffers 來動態構造字符資料,
10、String, StringBuffer StringBuilder 的區別,【基礎】
答:String 的長度是不可變的;StringBuffer 的長度是可變的,如果你對字串中的內容經常進行操作,特別是內容要修改時,那么使用StringBuffer.如果最后需要String,那么使用StringBuffer 的toString()方法,執行緒安全;StringBuilder 是從JDK 5 開始,為StringBuffer 該類補充了一個單個執行緒使用的等價類;通常應該優先使用StringBuilder 類,因為它支持所有相同的操作,但由于它不執行同步,所以速度更快,執行緒不安全,
11、多載(Overload)和重寫(Override)的區別,多載的方法能否根據回傳型別進行區分?【基礎】
答:方法的多載和重寫都是實作多型的方式,區別在于前者實作的是編譯時的多型性,而后者實作的是運行時的多型性,多載發生在一個類中,同名的方法如果有不同的引數串列(引數型別不同、引數個數不同或者二者都不同)則視為多載;重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的回傳型別,比父類被重寫方法更好訪問,不能比父類被重寫方法宣告更多的例外(里氏代換原則),多載對回傳型別沒有特殊的要求,
12、描述一下 JVM 加載 class 檔案的原理機制?【中等】
答:JVM 中類的裝載是由類加載器(ClassLoader)和它的子類來實作的,Java 中的類加載器是一個重要的 Java 運行時系統組件,它負責在運行時查找和裝入類檔案中的類,
由于 Java 的跨平臺性,經過編譯的 Java 源程式并不是一個可執行程式,而是一個或多個類檔案,當 Java 程式需要使用某個類時,JVM 會確保這個類已經被加載、連接(驗證、準備和決議)和初始化,類的加載是指把類的.class 檔案中的資料讀入到記憶體中,通常是創建一個位元組陣列讀入.class 檔案,然后產生與所加載類對應的 Class 物件,加載完成后,Class 物件還不完整,所以此時的類還不可用,當類被加載后就進入連接階段,這一階段包括驗證、準備(為靜態變數分配記憶體并設定默認的初始值)和決議(將符號參考替換為直接參考)三個步驟,最后 JVM 對類進行初始化,包括:
1)如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類;
2)如果類中存在初始化陳述句,就依次執行這些初始化陳述句,
從 Java 2(JDK 1.2)開始,類加載程序采取了雙親委托機制(PDM),PDM 更好的保證了 Java 平臺的安全性,在該機制中,JVM 自帶的 Bootstrap 是根加載器,其他的加載器都有且僅有一個父類加載器,類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載,
13、interface可以有方法的實作嗎?【中等】
答:jdk1.8以后有方法的實作,用default修飾,
14、是否可以從一個static 方法內部發出對非static 方法的呼叫?【基礎】
答:不可以,如果其中包含物件的method(),不能保證物件初始化,
15、GC 是什么? 為什么要有GC? 【基礎】
答:GC 是垃圾收集的意思(Gabage Collection),記憶體處理是編程人員容易出現問題的地方,忘記或者錯誤的記憶體回識訓導致程式或系統的不穩定甚至崩潰,Java 提供的GC 功能可以自動監測物件是否超過作用域從而達到自動回收記憶體的目的,Java 語言沒有提供釋放已分配記憶體的顯示操作方法,Java 程式員不用擔心記憶體管理,因為垃圾收集器會自動進行管理,要請求垃圾收集,可以呼叫下面的方法之一:System.gc() 或Runtime.getRuntime().gc()
16、垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收記憶體嗎?有什么辦法主動通知虛擬機進行垃圾回收?【基礎】
答:對于GC 來說,當程式員創建物件時,GC 就開始監控這個物件的地址、大小以及使用情況,通常,GC 采用有向圖的方式記錄和管理堆(heap)中的所有物件,通過這種方式確定哪些物件是"可達的",哪些物件是"不可達的",當GC 確定一些物件為"不可達"時,GC 就有責任回收這些記憶體空間,可以,程式員可以手動執行System.gc(),通知GC 運行,但是Java 語言規范并不保證GC 一定會執行,
17、一個“.java”源檔案中是否可以包含多個類(不是內部類)?有什么限制?【基礎】
答:可以;必須只有一個類名與檔案名相同,
18、Java 中的 final 關鍵字有哪些用法?【基礎】
答:(1)修飾類:表示該類不能被繼承;(2)修飾方法:表示方法不能被重寫;(3)修飾變數:表示變數只能一次賦值以后值不能被修改(常量),
19、編碼轉換:怎樣將GB2312 編碼的字串轉換為ISO-8859-1 編碼的字串?【基礎】
答:示例代碼如下:
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
20、error 和exception 有什么區別? 【基礎】
答:error 表示系統級的錯誤和程式不必處理的例外,是恢復不是不可能但很困難的情況下的一種嚴重問題;比如記憶體溢位,不可能指望程式能處理這樣的情況;exception 表示需要捕捉或者需要程式進行處理的例外,是一種設計或實作問題;也就是說,它表示如果程式運行正常,從不會發生的情況,
21、try{}里有一個return陳述句,那么緊跟在這個try后的finally{}里的代碼會不會被執行,什么時候被執行,在return前還是后?【基礎】
答:會執行,在方法回傳呼叫者前執行,
注意:在finally中改變回傳值的做法是不好的,因為如果存在finally代碼塊,try中的return陳述句不會立馬回傳呼叫者,而是記錄下回傳值待finally代碼塊執行完畢之后再向呼叫者回傳其值,然后如果在finally中修改了回傳值,就會回傳修改后的值,顯然,在finally中回傳或者修改回傳值會對程式造成很大的困擾,C#中直接用編譯錯誤的方式來阻止程式員干這種齷齪的事情,Java中也可以通過提升編譯器的語法檢查級別來產生警告或錯誤,Eclipse中可以在如圖所示的地方進行設定,強烈建議將此項設定為編譯錯誤,
22、List,Set,Map 是否繼承自Collection 介面?【基礎】
答:List,Set 是;Map 不是,
23、說出ArrayList,Vector, LinkedList 的存盤性能和特性?【基礎】
答:ArrayList 和Vector 都是使用陣列方式存盤資料,此陣列元素數大于實際存盤的資料以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及陣列元素移動等記憶體操作,所以索引資料快而插入資料慢,Vector 由于使用了synchronized 方法(執行緒安全),通常性能上較ArrayList 差,而LinkedList 使用雙向鏈表實作存盤,按序號索引資料需要進行前向或后向遍歷,但是插入資料時只需要記錄本項的前后項即可,所以插入速度較快,
24、HashMap 和Hashtable 的區別? 【基礎】
答:二者都實作了Map 介面,是將惟一鍵映射到特定的值上;主要區別在于:
1)HashMap 沒有排序,允許一個null 鍵和多個null 值,而Hashtable 不允許;
2)HashMap 把Hashtable 的contains 方法去掉了,改成containsvalue 和containsKey,因為contains 方法容易讓人引起誤解;
3)Hashtable 繼承自Dictionary 類,HashMap 是Java1.2 引進的Map 介面的實作;
4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多個執行緒訪問Hashtable 時,不需要自己為它的方法實作同步,而HashMap 就必須為之提供外同步,Hashtable 和HashMap 采用的hash/rehash 演算法大致一樣,所以性能不會有很大的差異,
25、Arraylist 與Vector 區別?【基礎】
答:就ArrayList 與Vector 主要從二方面來說:
1)同步性:Vector 是執行緒安全的(同步),而ArrayList 是執行緒式不安全的;
2)資料增長:當需要增長時,Vector 默認增長一倍,而ArrayList 卻是一半,
26、List、Map、Set 三個介面,存取元素時,各有什么特點?【基礎】
答:List 以特定次序來持有元素,可有重復元素,Set 無法擁有重復元素,內部排序,Map 保存key-value 值,value 可多值,
27、sleep() 和wait() 有什么區別? 【基礎】
答:sleep 是執行緒類(Thread)的方法,導致此執行緒暫停執行指定時間,給執行機會給其他執行緒,但是監控狀態依然保持,到時后會自動恢復,呼叫sleep 不會釋放物件鎖,wait 是Object 類的方法,對此物件呼叫wait 方法導致本執行緒放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件發出notify 方法(或notifyAll)后本執行緒才進入物件鎖定池準備獲得物件鎖進入運行狀態,
28、當一個執行緒進入一個物件的一個synchronized 方法后,其它執行緒是否可進入此物件的其它方法? 【基礎】
答:其它執行緒只能訪問該物件的其它非同步方法,同步方法則不能進入,
29、多執行緒有幾種實作方法,都是什么?同步有幾種實作方法,都是什么? 【基礎】
答:多執行緒有兩種實作方法,分別是繼承Thread 類與實作Runnable 介面,同步的實作方面有兩種,分別是synchronized,wait 與notify,
30、當一個執行緒進入一個物件的 synchronized 方法 A 之后,其它執行緒是否可進入此物件的 synchronized 方法 B?【中等】
答:不能,其它執行緒只能訪問該物件的非同步方法,同步方法則不能進入,因為非靜態方法上的 synchronized 修飾符要求執行方法時要獲得物件的鎖,如果已經進入 A 方法說明物件鎖已經被取走,那么試圖進入 B 方法的執行緒就只能在等鎖池(注意不是等待池哦)中等待物件的鎖
31、簡述synchronized 和java.util.concurrent.locks.Lock 的異同?【中等】
答:主要相同點:Lock 能完成synchronized 所實作的所有功能;主要不同點:Lock 有比synchronized 更精確的執行緒語意和更好的性能,synchronized 會自動釋放鎖,而Lock 一定要求程式員手工釋放,并且必須在finally 從句中釋放,
32、撰寫多執行緒程式有幾種實作方式?【中等】
答:Java 5 以前實作多執行緒有兩種實作方法:一種是繼承 Thread 類;另一種是實作 Runnable 介面,兩種方式都要通過重寫 run()方法來定義執行緒的行為,推薦使用后者,因為 Java 中的繼承是單繼承,一個類有一個父類,如果繼承了 Thread 類就無法再繼承其他類了,顯然使用 Runnable 介面更為靈活,
補充:Java 5 以后創建執行緒還有第三種方式:實作 Callable 介面,該介面中的 call 方法可以在執行緒執行結束時產生一個回傳值,代碼如下所示:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyTask implements Callable<Integer> {
private int upperBounds;
public MyTask(int upperBounds) {
this.upperBounds = upperBounds;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i = 1; i <= upperBounds; i++) {
sum += i;
}
return sum;
}
}
class Test {
public static void main(String[] args) throws Exception {
List<Future<Integer>> list = new ArrayList<>();
ExecutorService service = Executors.newFixedThreadPool(10);
for(int i = 0; i < 10; i++) {
list.add(service.submit(new MyTask((int) (Math.random() * 100))));
}
int sum = 0;
for(Future<Integer> future : list) {
//while(!future.isDone()) ;
sum += future.get();
}
System.out.println(sum);
}
}
33、Java 中如何實作序列化,有什么意義?【中等】
答:序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化,可以對流化后的物件進行讀寫操作,也可將流化后的物件傳輸于網路之間,序列化是為了解決物件流讀寫操作時可能引發的問題(如果不進行序列化可能會存在資料亂序的問題),要實作序列化,需要讓一個類實作 Serializable 介面,該介面是一個標識性介面,標注該類物件是可被序列化的,然后使用一個輸出流來構造一個物件輸出流并通過 writeObject(Object)方法就可以將實作物件寫出(即保存其狀態);如果需要反序列化則可以用一個輸入流建立物件輸入流,然后通過 readObject 方法從流中讀取物件,
二、資料庫
34、闡述 JDBC 操作資料庫的步驟,【基礎】
答:下面的代碼以連接本機的 Oracle 資料庫為例,演示 JDBC 操作資料庫的步驟,
//加載驅動,
Class.forName("oracle.jdbc.driver.OracleDriver");
//創建連接,
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
//創建陳述句,
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?"); ps.setInt(1, 1000);
ps.setInt(2, 3000);
//執行陳述句,
ResultSet rs = ps.executeQuery();
//處理結果,
while(rs.next()) {
System.out.println(rs.getInt("empno") + " - " + rs.getString("ename"));
}
//關閉資源,
finally {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
提示:關閉外部資源的順序應該和打開的順序相反,也就是說先關閉 ResultSet、再關閉Statement、在關閉 Connection,上面的代碼只關閉了 Connection(連接),雖然通常情況下在關閉連接時,連接上創建的陳述句和打開的游標也會關閉,但不能保證總是如此,因此應該按照剛才說的順序分別關閉,此外,第一步加載驅動在 JDBC 4.0 中是可以省略的(自動從類路徑中加載驅動),但是我們建議保留,
35、使用 JDBC 操作資料庫時,如何提升讀取資料的性能?如何提升更新資料的性能?【中等】
答:要提升讀取資料的性能,可以指定通過結果集(ResultSet)物件的 setFetchSize()方法指定每次抓取的記錄數(典型的空間換時間策略);要提升更新資料的性能可以使用 PreparedStatement 陳述句構建批處理,將若干 SQL 陳述句置于一個批處理中執行,
36、在進行資料庫編程時,連接池有什么作用?【基礎】
答:由于創建連接和釋放連接都有很大的開銷(尤其是資料庫服務器不在本地時,每次建立連接都需要進行 TCP 的三次握手,釋放連接需要進行 TCP 四次握手,造成的開銷是不可忽視的),為了提升系統訪問資料庫的性能,可以事先創建若干連接置于連接池中,需要時直接從連接池獲取,使用結束時歸還連接池而不必關閉連接,從而避免頻繁創建和釋放連接所造成的開銷,這是典型的用空間換取時間的策略(浪費了空間存盤連接,但節省了創建和釋放連接的時間),池化技術在 Java 開發中是很常見的,在使用執行緒時創建執行緒池的道理與此相同,基于 Java 的開源資料庫連接池主要有:C3P0、Proxool、DBCP、BoneCP、Druid 等,
37、事務的ACID是指什么?【基礎】
答:
-
原子性(Atomic):事務中各項操作,要么全做要么全不做,任何一項操作的失敗都會導致整個事務的失敗;
-
一致性(Consistent):事務結束后系統狀態是一致的;
-
隔離性(Isolated):并發執行的事務彼此無法看到對方的中間狀態;
-
持久性(Durable):事務完成后所做的改動都會被持久化,即使發生災難性的失敗,通過日志和同步備份可以在故障發生后重建資料,
38、談談臟讀、幻讀和不可重復讀?【中等】
臟讀(Dirty Read):A 事務讀取 B 事務尚未提交的資料并在此基礎上操作,而 B 事務執行回滾,那么 A 讀取到的資料就是臟資料,
| 時間轉賬事務 A | 取款事務 B | ||
|---|---|---|---|
| T1 | 開始事務 | ||
| T2 | 開始事務 | ||
| T3 | 查詢賬戶余額為 1000 元 | ||
| T4 | 取出 500 元余額修改為 500 | 元 | |
| T5 | 查詢賬戶余額為 500 元(臟讀) | ||
| T6 | 撤銷事務余額恢復為 1000 元 | ||
| T7 | 匯入 100 元把余額修改為 600 元 | ||
| T8 | 提交事務 | ||
不可重復讀(Unrepeatable Read):事務 A 重新讀取前面讀取過的資料,發現該資料已經被另一個已提交的事務 B 修改過了,
| 時間轉賬事務 A | 取款事務 B | |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為 1000 元 | |
| T4 | 查詢賬戶余額為 1000 元 | |
| T5 | 取出 100 元修改余額為 900 元 | |
| T6 | 提交事務 | |
| T7 | 查詢賬戶余額為 900 元(不可重復讀) | |
幻讀(Phantom Read):事務 A 重新執行一個查詢,回傳一系列符合查詢條件的行,發現其中插入了被事務 B 提交的行,
| 時間統計金額事務 A | 轉賬事務 B | |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 統計總存款為 10000 元 | |
| T4 | 新增一個存款賬戶存入 100 元 | |
| T5 | 提交事務 | |
| T6 | 再次統計總存款為 10100 元(幻讀) | |
第 1 類丟失更新:事務 A 撤銷時,把已經提交的事務 B 的更新資料覆寫了,
時間取款事務 A 轉賬事務 B
| 時間取款事務 A | 轉賬事務 B | |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為 1000 元 | |
| T4 | 查詢賬戶余額為 1000 元 | |
| T5 | 匯入 100 元修改余額為 1100 元 | |
| T6 | 提交事務 | |
| T7 | 取出 100 元將余額修改為 900 元 | |
| T8 | 撤銷事務 | |
| T9 | 余額恢復為 1000 元(丟失更新) | |
| 第 2 類丟失更新:事務 A 覆寫事務 B 已經提交的資料,造成事務 B 所做的操作丟失, | ||
| 時間轉賬事務 A | 取款事務 B | |
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為 1000 元 | |
| T4 | 查詢賬戶余額為 1000 元 | |
| T5 | 取出 100 元將余額修改為 900 元 | |
| T6 | 提交事務 | |
| T7 | 匯入 100 元將余額修改為 1100 元 | |
| T8 | 提交事務 | |
| T9 | 查詢賬戶余額為 1100 元(丟失更新) | |
資料并發訪問所產生的問題,在有些場景下可能是允許的,但是有些場景下可能就是致命的,資料庫通常會通過鎖機制來解決資料并發訪問問題,按鎖定物件不同可以分為表級鎖和行級鎖;按并發事務鎖定關系可以分為共享鎖和獨占鎖,具體的內容大家可以自行查閱資料進行了解,直接使用鎖是非常麻煩的,為此資料庫為用戶提供了自動鎖機制,只要用戶指定會話的事務隔離級別,資料庫就會通過分析 SQL 陳述句然后為事務訪問的資源加上合適的鎖,此外,資料庫還會維護這些鎖通過各種手段提高系統的性能,這些對用戶來說都是透明的(就是說你不用理解,事實上我確實也不知道),
ANSI/ISO SQL 92 標準定義了4 個等級的事務隔離級別,如下表所示:
| 隔離級別 | 臟讀 | 不可重復讀幻讀 | 第一類丟失更新第二類丟失更新 | ||
|---|---|---|---|---|---|
| READ UNCOMMITED 允許 | 允許 | 允許 | 不允許 | 允許 | |
| READ COMMITTED 不允許 | 允許 | 允許 | 不允許 | 允許 | |
| REPEATABLE READ 不允許 | 不允許 | 允許 | 不允許 | 不允許 | |
| SERIALIZABLE | 不允許 | 不允許 | 不允許 | 不允許 | 不允許 |
需要說明的是,事務隔離級別和資料訪問的并發性是對立的,事務隔離級別越高并發性就越差,所以要根據具體的應用來確定合適的事務隔離級別,這個世界沒有萬能的原則,
39、JDBC中如何進行事務處理?【中等】
答:Connection 提供了事務處理的方法,通過呼叫setAutoCommit(false)可以設定手動提交事務;當事務完成后用 commit()顯式提交事務;如果在事務處理程序中發生例外則通過 rollback()進行事務回滾,除此之外,從 JDBC 3.0 中還引入了 Savepoint(保存點)的概念,允許通過代碼設定保存點并讓事務回滾到指定的保存點,
40、獲得一個類的類物件有哪些方式?【基礎】
答:
-
方法 1:型別.class,例如:String.class
-
方法 2:物件.getClass(),例如:"hello".getClass()
-
方法 3:Class.forName(),例如:Class.forName("java.lang.String")
41、JSP 有哪些內置物件?作用分別是什么?【基礎】
答:JSP 有 9 個內置物件:
-
request:封裝客戶端的請求,其中包含來自 GET 或 POST 請求的引數;
-
response:封裝服務器對客戶端的回應;
-
pageContext:通過該物件可以獲取其他物件;
-
session:封裝用戶會話的物件;
-
application:封裝服務器運行環境的物件;
-
out:輸出服務器回應的輸出流物件;
-
config:Web 應用的配置物件;
-
page:JSP 頁面本身(相當于 Java 程式中的 this);
-
exception:封裝頁面拋出例外的物件,
42、get 和 post 請求的區別?【基礎】
答:①get 請求用來從服務器上獲得資源,而 post 是用來向服務器提交資料;
②get 將表單中資料按照 name=value 的形式,添加到 action 所指向的 URL 后面,并且兩者使用"?"連接,而各個變數之間使用"&"連接;post 是將表單中的資料放在 HTTP 協議的請求頭或訊息體中,傳遞到 action 所指向 URL;
③get 傳輸的資料要受到 URL 長度限制(1024 位元組);而 post 可以傳輸大量的資料,上傳檔案通常要使用 post 方式;
④使用 get 時引數會顯示在地址欄上,如果這些資料不是敏感資料,那么可以使用 get;對于敏感資料還是應用使用 post;
⑤get 使用 MIME 型別 application/x-www-form-urlencoded 的 URL 編碼(也叫百分號編碼)
文本的格式傳遞引數,保證被傳送的引數由遵循規范的文本組成,例如一個空格的編碼是"%20",
43、講解 JSP 中的四種作用域,【基礎】
答:JSP 中的四種作用域包括 page、request、session 和 application,具體來說:
-
page 代表與一個頁面相關的物件和屬性,
-
request 代表與 Web 客戶機發出的一個請求相關的物件和屬性,一個請求可能跨越多個頁面,涉及多個 Web 組件;需要在頁面顯示的臨時資料可以置于此作用域,
-
session 代表與某個用戶與服務器建立的一次會話相關的物件和屬性,跟某個用戶相關的資料應該放在用戶自己的 session 中,
-
application 代表與整個 Web 應用程式相關的物件和屬性,它實質上是跨越整個 Web 應用程式,包括多個頁面、請求和會話的一個全域作用域,
三、SSM框架
44、MyBatis 中使用#和$書寫占位符有什么區別?【中等】
答:#將傳入的資料都當成一個字串,會對傳入的資料自動加上引號;$將傳入的資料直接顯示生成在 SQL 中,注意:使用$占位符可能會導致 SQL 注射攻擊,能用#的地方就不要使用$,寫 order by 子句的時候應該用$而不是#,
45、解釋一下 MyBatis 中命名空間(namespace)的作用,【中等】
答:在大型專案中,可能存在大量的 SQL 陳述句,這時候為每個 SQL 陳述句起一個唯一的標識(ID)就變得并不容易了,為了解決這個問題,在 MyBatis 中,可以為每個映射檔案起一個唯一的命名空間,這樣定義在這個映射檔案中的每個 SQL 陳述句就成了定義在這個命名空間中的一個 ID,只要我們能夠保證每個命名空間中這個 ID 是唯一的,即使在不同映射檔案中的陳述句 ID 相同,也不會再產生沖突了,
46、什么是 IoC 和 DI?DI 是如何實作的?【中等】
答:IoC 叫控制反轉,是 Inversion of Control 的縮寫,DI(Dependency Injection)叫依賴注入,是對 IoC 更簡單的詮釋,控制反轉是把傳統上由程式代碼直接操控的物件的呼叫權交給容器,通過容器來實作物件組件的裝配和管理,所謂的"控制反轉"就是對組件物件控制權的轉移,從程式代碼本身轉移到了外部容器,由容器來創建物件并管理物件之間的依賴關系,IoC 體現了好萊塢原則 - "Don’t call me, we will call you",依賴注入的基本原則是應用組件不應該負責查找資源或者其他依賴的協作物件,配置物件的作業應該由容器負責,查找資源的邏輯應該從應用組件的代碼中抽取出來,交給容器來完成,DI 是對 IoC 更準確的描述,即組件之間的依賴關系由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關系注入到組件之中,
47、解釋一下什么叫 AOP(面向切面編程)?【基礎】
答:AOP(Aspect-Oriented Programming)指一種程式設計范型,該范型以一種稱為切面(aspect)的語言構造為基礎,切面是一種新的模塊化機制,用來描述分散在物件、類或方法中的橫切關注點(crosscutting concern),
48、你是如何理解"橫切關注"這個概念的?【中等】
答:"橫切關注"是會影響到整個應用程式的關注功能,它跟正常的業務邏輯是正交的,沒有必然的聯系,但是幾乎所有的業務邏輯都會涉及到這些關注功能,通常,事務、日志、安全性等關注就是應用中的橫切關注功能,
49、你如何理解 AOP 中的連接點(Joinpoint)、切點(Pointcut)、增強(Advice)、引介(Introduction)、織入(Weaving)、切面(Aspect)這些概念?【基礎】
答:a. 連接點(Joinpoint):程式執行的某個特定位置(如:某個方法呼叫前、呼叫后,方法拋出例外后),一個類或一段程式代碼擁有一些具有邊界性質的特定點,這些代碼中的特定點就是連接點,Spring 僅支持方法的連接點,
b. 切點(Pointcut):如果連接點相當于資料中的記錄,那么切點相當于查詢條件,一個切點可以匹配多個連接點,Spring AOP 的規則決議引擎負責決議切點所設定的查詢條件,找到對應的連接點,
c. 增強(Advice):增強是織入到目標類連接點上的一段程式代碼,Spring 提供的增強介面都是帶方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等,很多資料上將增強譯為“通知”,這明顯是個詞不達意的翻譯,讓很多程式員困惑了許久,
說明: Advice 在國內的很多書面資料中都被翻譯成"通知",但是很顯然這個翻譯無法表達其本質,有少量的讀物上將這個詞翻譯為"增強",這個翻譯是對 Advice 較為準確的詮釋,我們通過 AOP 將橫切關注功能加到原有的業務邏輯上,這就是對原有業務邏輯的一種增強,這種增強可以是前置增強、后置增強、回傳后增強、拋例外時增強和包圍型增強,
d. 引介(Introduction):引介是一種特殊的增強,它為類添加一些屬性和方法,這樣,即使一個業務類原本沒有實作某個介面,通過引介功能,可以動態的未該業務類添加介面的實作邏輯,讓業務類成為這個介面的實作類,
e. 織入(Weaving):織入是將增強添加到目標類具體連接點上的程序,AOP 有三種織入方式:①編譯期織入:需要特殊的 Java 編譯期(例如 AspectJ 的 ajc);②裝載期織入:要求使用特殊的類加載器,在裝載類的時候對類進行增強;③運行時織入:在運行時為目標類生成代理實作增強,Spring 采用了動態代理的方式實作了運行時織入,而 AspectJ 采用了編譯期織入和裝載期織入的方式,
f. 切面(Aspect):切面是由切點和增強(引介)組成的,它包括了對橫切關注功能的定義,也包括了對連接點的定義,
50、Spring 支持的事務管理型別有哪些?你在專案中使用哪種方式?【中等】
答:Spring 支持編程式事務管理和宣告式事務管理,許多 Spring 框架的用戶選擇宣告式事務管理,因為這種方式和應用程式的關聯較少,因此更加符合輕量級容器的概念,宣告式事務管理要優于編程式事務管理,盡管在靈活性方面它弱于編程式事務管理,因為編程式事務允許你通過代碼控制業務,
51、Spring MVC的作業原理是怎樣的?【基礎】
答:SpringMVC作業原理圖如下:
① 客戶端的所有請求都交給前端控制器 DispatcherServlet 來處理,它會負責呼叫系統的其他模塊來真正處理用戶的請求,
② DispatcherServlet 收到請求后,將根據請求的資訊(包括 URL、HTTP 協議方法、請求頭、請求引數、Cookie 等)以及 HandlerMapping 的配置找到處理該請求的 Handler(任何一個物件都可以作為請求的 Handler),
③在這個地方 Spring 會通過 HandlerAdapter 對該處理器進行封裝,
④ HandlerAdapter 是一個配接器,它用統一的介面對各種 Handler 中的方法進行呼叫,
⑤ Handler 完成對用戶請求的處理后,會回傳一個 ModelAndView 物件給 DispatcherServlet, ModelAndView 顧名思義,包含了資料模型以及相應的視圖的資訊,
⑥ ModelAndView 的視圖是邏輯視圖,DispatcherServlet 還要借助 ViewResolver 完成從邏輯視圖到真實視圖物件的決議作業,
⑦ 當得到真正的視圖物件后,DispatcherServlet 會利用視圖物件對模型資料進行渲染,
⑧ 客戶端得到回應,可能是一個普通的 HTML 頁面,也可以是 XML 或 JSON 字串,還可以是一張圖片或者一個 PDF 檔案,
52、什么是 XSS 攻擊?【困難】
答: XSS(Cross Site Script,跨站腳本攻擊)是向網頁中注入惡意腳本在用戶瀏覽網頁時在用戶瀏覽器中執行惡意腳本的攻擊方式,跨站腳本攻擊分有兩種形式:反射型攻擊(誘使用戶點擊一個嵌入惡意腳本的鏈接以達到攻擊的目標,目前有很多攻擊者利用論壇、微博發布含有惡意腳本的 URL 就屬于這種方式)和持久型攻擊(將惡意腳本提交到被攻擊網站的資料庫中,用戶瀏覽網頁時,惡意腳本從資料庫中被加載到頁面執行,QQ 郵箱的早期版本就曾經被利用作為持久型跨站腳本攻擊的平臺),XSS 雖然不是什么新鮮玩意,但是攻擊的手法卻不斷翻新,防范 XSS 主要有兩方面:消毒(對危險字符進行轉義)和 HttpOnly (防范 XSS 攻擊者竊取 Cookie 資料),
53、SQL 注入攻擊?【困難】
答: SQL 注入攻擊是注入攻擊最常見的形式(此外還有 OS 注入攻擊(Struts 2 的高危漏洞就是通過 OGNL 實施 OS 注入攻擊導致的)),當服務器使用請求引數構造 SQL 陳述句時,惡意的 SQL 被嵌入到 SQL 中交給資料庫執行,SQL 注入攻擊需要攻擊者對資料庫結構有所了解才能進行,攻擊者想要獲得表結構有多種方式:(1)如果使用開源系統搭建網站,資料庫結構也是公開的(目前有很多現成的系統可以直接搭建論壇,電商網站,雖然方便快 捷但是風險是必須要認真評估的);(2)錯誤回顯(如果將服務器的錯誤資訊直接顯示在頁面上,攻擊者可以通過非法引數引發頁面錯誤從而通過錯誤資訊了解資料庫結構,Web應用應當設定友好的錯誤頁,一方面符合最小驚訝原則,一方面屏蔽掉可能給系統帶來危險的錯誤回顯資訊);(3)盲注,防范 SQL 注入攻擊也可以采用消毒的方式,通過正則運算式對請求引數進行驗證,此外,引數系結也是很好的手段,這樣惡意的 SQL 會被當做 SQL 的引數而不是命令被執行,JDBC 中的 PreparedStatement 就是支持引數系結的陳述句物件,從性能和安全性上都明顯優于 Statement,
54、什么是CSRF攻擊?【困難】
答: CSRF 攻擊(Cross Site Request Forgery,跨站請求偽造)是攻擊者通過跨站請求,以合法的用戶身份進行非法操作(如轉賬或發帖等),CSRF 的原理是利用瀏覽器的 Cookie 或服務器的 Session,盜取用戶身份,其原理如下圖所示,防范 CSRF 的主要手段是識別請求者的身份,主要有以下幾種方式:
(1)在表單中添加令牌(token);
(2)驗證碼;
(3)檢查請求頭中的 Referer,
令牌和驗證都具有一次消費性的特征,因此在原理上一致的,但是驗證碼是一種糟糕的用戶體驗,不是必要的情況下不要輕易使用驗證碼,目前很多網站的做法是如果在短時間內多次提交一個表單未獲得成功后才要求提供驗證碼,這樣會獲得較好的用戶體驗,
四、redis
55、使用redis有哪些好處?【基礎】
答:
-
速度快,因為資料存在記憶體中,類似于HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1)
-
支持豐富資料型別,支持string,list,set,sorted set,hash
-
支持事務,操作都是原子性,所謂的原子性就是對資料的更改要么全部執行,要么全部不執行
-
豐富的特性:可用于快取,訊息,按key設定過期時間,過期后將會自動洗掉
56、Redis有哪些資料結構?【基礎】
答:字串String、字典Hash、串列List、集合Set、有序集合SortedSet,
57、如果有大量的key需要設定同一時間過期,一般需要注意什么?【中等】
答:如果大量的key過期時間設定的過于集中,到過期的那個時間點,redis可能會出現短暫的卡頓現象,一般需要在時間上加一個隨機值,使得過期時間分散一些,
58、為什么Redis需要把所有資料放到記憶體中?【中等】
答:Redis為了達到最快的讀寫速度將資料都讀到記憶體中,并通過異步的方式將資料寫入磁盤,所以redis具有快速和資料持久化的特征,如果不將資料放在記憶體中,磁盤I/O速度為嚴重影響redis的性能,在記憶體越來越便宜的今天,redis將會越來越受歡迎, 如果設定了最大使用的記憶體,則資料已有記錄數達到記憶體限值后不能繼續插入新值,
59、Redis提供了哪幾種持久化方式?【中等】
答:
- RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照存盤,
- AOF持久化方式記錄每次對服務器寫的操作,當服務器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加保存每次寫的操作到檔案末尾,Redis還能對AOF檔案進行后臺重寫,使得AOF檔案的體積不至于過大,
- 如果你只希望你的資料在服務器運行的時候存在,你也可以不使用任何持久化方式,
- 你也可以同時開啟兩種持久化方式, 在這種情況下, 當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案保存的資料集要比RDB檔案保存的資料集要完整,
- 最重要的事情是了解RDB和AOF持久化方式的不同,讓我們以RDB持久化方式開始,
60、如何選擇合適的持久化方式?【中等】
答:一般來說, 如果想達到足以媲美PostgreSQL的資料安全性, 你應該同時使用兩種持久化功能,如果你非常關心你的資料, 但仍然可以承受數分鐘以內的資料丟失,那么你可以只使用RDB持久化,
有很多用戶都只使用AOF持久化,但并不推薦這種方式:因為定時生成RDB快照(snapshot)非常便于進行資料庫備份, 并且 RDB 恢復資料集的速度也要比AOF恢復的速度要快,除此之外, 使用RDB還可以避免之前提到的AOF程式的bug,
61、redis支持的java客戶端你用過哪個?【基礎】
答: Jedis,Jedis是Redis的Java實作的客戶端,其API提供了比較全面的Redis命令的支持,
62、Redis集群的主從復制模型是怎樣的?【困難】
答:為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用,所以集群使用了主從復制模型,每個節點都會有N-1個復制品,
63、Redis集群之間是如何復制的?【中等】
答:異步復制,
64、怎么測驗Redis的連通性?【基礎】
ping,
五、訊息佇列
65、為什么要用訊息佇列?【中等】
解耦、異步、削峰
- A系統呼叫B系統、C系統,傳統的呼叫是直接呼叫,但是當B系統說我不需要你提供資料了,這時候A需要改代碼,C系統說我不需要某個欄位了,這時候A也要改代碼,如果又多了一個D系統,A又要寫代碼,為了實作解耦,引入訊息佇列,A將產生的資料丟到訊息佇列中,哪個系統需要 哪個系統就去取;
- A系統呼叫B系統,B系統由于某個需要呼叫第三方介面超時,導致A系統回應速度慢,而B系統的好壞又不會影響業務邏輯,所以可以改為A異步呼叫B,A將訊息丟到訊息佇列中,B系統訂閱訊息,實作A的快速回應;
- 當大量流量請求到系統A時,由于資料庫的處理能力有限,造成資料庫連接例外,使用訊息佇列,大量請求先丟到訊息佇列中,系統A使用按批拉資料的方式,批量處理資料,生產中,高峰期短暫的訊息積壓是允許的,
66、使用訊息佇列有什么缺點【中等】
- 系統復雜性增加:加了訊息佇列,需要保證訊息不會重復消費,需要保證訊息的可靠性,需要保證訊息佇列的高可用
- 系統的可用性降低:如果訊息佇列掛了,那么系統也會受到影響
67、為什么選用RocketMQ;RocketMQ和ActiveMQ的區別【困難】
RocketMQ模型簡單、介面易用,在阿里大規模使用,社區活躍,單機吞吐量10萬級,可用性非常高,訊息理論上不會丟失;
- ActiveMQ嚴格遵循JMS規范,可持久化到記憶體、檔案、資料庫,可用性高主要是主從,多語言支持,消失丟失率低;
- RocketMQ持久化到磁盤檔案,可用性非常高,支持分布式,只支持Java,訊息理論上不會丟失;
68、RocketMQ是怎么保證系統高可用的?【困難】
- 多Master部署,防止單點故障;
- 主從結構,訊息冗余,防止訊息丟失;
69、訊息中間件集群崩潰,如何保證百萬生產資料不丟失?【中等】
答: 把訊息持久化寫入到磁盤上去 ,
六、spring boot
70、Spring Boot 的核心組態檔有哪幾個?它們的區別是什么?【中等】
Spring Boot 的核心組態檔是 application 和 bootstrap 組態檔,
application 組態檔這個容易理解,主要用于 Spring Boot 專案的自動化配置,
bootstrap 組態檔有以下幾個應用場景:
-
使用 Spring Cloud Config 配置中心時,這時需要在 bootstrap 組態檔中添加連接到配置中心的配置屬性來加載外部配置中心的配置資訊;
-
一些固定的不能被覆寫的屬性;
-
一些加密/解密的場景;
71、Spring Boot 的組態檔有哪幾種格式?它們有什么區別?【中等】
.properties 和 .yml,它們的區別主要是書寫格式不同,
1).properties
app.user.name = javastack
2).yml
app:
user:
name: javastack
另外,.yml 格式不支持 @PropertySource 注解匯入配置,
72、Spring Boot 的核心注解是哪個?它主要由哪幾個注解組成的?【基礎】
啟動類上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要組合包含了以下 3 個注解:
-
@SpringBootConfiguration:組合了 @Configuration 注解,實作組態檔的功能,
-
@EnableAutoConfiguration:打開自動配置的功能,也可以關閉某個自動配置的選項,如關閉資料源自動配置功能:@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }),
-
@ComponentScan:Spring組件掃描,
73、開啟 Spring Boot 特性有哪幾種方式?【基礎】
1)繼承spring-boot-starter-parent專案
2)匯入spring-boot-dependencies專案依賴
74、Spring Boot 需要獨立的容器運行嗎?【基礎】
可以不需要,內置了 Tomcat/ Jetty 等容器,
75、如何在 Spring Boot 啟動的時候運行一些特定的代碼?【中等】
Spring Boot Runner啟動器,可以實作介面 ApplicationRunner 或者 CommandLineRunner,這兩個介面實作方式一樣,它們都只提供了一個 run 方法,
76、Spring Boot 有哪幾種讀取配置的方式?【中等】
Spring Boot 可以通過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來系結變數,
實體:
單個注入:@Value("${book.author}"),
映射一個類:@ConfigurationProperties(prefix="author",locations={"classpath:author.properties"})通過prefix指定前綴,通過locations指定位置
77、Spring Boot 如何定義多套不同環境配置?【中等】
提供多套組態檔,按照application-xxx.properties格式建立檔案,并在application.properties中指定,如:
application.properties
application-dev.properties
application-test.properties
application-prod.properties
78、SpringBoot中的定時任務如何實作?【中等】
通過配置注解@EnableScheduline來開啟對計劃任務的支持,然后再要執行的任務上加注解@Scheduled,
79、我們如何連接一個像 MYSQL 或者 orcale 一樣的外部資料庫?【中等】
讓我們以 MySQL 為例來思考這個問題:
第一步 - 把 mysql 連接器的依賴項添加至 pom.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
第二步 - 配置你的 MySQL 資料庫連接
配置 application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/todo_example
spring.datasource.username=todouser
spring.datasource.password=YOUR_PASSWORD
第三步 - 重新啟動,你就準備好了!
七、spring cloud
80、什么是微服務【中等】
-
以前的模式是 所有的代碼在同一個工程中 部署在同一個服務器中 同一個專案的不同模塊不同功能互相搶占資源
-
微服務 將工程根據不同的業務規則拆分成微服務 微服務部署在不同的機器上 服務之間進行相互呼叫
-
Java微服務的框架有 dubbo(只能用來做微服務),spring cloud(提供了服務的發現,斷路器等)
**81、微服務之間是如何獨立通訊的spring Cloud和 Dubbo有哪些區別?【困難】 **
答:
-
springcloud服務注冊中心是Spring Cloud Netflix Eureka
dubbo的注冊中心一般是zookeeper
-
dubbo只是類似Netflix的一個子集只有注冊中心,其他springcloud組件沒有
-
springcloud的呼叫方式是REST API
dubbo的呼叫方式是RPC
RPC服務提供方與呼叫方介面依賴方式太強
我們為每個微服務定義了各自的service抽象介面
并通過持續集成發布到私有倉庫中
呼叫方應用對微服務提供的抽象介面存在強依賴關系
REST方式的服務依賴要比RPC方式的依賴更為靈活
-
Dubbo的檔案可以說在國內開源框架中算是一流的,非常全,并且講解的也非常深入,國內開發者來說,閱讀起來更加容易上手
82、springcloud如何實作服務的注冊和發現【中等】
-
服務在發布時 指定對應的服務名(服務名包括了IP地址和埠) 將服務注冊到注冊中心(eureka或者zookeeper)
-
這一程序是springcloud自動實作 只需要在main方法添加@EnableDisscoveryClient 同一個服務修改埠就可以啟動多個實體
-
呼叫方法:傳遞服務名稱通過注冊中心獲取所有的可用實體 通過負載均衡策略呼叫(ribbon和feign)對應的服務
83、Ribbon和Feign的區別【中等】
Ribbon和Feign都是用于呼叫其他服務的,不過方式不同,
1.啟動類使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients,
2.服務的指定位置不同,Ribbon是在@RibbonClient注解上宣告,Feign則是在定義抽象方法的介面中使用@FeignClient宣告,
3.呼叫方式不同,Ribbon需要自己構建http請求,模擬http請求然后使用RestTemplate發送給其他服務,步驟相當繁瑣,
Feign則是在Ribbon的基礎上進行了一次改進,采用介面的方式,將需要呼叫的其他服務的方法定義成抽象方法即可,不需要自己構建http請求,不過要注意的是抽象方法的注解、方法簽名要和提供服務的方法完全一致,
84、springcloud斷路器的作用【中等】
當一個服務呼叫另一個服務由于網路原因或者自身原因出現問題時 呼叫者就會等待被呼叫者的回應 當更多的服務請求到這些資源時,導致更多的請求等待 這樣就會發生連鎖效應(雪崩效應) 斷路器就是解決這一問題
85、springcloud如何實作服務的注冊和發現【中等】
答:服務在發布時 指定對應的服務名,服務名包括了IP地址和埠,將服務注冊到注冊中心eureka或者zookeeper,這一程序是springcloud自動實作,只需要在main方法添加 @ EnableDisscoveryClient,同一個服務修改埠就可以啟動多個實體,
86、springcloud中的組件有那些?【中等】
答:獨挑大梁,獨自啟動不需要依賴其它組件
1)Eureka,服務注冊中心,特性有失效剔除、服務保護
2)Dashboard,Hystrix儀表盤,監控集群模式和單點模式,其中集群模式需要收集器Turbine配合
3)Zuul,API服務網關,功能有路由分發和過濾
4)Config,分布式配置中心,支持本地倉庫、SVN、Git、Jar包內配置等模式
潤物無聲,融合在每個微服務中、依賴其它組件并為其提供服務
1)Ribbon,客戶端負載均衡,特性有區域親和,重試機制
2)Hystrix,客戶端容錯保護,特性有服務降級、服務熔斷、請求快取、請求合并、依賴隔離
3)Feign,宣告式服務呼叫本質上就是Ribbon+Hystrix
4)Stream,訊息驅動,有Sink、Source、Processor三種通道,特性有訂閱發布、消費組、訊息磁區
5)Bus,訊息總線,配合Config倉庫修改的一種Stream實作,
6)Sleuth,分布式服務追蹤,需要搞清楚TraceID和SpanID以及抽樣,如何與ELK整合
八、其他
87、cookie和session的區別【基礎】
1、Cookies是一種能夠讓網站服務器把少量資料儲存到客戶端的硬碟或記憶體,或是從客戶端的硬碟讀取資料的一種技術,Cookies是當你瀏覽某網站時,由Web服務器置于你硬碟上的一個非常小的文本檔案,它可以記錄你的用戶ID、密碼、瀏覽過的網頁、停留的時間等資訊,session: 當用戶請求來自應用程式的 Web 頁時,如果該用戶還沒有會話,則 Web 服務器將自動創建一個 Session 物件,當會話過期或被放棄后,服務器將終止該會話,cookie機制:采用的是在客戶端保持狀態的方案,而session機制采用的是在服務端保持狀態的方案,同時我們看到由于服務器端保持狀態的方案在客戶端也需要保存一個標識,所以session機制可能需要借助cookie機制來達到保存標識的目的,
2、Session是服務器用來跟蹤用戶的一種手段,每個Session都有一個唯一標識:session ID,當服務器創建了Session時,給客戶端發送的回應報文包含了Set-cookie欄位,其中有一個名為sid的鍵值對,這個鍵值Session ID,客戶端收到后就把Cookie保存瀏覽器,并且之后發送的請求報表都包含SessionID,HTTP就是通過Session和Cookie這兩個發送一起合作來實作跟蹤用戶狀態,Session用于服務端,Cookie用于客戶端
88、一次完整的http請求程序【中等】
域名決議 --> 發起TCP的3次握手 --> 建立TCP連接后發起http請求 --> 服務器回應http請求,瀏覽器得到html代碼 --> 瀏覽器決議html代碼,并請求html代碼中的資源(如js、css、圖片等) --> 瀏覽器對頁面進行渲染呈現給用戶,
89、講一下長連接【困難】
一、基于http協議的長連接
在HTTP1.0和HTTP1.1協議中都有對長連接的支持,其中HTTP1.0需要在request中增加”Connection: keep-alive“ header才能夠支持,而HTTP1.1默認支持.
http1.0請求與服務端的互動程序:
-
客戶端發出帶有包含一個header:”Connection: keep-alive“的請求
-
服務端接收到這個請求后,根據http1.0和”Connection: keep-alive“判斷出這是一個長連接,就會在response的header中也增加”Connection: keep-alive“,同是不會關閉已建立的tcp連接.
-
客戶端收到服務端的response后,發現其中包含”Connection: keep-alive“,就認為是一個長連接,不關閉這個連接,并用該連接再發送request.轉到a),
二、發心跳包,每隔幾秒就發一個資料包過去
90、TCP如何保證可靠傳輸?【困難】
-
三次握手,
-
將資料截斷為合理的長度,應用資料被分割成 TCP 認為最適合發送的資料塊(按位元組編號,合理分片)
-
超時重發,當 TCP 發出一個段后,它啟動一個定時器,如果不能及時收到一個確認就重發
-
對于收到的請求,給出確認回應
-
校驗出包有錯,丟棄報文段,不給出回應
-
對失序資料進行重新排序,然后才交給應用層
-
對于重復資料 , 能夠丟棄重復資料
-
流量控制,TCP 連接的每一方都有固定大小的緩沖空間,TCP 的接收端只允許另一端發送接收端緩沖區所能接納的資料,這將防止較快主機致使較慢主機的緩沖區溢位,
-
擁塞控制,當網路擁塞時,減少資料的發送,
91、URI和URL的區別【中等】
URI,是uniform resource identifier,統一資源識別符號,用來唯一的標識一個資源,Web上可用的每種資源如HTML檔案、影像、視頻片段、程式等都是一個來URI來定位的
URI一般由三部組成:
-
訪問資源的命名機制
-
存放資源的主機名
-
資源自身的名稱,由路徑表示,著重強調于資源,
URL是uniform resource locator,統一資源定位器,它是一種具體的URI,即URL可以用來標識一個資源,而且還指明了如何locate這個資源,URL是Internet上用來描述資訊資源的字串,主要用在各種WWW客戶程式和服務器程式上,特別是著名的Mosaic,采用URL可以用一種統一的格式來描述各種資訊資源,包括檔案、服務器的地址和目錄等,
URL一般由三部組成:
-
協議(或稱為服務方式)
-
存有該資源的主機IP地址(有時也包括埠號)
-
主機資源的具體地址,如目錄和檔案名等
92、http和https的區別?【中等】
-
https協議需要到CA申請證書,一般免費證書很少,需要交費,
-
http是超文本傳輸協議,資訊是明文傳輸;https 則是具有安全性的ssl加密傳輸協 議,
-
http和https使用的是完全不同的連接方式,用的埠也不一樣,前者是80,后者是443,
-
http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,比http協議安全,
-
http默認使用80埠,https默認使用443埠
93、docker常用命令【中等】
1.docker images // 查看鏡像
2.docker run 鏡像名稱 // 生成一個正在運行的容器實體
3.docker stop 容器名稱 // 停止容器
4.docker rm 容器名稱 // 洗掉容器
5.docker start 容器名稱 // 啟動容器
6.docker restart 容器名稱 //重啟容器
7.docker rmi 鏡像名稱 // 洗掉鏡像
8.docker exec -it 容器名稱 /bin/bash // 進入容器
9.docker ps // 顯示正在運行的所有容器
10.docker ps -a // 顯示所有容器(包括已經停止的)
11.docker pull 鏡像名稱:版本號 // 拉取鏡像
94、什么是Docker鏡像?【中等】
Docker鏡像是Docker容器的源代碼,換句話說,Docker鏡像用于創建容器,使用build命令創建映像,并且在使用run啟動時它們將生成容器,鏡像存盤在Docker注冊表http://registry.hub.docker.com中,因為它們可能變得非常大,鏡像被設計為由其他鏡像層組成,允許在通過網路傳輸鏡像時發送最少量的資料,
95、什么是Docker容器?【中等】
Docker容器包括應用程式及其所有依賴項,但與其他容器共享內核,作為主機作業系統上用戶空間中的獨立行程運行,Docker容器不依賴于任何特定的基礎架構:它們可以在任何計算機,任何基礎架構和任何云中運行,
96、什么是Docker Hub?【中等】
Docker hub是一個基于云的注冊表服務,允許您鏈接到代碼存盤庫,構建鏡像并測驗它們,存盤手動推送的鏡像以及指向Docker云的鏈接,以便您可以將鏡像部署到主機,它為整個開發流程中的容器鏡像發現,分發和變更管理,用戶和團隊協作以及作業流自動化提供了集中資源,
97、什么是 Git 復刻(fork)?復刻(fork)、分支(branch)和克隆(clone)之間有什么區別?【中等】
- 復刻(fork)
是對存儲倉庫(repository)進行的遠程的、服務器端的拷貝,從源頭上就有所區別,復刻實際上不是 Git 的范疇,它更像是個政治/社會概念,
- 克隆(clone)
不是復刻,克隆是個對某個遠程倉庫的本地拷貝,克隆時,實際上是拷貝整個源存盤倉庫,包括所有歷史記錄和分支,
- 分支(branch)
是一種機制,用于處理單一存盤倉庫中的變更,并最終目的是用于與其他部分代碼合并,
98、“git pull”和“git fetch”之間有什么區別?【中等】
簡單來說,git pull 是 git fetch + git merge, 當你使用 pull,Git 會試著自動為你完成作業,它是背景關系(作業環境)敏感的,所以 Git 會把所有拉取的提交合并到你當前處理的分支中,
pull 則是 自動合并提交而沒有讓你復查的程序,如果你沒有細心管理你的分支,你可能會頻繁遇到沖突,
當你 fetch,Git 會收集目標分支中的所有不存在的提交,并將這些提交存盤到本地倉庫中,但Git 不會把這些提交合并到當前分支中,這種處理邏輯在當你需要保持倉庫更新,在更新檔案時又希望處理可能中斷的事情時,這將非常實用,而將提交合并到主分支中,則該使用 merge,
99、使用Ajax的優缺點分別是什么?【中等】
優點
- 互動性更好,來自服務器的新內容可以動態更改,無需重新加載整個頁面,
- 減少與服務器的連接,因為腳本和樣式只需要被請求一次,
- 狀態可以維護在一個頁面上,JavaScript 變數和 DOM 狀態將得到保持,因為主容器頁面未被重新加載,
- 基本上包括大部分 SPA 的優點,
缺點
- 動態網頁很難收藏,
- 如果 JavaScript 已在瀏覽器中被禁用,則不起作用,
- 有些網路爬蟲不執行 JavaScript,也不會看到 JavaScript 加載的內容,
- 基本上包括大部分 SPA 的缺點,
100、跨域問題,誰限制的跨域,怎么解決【困難】
- 瀏覽器的同源策略導致了跨域
- 用于隔離潛在惡意檔案的重要安全機制
- jsonp ,允許 script 加載第三方資源
- nginx 反向代理(nginx 服務內部配置 Access-Control-Allow-Origin *)
- cors 前后端協作設定請求頭部,Access-Control-Allow-Origin 等頭部資訊
- iframe 嵌套通訊,postmessage
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/3837.html
標籤:其他
上一篇:滑動視窗的最大值
下一篇:二叉搜索樹的第K個結點
