[转载] 2020最新Java面试题,常见面试题及答案汇总
參考鏈接: Java程序的輸出| 18(重寫Override)
發(fā)現(xiàn)網(wǎng)上很多Java面試題都沒有答案,所以花了很長(zhǎng)時(shí)間搜集整理出來了這套Java面試題大全,希望對(duì)大家有幫助哈~?
博主已將以下這些面試題整理成了一個(gè)Java面試手冊(cè),是PDF版的。?
關(guān)注博主的微信公眾號(hào):Java團(tuán)長(zhǎng),然后回復(fù)“面試手冊(cè)”即可獲取~?
一、Java 基礎(chǔ)?
1. JDK 和 JRE 有什么區(qū)別??
JDK:Java Development Kit 的簡(jiǎn)稱,java 開發(fā)工具包,提供了 java 的開發(fā)環(huán)境和運(yùn)行環(huán)境。JRE:Java Runtime Environment 的簡(jiǎn)稱,java 運(yùn)行環(huán)境,為 java 的運(yùn)行提供了所需環(huán)境。
具體來說 JDK 其實(shí)包含了 JRE,同時(shí)還包含了編譯 java 源碼的編譯器 javac,還包含了很多 java 程序調(diào)試和分析的工具。簡(jiǎn)單來說:如果你需要運(yùn)行 java 程序,只需安裝 JRE 就可以了,如果你需要編寫 java 程序,需要安裝 JDK。?
2. == 和 equals 的區(qū)別是什么??
== 解讀?
對(duì)于基本類型和引用類型 == 的作用效果是不同的,如下所示:?
基本類型:比較的是值是否相同;引用類型:比較的是引用是否相同;
代碼示例:?
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true?
代碼解讀:因?yàn)?x 和 y 指向的是同一個(gè)引用,所以 == 也是 true,而 new String()方法則重寫開辟了內(nèi)存空間,所以 == 結(jié)果為 false,而 equals 比較的一直是值,所以結(jié)果都為 true。?
equals 解讀?
equals 本質(zhì)上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法,把它變成了值比較。看下面的代碼就明白了。?
首先來看默認(rèn)情況下 equals 比較一個(gè)有相同值的對(duì)象,代碼如下:?
class Cat {
? ? public Cat(String name) {
? ? ? ? this.name = name;
? ? }
?
? ? private String name;
?
? ? public String getName() {
? ? ? ? return name;
? ? }
?
? ? public void setName(String name) {
? ? ? ? this.name = name;
? ? }
}
?
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false?
輸出結(jié)果出乎我們的意料,竟然是 false?這是怎么回事,看了 equals 源碼就知道了,源碼如下:?
public boolean equals(Object obj) {
? ? return (this == obj);
}?
原來 equals 本質(zhì)上就是 ==。?
那問題來了,兩個(gè)相同值的 String 對(duì)象,為什么返回的是 true?代碼如下:?
String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true?
同樣的,當(dāng)我們進(jìn)入 String 的 equals 方法,找到了答案,代碼如下:?
public boolean equals(Object anObject) {
? ? if (this == anObject) {
? ? ? ? return true;
? ? }
? ? if (anObject instanceof String) {
? ? ? ? String anotherString = (String)anObject;
? ? ? ? int n = value.length;
? ? ? ? if (n == anotherString.value.length) {
? ? ? ? ? ? char v1[] = value;
? ? ? ? ? ? char v2[] = anotherString.value;
? ? ? ? ? ? int i = 0;
? ? ? ? ? ? while (n-- != 0) {
? ? ? ? ? ? ? ? if (v1[i] != v2[i])
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? i++;
? ? ? ? ? ? }
? ? ? ? ? ? return true;
? ? ? ? }
? ? }
? ? return false;
}?
原來是 String 重寫了 Object 的 equals 方法,把引用比較改成了值比較。?
總結(jié) :== 對(duì)于基本類型來說是值比較,對(duì)于引用類型來說是比較的是引用;而 equals 默認(rèn)情況下是引用比較,只是很多類重新了 equals 方法,比如 String、Integer 等把它變成了值比較,所以一般情況下 equals 比較的是值是否相等。?
3. 兩個(gè)對(duì)象的 hashCode()相同,則 equals()也一定為 true,對(duì)嗎??
不對(duì),兩個(gè)對(duì)象的 hashCode()相同,equals()不一定 true。?
代碼示例:?
String str1 = "通話";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d",? str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));?
執(zhí)行的結(jié)果:?
?
?str1:1179395 | str2:1179395?
?false?
?
代碼解讀:很顯然“通話”和“重地”的 hashCode() 相同,然而 equals() 則為 false,因?yàn)樵谏⒘斜碇?#xff0c;hashCode()相等即兩個(gè)鍵值對(duì)的哈希值相等,然而哈希值相等,并不一定能得出鍵值對(duì)相等。?
4. final 在 java 中有什么作用??
final 修飾的類叫最終類,該類不能被繼承。final 修飾的方法不能被重寫。final 修飾的變量叫常量,常量必須初始化,初始化之后值就不能被修改。
5. java 中的 Math.round(-1.5) 等于多少??
等于 -1,因?yàn)樵跀?shù)軸上取值時(shí),中間值(0.5)向右取整,所以正 0.5 是往上取整,負(fù) 0.5 是直接舍棄。?
6. String 屬于基礎(chǔ)的數(shù)據(jù)類型嗎??
String 不屬于基礎(chǔ)類型,基礎(chǔ)類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬于對(duì)象。?
7. java 中操作字符串都有哪些類?它們之間有什么區(qū)別??
操作字符串的類有:String、StringBuffer、StringBuilder。?
String 和 StringBuffer、StringBuilder 的區(qū)別在于 String 聲明的是不可變的對(duì)象,每次操作都會(huì)生成新的 String 對(duì)象,然后將指針指向新的 String 對(duì)象,而 StringBuffer、StringBuilder 可以在原有對(duì)象的基礎(chǔ)上進(jìn)行操作,所以在經(jīng)常改變字符串內(nèi)容的情況下最好不要使用 String。?
StringBuffer 和 StringBuilder 最大的區(qū)別在于,StringBuffer 是線程安全的,而 StringBuilder 是非線程安全的,但 StringBuilder 的性能卻高于 StringBuffer,所以在單線程環(huán)境下推薦使用 StringBuilder,多線程環(huán)境下推薦使用 StringBuffer。?
8. String str="i"與 String str=new String("i")一樣嗎??
不一樣,因?yàn)閮?nèi)存的分配方式不一樣。String str="i"的方式,java 虛擬機(jī)會(huì)將其分配到常量池中;而 String str=new String("i") 則會(huì)被分到堆內(nèi)存中。?
9. 如何將字符串反轉(zhuǎn)??
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。?
示例代碼:?
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder.reverse()); // gfedcba?
10. String 類的常用方法都有那些??
indexOf():返回指定字符的索引。charAt():返回指定索引處的字符。replace():字符串替換。trim():去除字符串兩端空白。split():分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。getBytes():返回字符串的 byte 類型數(shù)組。length():返回字符串長(zhǎng)度。toLowerCase():將字符串轉(zhuǎn)成小寫字母。toUpperCase():將字符串轉(zhuǎn)成大寫字符。substring():截取字符串。equals():字符串比較。
11. 抽象類必須要有抽象方法嗎??
不需要,抽象類不一定非要有抽象方法。?
示例代碼:?
abstract class Cat {
? ? public static void sayHi() {
? ? ? ? System.out.println("hi~");
? ? }
}?
上面代碼,抽象類并沒有抽象方法但完全可以正常運(yùn)行。?
12. 普通類和抽象類有哪些區(qū)別??
普通類不能包含抽象方法,抽象類可以包含抽象方法。抽象類不能直接實(shí)例化,普通類可以直接實(shí)例化。
13. 抽象類能使用 final 修飾嗎??
不能,定義抽象類就是讓其他類繼承的,如果定義為 final 該類就不能被繼承,這樣彼此就會(huì)產(chǎn)生矛盾,所以 final 不能修飾抽象類,如下圖所示,編輯器也會(huì)提示錯(cuò)誤信息:?
?
14. 接口和抽象類有什么區(qū)別??
實(shí)現(xiàn):抽象類的子類使用 extends 來繼承;接口必須使用 implements 來實(shí)現(xiàn)接口。構(gòu)造函數(shù):抽象類可以有構(gòu)造函數(shù);接口不能有。main 方法:抽象類可以有 main 方法,并且我們能運(yùn)行它;接口不能有 main 方法。實(shí)現(xiàn)數(shù)量:類可以實(shí)現(xiàn)很多個(gè)接口;但是只能繼承一個(gè)抽象類。訪問修飾符:接口中的方法默認(rèn)使用 public 修飾;抽象類中的方法可以是任意訪問修飾符。
15. java 中 IO 流分為幾種??
按功能來分:輸入流(input)、輸出流(output)。?
按類型來分:字節(jié)流和字符流。?
字節(jié)流和字符流的區(qū)別是:字節(jié)流按 8 位傳輸以字節(jié)為單位輸入輸出數(shù)據(jù),字符流按 16 位傳輸以字符為單位輸入輸出數(shù)據(jù)。?
16. BIO、NIO、AIO 有什么區(qū)別??
BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統(tǒng) IO,它的特點(diǎn)是模式簡(jiǎn)單使用方便,并發(fā)處理能力低。NIO:New IO 同步非阻塞 IO,是傳統(tǒng) IO 的升級(jí),客戶端和服務(wù)器端通過 Channel(通道)通訊,實(shí)現(xiàn)了多路復(fù)用。AIO:Asynchronous IO 是 NIO 的升級(jí),也叫 NIO2,實(shí)現(xiàn)了異步非堵塞 IO ,異步 IO 的操作基于事件和回調(diào)機(jī)制。
17. Files的常用方法都有哪些??
Files.exists():檢測(cè)文件路徑是否存在。Files.createFile():創(chuàng)建文件。Files.createDirectory():創(chuàng)建文件夾。Files.delete():刪除一個(gè)文件或目錄。Files.copy():復(fù)制文件。Files.move():移動(dòng)文件。Files.size():查看文件個(gè)數(shù)。Files.read():讀取文件。Files.write():寫入文件。
?
二、容器?
18. java 容器都有哪些??
常用容器的圖錄:?
?
19. Collection 和 Collections 有什么區(qū)別??
java.util.Collection 是一個(gè)集合接口(集合類的一個(gè)頂級(jí)接口)。它提供了對(duì)集合對(duì)象進(jìn)行基本操作的通用接口方法。Collection接口在Java 類庫中有很多具體的實(shí)現(xiàn)。Collection接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式,其直接繼承接口有List與Set。Collections則是集合類的一個(gè)工具類/幫助類,其中提供了一系列靜態(tài)方法,用于對(duì)集合中元素進(jìn)行排序、搜索以及線程安全等各種操作。
20. List、Set、Map 之間的區(qū)別是什么??
?
21. HashMap 和 Hashtable 有什么區(qū)別??
hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。hashMap允許空鍵值,而hashTable不允許。
22. 如何決定使用 HashMap 還是 TreeMap??
對(duì)于在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。然而,假如你需要對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap是更好的選擇。基于你的collection的大小,也許向HashMap中添加元素會(huì)更快,將map換為TreeMap進(jìn)行有序key的遍歷。?
23. 說一下 HashMap 的實(shí)現(xiàn)原理??
HashMap概述: HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恒久不變。??
HashMap的數(shù)據(jù)結(jié)構(gòu): 在java編程語言中,最基本的結(jié)構(gòu)就是兩種,一個(gè)是數(shù)組,另外一個(gè)是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來構(gòu)造的,HashMap也不例外。HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。?
當(dāng)我們往Hashmap中put元素時(shí),首先根據(jù)key的hashcode重新計(jì)算hash值,根絕hash值得到這個(gè)元素在數(shù)組中的位置(下標(biāo)),如果該數(shù)組在該位置上已經(jīng)存放了其他元素,那么在這個(gè)位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放入鏈尾.如果數(shù)組中該位置沒有元素,就直接將該元素放到數(shù)組的該位置上。?
需要注意Jdk 1.8中對(duì)HashMap的實(shí)現(xiàn)做了優(yōu)化,當(dāng)鏈表中的節(jié)點(diǎn)數(shù)據(jù)超過八個(gè)之后,該鏈表會(huì)轉(zhuǎn)為紅黑樹來提高查詢效率,從原來的O(n)到O(logn)?
24. 說一下 HashSet 的實(shí)現(xiàn)原理??
HashSet底層由HashMap實(shí)現(xiàn)HashSet的值存放于HashMap的key上HashMap的value統(tǒng)一為PRESENT
25. ArrayList 和 LinkedList 的區(qū)別是什么??
最明顯的區(qū)別是 ArrrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,支持隨機(jī)訪問,而 LinkedList 的底層數(shù)據(jù)結(jié)構(gòu)是雙向循環(huán)鏈表,不支持隨機(jī)訪問。使用下標(biāo)訪問一個(gè)元素,ArrayList 的時(shí)間復(fù)雜度是 O(1),而 LinkedList 是 O(n)。?
26. 如何實(shí)現(xiàn)數(shù)組和 List 之間的轉(zhuǎn)換??
List轉(zhuǎn)換成為數(shù)組:調(diào)用ArrayList的toArray方法。數(shù)組轉(zhuǎn)換成為L(zhǎng)ist:調(diào)用Arrays的asList方法。
27. ArrayList 和 Vector 的區(qū)別是什么??
Vector是同步的,而ArrayList不是。然而,如果你尋求在迭代的時(shí)候?qū)α斜磉M(jìn)行改變,你應(yīng)該使用CopyOnWriteArrayList。 ArrayList比Vector快,它因?yàn)橛型?#xff0c;不會(huì)過載。 ArrayList更加通用,因?yàn)槲覀兛梢允褂肅ollections工具類輕易地獲取同步列表和只讀列表。
28. Array 和 ArrayList 有何區(qū)別??
Array可以容納基本類型和對(duì)象,而ArrayList只能容納對(duì)象。 Array是指定大小的,而ArrayList大小是固定的。 Array沒有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
29. 在 Queue 中 poll()和 remove()有什么區(qū)別??
poll() 和 remove() 都是從隊(duì)列中取出一個(gè)元素,但是 poll() 在獲取元素失敗的時(shí)候會(huì)返回空,但是 remove() 失敗的時(shí)候會(huì)拋出異常。?
30. 哪些集合類是線程安全的??
vector:就比arraylist多了個(gè)同步化機(jī)制(線程安全),因?yàn)樾瘦^低,現(xiàn)在已經(jīng)不太建議使用。在web應(yīng)用中,特別是前臺(tái)頁面,往往效率(頁面響應(yīng)速度)是優(yōu)先考慮的。statck:堆棧類,先進(jìn)后出。hashtable:就比hashmap多了個(gè)線程安全。enumeration:枚舉,相當(dāng)于迭代器。
31. 迭代器 Iterator 是什么??
迭代器是一種設(shè)計(jì)模式,它是一個(gè)對(duì)象,它可以遍歷并選擇序列中的對(duì)象,而開發(fā)人員不需要了解該序列的底層結(jié)構(gòu)。迭代器通常被稱為“輕量級(jí)”對(duì)象,因?yàn)閯?chuàng)建它的代價(jià)小。?
32. Iterator 怎么使用?有什么特點(diǎn)??
Java中的Iterator功能比較簡(jiǎn)單,并且只能單向移動(dòng):?
(1) 使用方法iterator()要求容器返回一個(gè)Iterator。第一次調(diào)用Iterator的next()方法時(shí),它返回序列的第一個(gè)元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。?
(2) 使用next()獲得序列中的下一個(gè)元素。?
(3) 使用hasNext()檢查序列中是否還有元素。?
(4) 使用remove()將迭代器新返回的元素刪除。?
Iterator是Java迭代器最簡(jiǎn)單的實(shí)現(xiàn),為L(zhǎng)ist設(shè)計(jì)的ListIterator具有更多的功能,它可以從兩個(gè)方向遍歷List,也可以從List中插入和刪除元素。?
33. Iterator 和 ListIterator 有什么區(qū)別??
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。 Iterator對(duì)集合只能是前向遍歷,ListIterator既可以前向也可以后向。 ListIterator實(shí)現(xiàn)了Iterator接口,并包含其他的功能,比如:增加元素,替換元素,獲取前一個(gè)和后一個(gè)元素的索引,等等。
?
?三、多線程?
35. 并行和并發(fā)有什么區(qū)別??
并行是指兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生;而并發(fā)是指兩個(gè)或多個(gè)事件在同一時(shí)間間隔發(fā)生。并行是在不同實(shí)體上的多個(gè)事件,并發(fā)是在同一實(shí)體上的多個(gè)事件。在一臺(tái)處理器上“同時(shí)”處理多個(gè)任務(wù),在多臺(tái)處理器上同時(shí)處理多個(gè)任務(wù)。如hadoop分布式集群。
所以并發(fā)編程的目標(biāo)是充分的利用處理器的每一個(gè)核,以達(dá)到最高的處理性能。?
36. 線程和進(jìn)程的區(qū)別??
簡(jiǎn)而言之,進(jìn)程是程序運(yùn)行和資源分配的基本單位,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程。進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存資源,減少切換次數(shù),從而效率更高。線程是進(jìn)程的一個(gè)實(shí)體,是cpu調(diào)度和分派的基本單位,是比程序更小的能獨(dú)立運(yùn)行的基本單位。同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。?
37. 守護(hù)線程是什么??
守護(hù)線程(即daemon thread),是個(gè)服務(wù)線程,準(zhǔn)確地來說就是服務(wù)其他的線程。?
38. 創(chuàng)建線程有哪幾種方式??
①. 繼承Thread類創(chuàng)建線程類?
定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務(wù)。因此把run()方法稱為執(zhí)行體。創(chuàng)建Thread子類的實(shí)例,即創(chuàng)建了線程對(duì)象。調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程。
②. 通過Runnable接口創(chuàng)建線程類?
定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體。創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例,并依此實(shí)例作為Thread的target來創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象。調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程。
③. 通過Callable和Future創(chuàng)建線程?
創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值。創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例,使用FutureTask類來包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程。調(diào)用FutureTask對(duì)象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值。
39. 說一下 runnable 和 callable 有什么區(qū)別??
有點(diǎn)深的問題了,也看出一個(gè)Java程序員學(xué)習(xí)知識(shí)的廣度。?
Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已;Callable接口中的call()方法是有返回值的,是一個(gè)泛型,和Future、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果。
40. 線程有哪些狀態(tài)??
線程通常都有五種狀態(tài),創(chuàng)建、就緒、運(yùn)行、阻塞和死亡。?
創(chuàng)建狀態(tài)。在生成線程對(duì)象,并沒有調(diào)用該對(duì)象的start方法,這是線程處于創(chuàng)建狀態(tài)。就緒狀態(tài)。當(dāng)調(diào)用了線程對(duì)象的start方法之后,該線程就進(jìn)入了就緒狀態(tài),但是此時(shí)線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程,此時(shí)處于就緒狀態(tài)。在線程運(yùn)行之后,從等待或者睡眠中回來之后,也會(huì)處于就緒狀態(tài)。運(yùn)行狀態(tài)。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當(dāng)前線程,此時(shí)線程就進(jìn)入了運(yùn)行狀態(tài),開始運(yùn)行run函數(shù)當(dāng)中的代碼。阻塞狀態(tài)。線程正在運(yùn)行的時(shí)候,被暫停,通常是為了等待某個(gè)時(shí)間的發(fā)生(比如說某項(xiàng)資源就緒)之后再繼續(xù)運(yùn)行。sleep,suspend,wait等方法都可以導(dǎo)致線程阻塞。死亡狀態(tài)。如果一個(gè)線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后,該線程就會(huì)死亡。對(duì)于已經(jīng)死亡的線程,無法再使用start方法令其進(jìn)入就緒
41. sleep() 和 wait() 有什么區(qū)別??
sleep():方法是線程類(Thread)的靜態(tài)方法,讓調(diào)用線程進(jìn)入睡眠狀態(tài),讓出執(zhí)行機(jī)會(huì)給其他線程,等到休眠時(shí)間結(jié)束后,線程進(jìn)入就緒狀態(tài)和其他線程一起競(jìng)爭(zhēng)cpu的執(zhí)行時(shí)間。因?yàn)閟leep() 是static靜態(tài)的方法,他不能改變對(duì)象的機(jī)鎖,當(dāng)一個(gè)synchronized塊中調(diào)用了sleep() 方法,線程雖然進(jìn)入休眠,但是對(duì)象的機(jī)鎖沒有被釋放,其他線程依然無法訪問這個(gè)對(duì)象。?
wait():wait()是Object類的方法,當(dāng)一個(gè)線程執(zhí)行到wait方法時(shí),它就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池,同時(shí)釋放對(duì)象的機(jī)鎖,使得其他線程能夠訪問,可以通過notify,notifyAll方法來喚醒等待的線程。?
42. notify()和 notifyAll()有什么區(qū)別??
如果線程調(diào)用了對(duì)象的 wait()方法,那么線程便會(huì)處于該對(duì)象的等待池中,等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。當(dāng)有線程調(diào)用了對(duì)象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機(jī)喚醒一個(gè) wait 線程),被喚醒的的線程便會(huì)進(jìn)入該對(duì)象的鎖池中,鎖池中的線程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖。也就是說,調(diào)用了notify后只要一個(gè)線程會(huì)由等待池進(jìn)入鎖池,而notifyAll會(huì)將該對(duì)象等待池內(nèi)的所有線程移動(dòng)到鎖池中,等待鎖競(jìng)爭(zhēng)。優(yōu)先級(jí)高的線程競(jìng)爭(zhēng)到對(duì)象鎖的概率大,假若某線程沒有競(jìng)爭(zhēng)到該對(duì)象鎖,它還會(huì)留在鎖池中,唯有線程再次調(diào)用 wait()方法,它才會(huì)重新回到等待池中。而競(jìng)爭(zhēng)到對(duì)象鎖的線程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了 synchronized 代碼塊,它會(huì)釋放掉該對(duì)象鎖,這時(shí)鎖池中的線程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖。
43. 線程的 run()和 start()有什么區(qū)別??
每個(gè)線程都是通過某個(gè)特定Thread對(duì)象所對(duì)應(yīng)的方法run()來完成其操作的,方法run()稱為線程體。通過調(diào)用Thread類的start()方法來啟動(dòng)一個(gè)線程。?
start()方法來啟動(dòng)一個(gè)線程,真正實(shí)現(xiàn)了多線程運(yùn)行。這時(shí)無需等待run方法體代碼執(zhí)行完畢,可以直接繼續(xù)執(zhí)行下面的代碼; 這時(shí)此線程是處于就緒狀態(tài), 并沒有運(yùn)行。 然后通過此Thread類調(diào)用方法run()來完成其運(yùn)行狀態(tài), 這里方法run()稱為線程體,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容, Run方法運(yùn)行結(jié)束, 此線程終止。然后CPU再調(diào)度其它線程。?
run()方法是在本線程里的,只是線程里的一個(gè)函數(shù),而不是多線程的。 如果直接調(diào)用run(),其實(shí)就相當(dāng)于是調(diào)用了一個(gè)普通函數(shù)而已,直接待用run()方法必須等待run()方法執(zhí)行完畢才能執(zhí)行下面的代碼,所以執(zhí)行路徑還是只有一條,根本就沒有線程的特征,所以在多線程執(zhí)行時(shí)要使用start()方法而不是run()方法。?
44. 創(chuàng)建線程池有哪幾種方式??
①. newFixedThreadPool(int nThreads)?
創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到達(dá)到線程池的最大數(shù)量,這時(shí)線程規(guī)模將不再變化,當(dāng)線程發(fā)生未預(yù)期的錯(cuò)誤而結(jié)束時(shí),線程池會(huì)補(bǔ)充一個(gè)新的線程。?
②. newCachedThreadPool()?
創(chuàng)建一個(gè)可緩存的線程池,如果線程池的規(guī)模超過了處理需求,將自動(dòng)回收空閑線程,而當(dāng)需求增加時(shí),則可以自動(dòng)添加新線程,線程池的規(guī)模不存在任何限制。?
③. newSingleThreadExecutor()?
這是一個(gè)單線程的Executor,它創(chuàng)建單個(gè)工作線程來執(zhí)行任務(wù),如果這個(gè)線程異常結(jié)束,會(huì)創(chuàng)建一個(gè)新的來替代它;它的特點(diǎn)是能確保依照任務(wù)在隊(duì)列中的順序來串行執(zhí)行。?
④. newScheduledThreadPool(int corePoolSize)?
創(chuàng)建了一個(gè)固定長(zhǎng)度的線程池,而且以延遲或定時(shí)的方式來執(zhí)行任務(wù),類似于Timer。?
45. 線程池都有哪些狀態(tài)??
線程池有5種狀態(tài):Running、ShutDown、Stop、Tidying、Terminated。?
線程池各個(gè)狀態(tài)切換框架圖:?
?
46. 線程池中 submit()和 execute()方法有什么區(qū)別??
接收的參數(shù)不一樣submit有返回值,而execute沒有submit方便Exception處理
47. 在 java 程序中怎么保證多線程的運(yùn)行安全??
線程安全在三個(gè)方面體現(xiàn):?
原子性:提供互斥訪問,同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)進(jìn)行操作,(atomic,synchronized);可見性:一個(gè)線程對(duì)主內(nèi)存的修改可以及時(shí)地被其他線程看到,(synchronized,volatile);有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序,該觀察結(jié)果一般雜亂無序,(happens-before原則)。
48. 多線程鎖的升級(jí)原理是什么??
在Java中,鎖共有4種狀態(tài),級(jí)別從低到高依次為:無狀態(tài)鎖,偏向鎖,輕量級(jí)鎖和重量級(jí)鎖狀態(tài),這幾個(gè)狀態(tài)會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)。鎖可以升級(jí)但不能降級(jí)。?
鎖升級(jí)的圖示過程:??
?
49. 什么是死鎖??
死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過程中,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程。是操作系統(tǒng)層面的一個(gè)錯(cuò)誤,是進(jìn)程死鎖的簡(jiǎn)稱,最早在 1965 年由 Dijkstra 在研究銀行家算法時(shí)提出的,它是計(jì)算機(jī)操作系統(tǒng)乃至整個(gè)并發(fā)程序設(shè)計(jì)領(lǐng)域最難處理的問題之一。?
50. 怎么防止死鎖??
死鎖的四個(gè)必要條件:?
互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程進(jìn)行訪問,若其他進(jìn)程訪問該資源,只能等待,直至占有該資源的進(jìn)程使用完成后釋放該資源請(qǐng)求和保持條件:進(jìn)程獲得一定的資源之后,又對(duì)其他資源發(fā)出請(qǐng)求,但是該資源可能被其他進(jìn)程占有,此事請(qǐng)求阻塞,但又對(duì)自己獲得的資源保持不放不可剝奪條件:是指進(jìn)程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用完后自己釋放環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后,若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個(gè)條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之 一不滿足,就不會(huì)發(fā)生死鎖。?
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個(gè)必要條件,就可以最大可能地避免、預(yù)防和 解除死鎖。?
所以,在系統(tǒng)設(shè)計(jì)、進(jìn)程調(diào)度等方面注意如何不讓這四個(gè)必要條件成立,如何確 定資源的合理分配算法,避免進(jìn)程永久占據(jù)系統(tǒng)資源。?
此外,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源。因此,對(duì)資源的分配要給予合理的規(guī)劃。?
51. ThreadLocal 是什么?有哪些使用場(chǎng)景??
線程局部變量是局限于線程內(nèi)部的變量,屬于線程自身所有,不在多個(gè)線程間共享。Java提供ThreadLocal類來支持線程局部變量,是一種實(shí)現(xiàn)線程安全的方式。但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時(shí)候要特別小心,在這種情況下,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長(zhǎng)。任何線程局部變量一旦在工作完成后沒有釋放,Java 應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)。?
52.說一下 synchronized 底層實(shí)現(xiàn)原理??
synchronized可以保證方法或者代碼塊在運(yùn)行時(shí),同一時(shí)刻只有一個(gè)方法可以進(jìn)入到臨界區(qū),同時(shí)它還可以保證共享變量的內(nèi)存可見性。?
Java中每一個(gè)對(duì)象都可以作為鎖,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):?
普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象靜態(tài)同步方法,鎖是當(dāng)前類的class對(duì)象同步方法塊,鎖是括號(hào)里面的對(duì)象
53. synchronized 和 volatile 的區(qū)別是什么??
volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問該變量,其他線程被阻塞住。volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量、方法、和類級(jí)別的。volatile僅能實(shí)現(xiàn)變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized標(biāo)記的變量可以被編譯器優(yōu)化。
54. synchronized 和 Lock 有什么區(qū)別??
首先synchronized是java內(nèi)置關(guān)鍵字,在jvm層面,Lock是個(gè)java類;synchronized無法判斷是否獲取鎖的狀態(tài),Lock可以判斷是否獲取到鎖;synchronized會(huì)自動(dòng)釋放鎖(a 線程執(zhí)行完同步代碼會(huì)釋放鎖 ;b 線程執(zhí)行過程中發(fā)生異常會(huì)釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;用synchronized關(guān)鍵字的兩個(gè)線程1和線程2,如果當(dāng)前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會(huì)一直等待下去,而Lock鎖就不一定會(huì)等待下去,如果嘗試獲取不到鎖,線程可以不用一直等待就結(jié)束了;synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可); Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。?
55. synchronized 和 ReentrantLock 區(qū)別是什么??
synchronized是和if、else、for、while一樣的關(guān)鍵字,ReentrantLock是類,這是二者的本質(zhì)區(qū)別。既然ReentrantLock是類,那么它就提供了比synchronized更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock比synchronized的擴(kuò)展性體現(xiàn)在幾點(diǎn)上:??
ReentrantLock可以對(duì)獲取鎖的等待時(shí)間進(jìn)行設(shè)置,這樣就避免了死鎖 ReentrantLock可以獲取各種鎖的信息ReentrantLock可以靈活地實(shí)現(xiàn)多路通知?
另外,二者的鎖機(jī)制其實(shí)也是不一樣的:ReentrantLock底層調(diào)用的是Unsafe的park方法加鎖,synchronized操作的應(yīng)該是對(duì)象頭中mark word。?
56. 說一下 atomic 的原理??
Atomic包中的類基本的特性就是在多線程環(huán)境下,當(dāng)有多個(gè)線程同時(shí)對(duì)單個(gè)(包括基本類型及引用類型)變量進(jìn)行操作時(shí),具有排他性,即當(dāng)多個(gè)線程同時(shí)對(duì)該變量的值進(jìn)行更新時(shí),僅有一個(gè)線程能成功,而未成功的線程可以向自旋鎖一樣,繼續(xù)嘗試,一直等到執(zhí)行成功。?
Atomic系列的類中的核心方法都會(huì)調(diào)用unsafe類中的幾個(gè)本地方法。我們需要先知道一個(gè)東西就是Unsafe類,全名為:sun.misc.Unsafe,這個(gè)類包含了大量的對(duì)C代碼的操作,包括很多直接內(nèi)存分配以及原子操作的調(diào)用,而它之所以標(biāo)記為非安全的,是告訴你這個(gè)里面大量的方法調(diào)用都會(huì)存在安全隱患,需要小心使用,否則會(huì)導(dǎo)致嚴(yán)重的后果,例如在通過unsafe分配內(nèi)存的時(shí)候,如果自己指定某些區(qū)域可能會(huì)導(dǎo)致一些類似C++一樣的指針越界到其他進(jìn)程的問題。?
?
四、反射?
57. 什么是反射??
反射主要是指程序可以訪問、檢測(cè)和修改它本身狀態(tài)或行為的一種能力?
Java反射:?
在Java運(yùn)行時(shí)環(huán)境中,對(duì)于任意一個(gè)類,能否知道這個(gè)類有哪些屬性和方法?對(duì)于任意一個(gè)對(duì)象,能否調(diào)用它的任意一個(gè)方法?
Java反射機(jī)制主要提供了以下功能:?
在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象。在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法。在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法。?
58. 什么是 java 序列化?什么情況下需要序列化??
簡(jiǎn)單說就是為了保存在內(nèi)存中的各種對(duì)象的狀態(tài)(也就是實(shí)例變量,不是方法),并且可以把保存的對(duì)象狀態(tài)再讀出來。雖然你可以用你自己的各種各樣的方法來保存object states,但是Java給你提供一種應(yīng)該比你自己好的保存對(duì)象狀態(tài)的機(jī)制,那就是序列化。 什么情況下需要序列化:?
a)當(dāng)你想把的內(nèi)存中的對(duì)象狀態(tài)保存到一個(gè)文件中或者數(shù)據(jù)庫中時(shí)候; b)當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對(duì)象的時(shí)候; c)當(dāng)你想通過RMI傳輸對(duì)象的時(shí)候;?
59. 動(dòng)態(tài)代理是什么?有哪些應(yīng)用??
動(dòng)態(tài)代理:?
當(dāng)想要給實(shí)現(xiàn)了某個(gè)接口的類中的方法,加一些額外的處理。比如說加日志,加事務(wù)等。可以給這個(gè)類創(chuàng)建一個(gè)代理,故名思議就是創(chuàng)建一個(gè)新的類,這個(gè)類不僅包含原來類方法的功能,而且還在原來的基礎(chǔ)上添加了額外處理的新類。這個(gè)代理類并不是定義好的,是動(dòng)態(tài)生成的。具有解耦意義,靈活,擴(kuò)展性強(qiáng)。?
動(dòng)態(tài)代理的應(yīng)用:?
Spring的AOP加事務(wù)加權(quán)限加日志
60. 怎么實(shí)現(xiàn)動(dòng)態(tài)代理??
首先必須定義一個(gè)接口,還要有一個(gè)InvocationHandler(將實(shí)現(xiàn)接口的類的對(duì)象傳遞給它)處理類。再有一個(gè)工具類Proxy(習(xí)慣性將其稱為代理類,因?yàn)檎{(diào)用他的newInstance()可以產(chǎn)生代理對(duì)象,其實(shí)他只是一個(gè)產(chǎn)生代理對(duì)象的工具類)。利用到InvocationHandler,拼接代理類源碼,將其編譯生成代理類的二進(jìn)制碼,利用加載器加載,并將其實(shí)例化產(chǎn)生代理對(duì)象,最后返回。?
?
五、對(duì)象拷貝?
61. 為什么要使用克隆??
想對(duì)一個(gè)對(duì)象進(jìn)行處理,又想保留原有的數(shù)據(jù)進(jìn)行接下來的操作,就需要克隆了,Java語言中克隆針對(duì)的是類的實(shí)例。?
62. 如何實(shí)現(xiàn)對(duì)象克隆??
有兩種方式:?
1). 實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法;?
2). 實(shí)現(xiàn)Serializable接口,通過對(duì)象的序列化和反序列化實(shí)現(xiàn)克隆,可以實(shí)現(xiàn)真正的深度克隆,代碼如下:?
?
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
?
public class MyUtil {
?
? ? private MyUtil() {
? ? ? ? throw new AssertionError();
? ? }
?
? ? @SuppressWarnings("unchecked")
? ? public static <T extends Serializable> T clone(T obj) throws Exception {
? ? ? ? ByteArrayOutputStream bout = new ByteArrayOutputStream();
? ? ? ? ObjectOutputStream oos = new ObjectOutputStream(bout);
? ? ? ? oos.writeObject(obj);
?
? ? ? ? ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
? ? ? ? ObjectInputStream ois = new ObjectInputStream(bin);
? ? ? ? return (T) ois.readObject();
?
? ? ? ? // 說明:調(diào)用ByteArrayInputStream或ByteArrayOutputStream對(duì)象的close方法沒有任何意義
? ? ? ? // 這兩個(gè)基于內(nèi)存的流只要垃圾回收器清理對(duì)象就能夠釋放資源,這一點(diǎn)不同于對(duì)外部資源(如文件流)的釋放
? ? }
}?
下面是測(cè)試代碼:?
?
import java.io.Serializable;
?
/**
?* 人類
?* @author nnngu
?*
?*/
class Person implements Serializable {
? ? private static final long serialVersionUID = -9102017020286042305L;
?
? ? private String name;? ? // 姓名
? ? private int age;? ? ? ? // 年齡
? ? private Car car;? ? ? ? // 座駕
?
? ? public Person(String name, int age, Car car) {
? ? ? ? this.name = name;
? ? ? ? this.age = age;
? ? ? ? this.car = car;
? ? }
?
? ? 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;
? ? }
?
? ? public Car getCar() {
? ? ? ? return car;
? ? }
?
? ? public void setCar(Car car) {
? ? ? ? this.car = car;
? ? }
?
? ? @Override
? ? public String toString() {
? ? ? ? return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
? ? }
?
}?
?
/**
?* 小汽車類
?* @author nnngu
?*
?*/
class Car implements Serializable {
? ? private static final long serialVersionUID = -5713945027627603702L;
?
? ? private String brand;? ? ? ?// 品牌
? ? private int maxSpeed;? ? ? ?// 最高時(shí)速
?
? ? public Car(String brand, int maxSpeed) {
? ? ? ? this.brand = brand;
? ? ? ? this.maxSpeed = maxSpeed;
? ? }
?
? ? public String getBrand() {
? ? ? ? return brand;
? ? }
?
? ? public void setBrand(String brand) {
? ? ? ? this.brand = brand;
? ? }
?
? ? public int getMaxSpeed() {
? ? ? ? return maxSpeed;
? ? }
?
? ? public void setMaxSpeed(int maxSpeed) {
? ? ? ? this.maxSpeed = maxSpeed;
? ? }
?
? ? @Override
? ? public String toString() {
? ? ? ? return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
? ? }
?
}?
class CloneTest {
?
? ? public static void main(String[] args) {
? ? ? ? try {
? ? ? ? ? ? Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
? ? ? ? ? ? Person p2 = MyUtil.clone(p1);? ?// 深度克隆
? ? ? ? ? ? p2.getCar().setBrand("BYD");
? ? ? ? ? ? // 修改克隆的Person對(duì)象p2關(guān)聯(lián)的汽車對(duì)象的品牌屬性
? ? ? ? ? ? // 原來的Person對(duì)象p1關(guān)聯(lián)的汽車不會(huì)受到任何影響
? ? ? ? ? ? // 因?yàn)樵诳寺erson對(duì)象時(shí)其關(guān)聯(lián)的汽車對(duì)象也被克隆了
? ? ? ? ? ? System.out.println(p1);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
}?
注意:基于序列化和反序列化實(shí)現(xiàn)的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的對(duì)象是否支持序列化,這項(xiàng)檢查是編譯器完成的,不是在運(yùn)行時(shí)拋出異常,這種是方案明顯優(yōu)于使用Object類的clone方法克隆對(duì)象。讓問題在編譯的時(shí)候暴露出來總是好過把問題留到運(yùn)行時(shí)。?
63. 深拷貝和淺拷貝區(qū)別是什么??
淺拷貝只是復(fù)制了對(duì)象的引用地址,兩個(gè)對(duì)象指向同一個(gè)內(nèi)存地址,所以修改其中任意的值,另一個(gè)值都會(huì)隨之變化,這就是淺拷貝(例:assign())深拷貝是將對(duì)象及值復(fù)制過來,兩個(gè)對(duì)象修改其中任意的值另一個(gè)值不會(huì)改變,這就是深拷貝(例:JSON.parse()和JSON.stringify(),但是此方法無法復(fù)制函數(shù)類型)
?
六、Java Web?
64. jsp 和 servlet 有什么區(qū)別??
jsp經(jīng)編譯后就變成了Servlet.(JSP的本質(zhì)就是Servlet,JVM只能識(shí)別java的類,不能識(shí)別JSP的代碼,Web容器將JSP的代碼編譯成JVM能夠識(shí)別的java類)jsp更擅長(zhǎng)表現(xiàn)于頁面顯示,servlet更擅長(zhǎng)于邏輯控制。Servlet中沒有內(nèi)置對(duì)象,Jsp中的內(nèi)置對(duì)象都是必須通過HttpServletRequest對(duì)象,HttpServletResponse對(duì)象以及HttpServlet對(duì)象得到。Jsp是Servlet的一種簡(jiǎn)化,使用Jsp只需要完成程序員需要輸出到客戶端的內(nèi)容,Jsp中的Java腳本如何鑲嵌到一個(gè)類中,由Jsp容器完成。而Servlet則是個(gè)完整的Java類,這個(gè)類的Service方法用于生成對(duì)客戶端的響應(yīng)。
65. jsp 有哪些內(nèi)置對(duì)象?作用分別是什么??
JSP有9個(gè)內(nèi)置對(duì)象:?
request:封裝客戶端的請(qǐng)求,其中包含來自GET或POST請(qǐng)求的參數(shù);response:封裝服務(wù)器對(duì)客戶端的響應(yīng);pageContext:通過該對(duì)象可以獲取其他對(duì)象;session:封裝用戶會(huì)話的對(duì)象;application:封裝服務(wù)器運(yùn)行環(huán)境的對(duì)象;out:輸出服務(wù)器響應(yīng)的輸出流對(duì)象;config:Web應(yīng)用的配置對(duì)象;page:JSP頁面本身(相當(dāng)于Java程序中的this);exception:封裝頁面拋出異常的對(duì)象。
66. 說一下 jsp 的 4 種作用域??
JSP中的四種作用域包括page、request、session和application,具體來說:?
page代表與一個(gè)頁面相關(guān)的對(duì)象和屬性。request代表與Web客戶機(jī)發(fā)出的一個(gè)請(qǐng)求相關(guān)的對(duì)象和屬性。一個(gè)請(qǐng)求可能跨越多個(gè)頁面,涉及多個(gè)Web組件;需要在頁面顯示的臨時(shí)數(shù)據(jù)可以置于此作用域。session代表與某個(gè)用戶與服務(wù)器建立的一次會(huì)話相關(guān)的對(duì)象和屬性。跟某個(gè)用戶相關(guān)的數(shù)據(jù)應(yīng)該放在用戶自己的session中。application代表與整個(gè)Web應(yīng)用程序相關(guān)的對(duì)象和屬性,它實(shí)質(zhì)上是跨越整個(gè)Web應(yīng)用程序,包括多個(gè)頁面、請(qǐng)求和會(huì)話的一個(gè)全局作用域。
67. session 和 cookie 有什么區(qū)別??
由于HTTP協(xié)議是無狀態(tài)的協(xié)議,所以服務(wù)端需要記錄用戶的狀態(tài)時(shí),就需要用某種機(jī)制來識(shí)具體的用戶,這個(gè)機(jī)制就是Session.典型的場(chǎng)景比如購物車,當(dāng)你點(diǎn)擊下單按鈕時(shí),由于HTTP協(xié)議無狀態(tài),所以并不知道是哪個(gè)用戶操作的,所以服務(wù)端要為特定的用戶創(chuàng)建了特定的Session,用用于標(biāo)識(shí)這個(gè)用戶,并且跟蹤用戶,這樣才知道購物車?yán)锩嬗袔妆緯_@個(gè)Session是保存在服務(wù)端的,有一個(gè)唯一標(biāo)識(shí)。在服務(wù)端保存Session的方法很多,內(nèi)存、數(shù)據(jù)庫、文件都有。集群的時(shí)候也要考慮Session的轉(zhuǎn)移,在大型的網(wǎng)站,一般會(huì)有專門的Session服務(wù)器集群,用來保存用戶會(huì)話,這個(gè)時(shí)候 Session 信息都是放在內(nèi)存的,使用一些緩存服務(wù)比如Memcached之類的來放 Session。思考一下服務(wù)端如何識(shí)別特定的客戶?這個(gè)時(shí)候Cookie就登場(chǎng)了。每次HTTP請(qǐng)求的時(shí)候,客戶端都會(huì)發(fā)送相應(yīng)的Cookie信息到服務(wù)端。實(shí)際上大多數(shù)的應(yīng)用都是用 Cookie 來實(shí)現(xiàn)Session跟蹤的,第一次創(chuàng)建Session的時(shí)候,服務(wù)端會(huì)在HTTP協(xié)議中告訴客戶端,需要在 Cookie 里面記錄一個(gè)Session ID,以后每次請(qǐng)求把這個(gè)會(huì)話ID發(fā)送到服務(wù)器,我就知道你是誰了。有人問,如果客戶端的瀏覽器禁用了 Cookie 怎么辦?一般這種情況下,會(huì)使用一種叫做URL重寫的技術(shù)來進(jìn)行會(huì)話跟蹤,即每次HTTP交互,URL后面都會(huì)被附加上一個(gè)諸如 sid=xxxxx 這樣的參數(shù),服務(wù)端據(jù)此來識(shí)別用戶。Cookie其實(shí)還可以用在一些方便用戶的場(chǎng)景下,設(shè)想你某次登陸過一個(gè)網(wǎng)站,下次登錄的時(shí)候不想再次輸入賬號(hào)了,怎么辦?這個(gè)信息可以寫到Cookie里面,訪問網(wǎng)站的時(shí)候,網(wǎng)站頁面的腳本可以讀取這個(gè)信息,就自動(dòng)幫你把用戶名給填了,能夠方便一下用戶。這也是Cookie名稱的由來,給用戶的一點(diǎn)甜頭。所以,總結(jié)一下:Session是在服務(wù)端保存的一個(gè)數(shù)據(jù)結(jié)構(gòu),用來跟蹤用戶的狀態(tài),這個(gè)數(shù)據(jù)可以保存在集群、數(shù)據(jù)庫、文件中;Cookie是客戶端保存用戶信息的一種機(jī)制,用來記錄用戶的一些信息,也是實(shí)現(xiàn)Session的一種方式。
68. 說一下 session 的工作原理??
其實(shí)session是一個(gè)存在服務(wù)器上的類似于一個(gè)散列表格的文件。里面存有我們需要的信息,在我們需要用的時(shí)候可以從里面取出來。類似于一個(gè)大號(hào)的map吧,里面的鍵存儲(chǔ)的是用戶的sessionid,用戶向服務(wù)器發(fā)送請(qǐng)求的時(shí)候會(huì)帶上這個(gè)sessionid。這時(shí)就可以從中取出對(duì)應(yīng)的值了。?
69. 如果客戶端禁止 cookie 能實(shí)現(xiàn) session 還能用嗎??
Cookie與 Session,一般認(rèn)為是兩個(gè)獨(dú)立的東西,Session采用的是在服務(wù)器端保持狀態(tài)的方案,而Cookie采用的是在客戶端保持狀態(tài)的方案。但為什么禁用Cookie就不能得到Session呢?因?yàn)镾ession是用Session ID來確定當(dāng)前對(duì)話所對(duì)應(yīng)的服務(wù)器Session,而Session ID是通過Cookie來傳遞的,禁用Cookie相當(dāng)于失去了Session ID,也就得不到Session了。?
假定用戶關(guān)閉Cookie的情況下使用Session,其實(shí)現(xiàn)途徑有以下幾種:?
設(shè)置php.ini配置文件中的“session.use_trans_sid = 1”,或者編譯時(shí)打開打開了“--enable-trans-sid”選項(xiàng),讓PHP自動(dòng)跨頁傳遞Session ID。手動(dòng)通過URL傳值、隱藏表單傳遞Session ID。用文件、數(shù)據(jù)庫等形式保存Session ID,在跨頁過程中手動(dòng)調(diào)用。
70. spring mvc 和 struts 的區(qū)別是什么??
攔截機(jī)制的不同
Struts2是類級(jí)別的攔截,每次請(qǐng)求就會(huì)創(chuàng)建一個(gè)Action,和Spring整合時(shí)Struts2的ActionBean注入作用域是原型模式prototype,然后通過setter,getter吧request數(shù)據(jù)注入到屬性。Struts2中,一個(gè)Action對(duì)應(yīng)一個(gè)request,response上下文,在接收參數(shù)時(shí),可以通過屬性接收,這說明屬性參數(shù)是讓多個(gè)方法共享的。Struts2中Action的一個(gè)方法可以對(duì)應(yīng)一個(gè)url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標(biāo)識(shí)其所屬方法了,只能設(shè)計(jì)為多例。?
SpringMVC是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)Request上下文,所以方法直接基本上是獨(dú)立的,獨(dú)享request,response數(shù)據(jù)。而每個(gè)方法同時(shí)又何一個(gè)url對(duì)應(yīng),參數(shù)的傳遞是直接注入到方法中的,是方法所獨(dú)有的。處理結(jié)果通過ModeMap返回給框架。在Spring整合時(shí),SpringMVC的Controller Bean默認(rèn)單例模式Singleton,所以默認(rèn)對(duì)所有的請(qǐng)求,只會(huì)創(chuàng)建一個(gè)Controller,有應(yīng)為沒有共享的屬性,所以是線程安全的,如果要改變默認(rèn)的作用域,需要添加@Scope注解修改。?
Struts2有自己的攔截Interceptor機(jī)制,SpringMVC這是用的是獨(dú)立的Aop方式,這樣導(dǎo)致Struts2的配置文件量還是比SpringMVC大。?
底層框架的不同
Struts2采用Filter(StrutsPrepareAndExecuteFilter)實(shí)現(xiàn),SpringMVC(DispatcherServlet)則采用Servlet實(shí)現(xiàn)。Filter在容器啟動(dòng)之后即初始化;服務(wù)停止以后墜毀,晚于Servlet。Servlet在是在調(diào)用時(shí)初始化,先于Filter調(diào)用,服務(wù)停止后銷毀。?
性能方面
Struts2是類級(jí)別的攔截,每次請(qǐng)求對(duì)應(yīng)實(shí)例一個(gè)新的Action,需要加載所有的屬性值注入,SpringMVC實(shí)現(xiàn)了零配置,由于SpringMVC基于方法的攔截,有加載一次單例模式bean注入。所以,SpringMVC開發(fā)效率和性能高于Struts2。?
配置方面
spring MVC和Spring是無縫的。從這個(gè)項(xiàng)目的管理和安全上也比Struts2高。?
71. 如何避免 sql 注入??
PreparedStatement(簡(jiǎn)單又有效的方法)使用正則表達(dá)式過濾傳入的參數(shù)字符串過濾JSP中調(diào)用該函數(shù)檢查是否包函非法字符JSP頁面判斷代碼
72. 什么是 XSS 攻擊,如何避免??
XSS攻擊又稱CSS,全稱Cross Site Script? (跨站腳本攻擊),其原理是攻擊者向有XSS漏洞的網(wǎng)站中輸入惡意的 HTML 代碼,當(dāng)用戶瀏覽該網(wǎng)站時(shí),這段 HTML 代碼會(huì)自動(dòng)執(zhí)行,從而達(dá)到攻擊的目的。XSS 攻擊類似于 SQL 注入攻擊,SQL注入攻擊中以SQL語句作為用戶輸入,從而達(dá)到查詢/修改/刪除數(shù)據(jù)的目的,而在xss攻擊中,通過插入惡意腳本,實(shí)現(xiàn)對(duì)用戶游覽器的控制,獲取用戶的一些信息。 XSS是 Web 程序中常見的漏洞,XSS 屬于被動(dòng)式且用于客戶端的攻擊方式。?
XSS防范的總體思路是:對(duì)輸入(和URL參數(shù))進(jìn)行過濾,對(duì)輸出進(jìn)行編碼。?
73. 什么是 CSRF 攻擊,如何避免??
CSRF(Cross-site request forgery)也被稱為 one-click attack或者 session riding,中文全稱是叫跨站請(qǐng)求偽造。一般來說,攻擊者通過偽造用戶的瀏覽器的請(qǐng)求,向訪問一個(gè)用戶自己曾經(jīng)認(rèn)證訪問過的網(wǎng)站發(fā)送出去,使目標(biāo)網(wǎng)站接收并誤以為是用戶的真實(shí)操作而去執(zhí)行命令。常用于盜取賬號(hào)、轉(zhuǎn)賬、發(fā)送虛假消息等。攻擊者利用網(wǎng)站對(duì)請(qǐng)求的驗(yàn)證漏洞而實(shí)現(xiàn)這樣的攻擊行為,網(wǎng)站能夠確認(rèn)請(qǐng)求來源于用戶的瀏覽器,卻不能驗(yàn)證請(qǐng)求是否源于用戶的真實(shí)意愿下的操作行為。?
如何避免:?
1. 驗(yàn)證 HTTP Referer 字段?
?
?HTTP頭中的Referer字段記錄了該 HTTP 請(qǐng)求的來源地址。在通常情況下,訪問一個(gè)安全受限頁面的請(qǐng)求來自于同一個(gè)網(wǎng)站,而如果黑客要對(duì)其實(shí)施 CSRF 攻擊,他一般只能在他自己的網(wǎng)站構(gòu)造請(qǐng)求。因此,可以通過驗(yàn)證Referer值來防御CSRF 攻擊。?
?
2. 使用驗(yàn)證碼?
?
?關(guān)鍵操作頁面加上驗(yàn)證碼,后臺(tái)收到請(qǐng)求后通過判斷驗(yàn)證碼可以防御CSRF。但這種方法對(duì)用戶不太友好。?
?
3. 在請(qǐng)求地址中添加token并驗(yàn)證?
?
?CSRF 攻擊之所以能夠成功,是因?yàn)楹诳涂梢酝耆珎卧煊脩舻恼?qǐng)求,該請(qǐng)求中所有的用戶驗(yàn)證信息都是存在于cookie中,因此黑客可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的cookie 來通過安全驗(yàn)證。要抵御 CSRF,關(guān)鍵在于在請(qǐng)求中放入黑客所不能偽造的信息,并且該信息不存在于 cookie 之中。可以在 HTTP 請(qǐng)求中以參數(shù)的形式加入一個(gè)隨機(jī)產(chǎn)生的 token,并在服務(wù)器端建立一個(gè)攔截器來驗(yàn)證這個(gè) token,如果請(qǐng)求中沒有token或者 token 內(nèi)容不正確,則認(rèn)為可能是 CSRF 攻擊而拒絕該請(qǐng)求。這種方法要比檢查 Referer 要安全一些,token 可以在用戶登陸后產(chǎn)生并放于session之中,然后在每次請(qǐng)求時(shí)把token 從 session 中拿出,與請(qǐng)求中的 token 進(jìn)行比對(duì),但這種方法的難點(diǎn)在于如何把 token 以參數(shù)的形式加入請(qǐng)求。 對(duì)于 GET 請(qǐng)求,token 將附在請(qǐng)求地址之后,這樣 URL 就變成 http://url?csrftoken=tokenvalue。 而對(duì)于 POST 請(qǐng)求來說,要在 form 的最后加上 <input type="hidden" name="csrftoken" value="tokenvalue"/>,這樣就把token以參數(shù)的形式加入請(qǐng)求了。?
?
4. 在HTTP 頭中自定義屬性并驗(yàn)證?
?
?這種方法也是使用 token 并進(jìn)行驗(yàn)證,和上一種方法不同的是,這里并不是把 token 以參數(shù)的形式置于 HTTP 請(qǐng)求之中,而是把它放到 HTTP 頭中自定義的屬性里。通過 XMLHttpRequest 這個(gè)類,可以一次性給所有該類請(qǐng)求加上 csrftoken 這個(gè) HTTP 頭屬性,并把 token 值放入其中。這樣解決了上種方法在請(qǐng)求中加入 token 的不便,同時(shí),通過 XMLHttpRequest 請(qǐng)求的地址不會(huì)被記錄到瀏覽器的地址欄,也不用擔(dān)心 token 會(huì)透過 Referer 泄露到其他網(wǎng)站中去。?
?
?
七、異常?
74. throw 和 throws 的區(qū)別??
throws是用來聲明一個(gè)方法可能拋出的所有異常信息,throws是將異常聲明但是不處理,而是將異常往上傳,誰調(diào)用我就交給誰處理。而throw則是指拋出的一個(gè)具體的異常類型。?
75. final、finally、finalize 有什么區(qū)別??
final可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表示該變量是一個(gè)常量不能被重新賦值。finally一般作用在try-catch代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來存放一些關(guān)閉資源的代碼。finalize是一個(gè)方法,屬于Object類的一個(gè)方法,而Object類是所有類的父類,該方法一般由垃圾回收器來調(diào)用,當(dāng)我們調(diào)用System的gc()方法的時(shí)候,由垃圾回收器調(diào)用finalize(),回收垃圾。?
76. try-catch-finally 中哪個(gè)部分可以省略??
答:catch 可以省略?
原因:?
更為嚴(yán)格的說法其實(shí)是:try只適合處理運(yùn)行時(shí)異常,try+catch適合處理運(yùn)行時(shí)異常+普通異常。也就是說,如果你只用try去處理普通異常卻不加以catch處理,編譯是通不過的,因?yàn)榫幾g器硬性規(guī)定,普通異常如果選擇捕獲,則必須用catch顯示聲明以便進(jìn)一步處理。而運(yùn)行時(shí)異常在編譯時(shí)沒有如此規(guī)定,所以catch可以省略,你加上catch編譯器也覺得無可厚非。?
理論上,編譯器看任何代碼都不順眼,都覺得可能有潛在的問題,所以你即使對(duì)所有代碼加上try,代碼在運(yùn)行期時(shí)也只不過是在正常運(yùn)行的基礎(chǔ)上加一層皮。但是你一旦對(duì)一段代碼加上try,就等于顯示地承諾編譯器,對(duì)這段代碼可能拋出的異常進(jìn)行捕獲而非向上拋出處理。如果是普通異常,編譯器要求必須用catch捕獲以便進(jìn)一步處理;如果運(yùn)行時(shí)異常,捕獲然后丟棄并且+finally掃尾處理,或者加上catch捕獲以便進(jìn)一步處理。?
至于加上finally,則是在不管有沒捕獲異常,都要進(jìn)行的“掃尾”處理。?
77. try-catch-finally 中,如果 catch 中 return 了,finally 還會(huì)執(zhí)行嗎??
答:會(huì)執(zhí)行,在 return 前執(zhí)行。?
代碼示例1:?
?
/*
?* java面試題--如果catch里面有return語句,finally里面的代碼還會(huì)執(zhí)行嗎?
?*/
public class FinallyDemo2 {
? ? public static void main(String[] args) {
? ? ? ? System.out.println(getInt());
? ? }
?
? ? public static int getInt() {
? ? ? ? int a = 10;
? ? ? ? try {
? ? ? ? ? ? System.out.println(a / 0);
? ? ? ? ? ? a = 20;
? ? ? ? } catch (ArithmeticException e) {
? ? ? ? ? ? a = 30;
? ? ? ? ? ? return a;
? ? ? ? ? ? /*
? ? ? ? ? ? ?* return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30;這個(gè)返回路徑就形成了
? ? ? ? ? ? ?* 但是呢,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容,a=40
? ? ? ? ? ? ?* 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了,而是常量30
? ? ? ? ? ? ?*/
? ? ? ? } finally {
? ? ? ? ? ? a = 40;
? ? ? ? }
?
//? ? ? return a;
? ? }
}?
執(zhí)行結(jié)果:30?
代碼示例2:?
?
package com.java_02;
?
/*
?* java面試題--如果catch里面有return語句,finally里面的代碼還會(huì)執(zhí)行嗎?
?*/
public class FinallyDemo2 {
? ? public static void main(String[] args) {
? ? ? ? System.out.println(getInt());
? ? }
?
? ? public static int getInt() {
? ? ? ? int a = 10;
? ? ? ? try {
? ? ? ? ? ? System.out.println(a / 0);
? ? ? ? ? ? a = 20;
? ? ? ? } catch (ArithmeticException e) {
? ? ? ? ? ? a = 30;
? ? ? ? ? ? return a;
? ? ? ? ? ? /*
? ? ? ? ? ? ?* return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30;這個(gè)返回路徑就形成了
? ? ? ? ? ? ?* 但是呢,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容,a=40
? ? ? ? ? ? ?* 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了,而是常量30
? ? ? ? ? ? ?*/
? ? ? ? } finally {
? ? ? ? ? ? a = 40;
? ? ? ? ? ? return a; //如果這樣,就又重新形成了一條返回路徑,由于只能通過1個(gè)return返回,所以這里直接返回40
? ? ? ? }
?
//? ? ? return a;
? ? }
}?
執(zhí)行結(jié)果:40?
78. 常見的異常類有哪些??
NullPointerException:當(dāng)應(yīng)用程序試圖訪問空對(duì)象時(shí),則拋出該異常。SQLException:提供關(guān)于數(shù)據(jù)庫訪問錯(cuò)誤或其他錯(cuò)誤信息的異常。IndexOutOfBoundsException:指示某排序索引(例如對(duì)數(shù)組、字符串或向量的排序)超出范圍時(shí)拋出。 NumberFormatException:當(dāng)應(yīng)用程序試圖將字符串轉(zhuǎn)換成一種數(shù)值類型,但該字符串不能轉(zhuǎn)換為適當(dāng)格式時(shí),拋出該異常。FileNotFoundException:當(dāng)試圖打開指定路徑名表示的文件失敗時(shí),拋出此異常。IOException:當(dāng)發(fā)生某種I/O異常時(shí),拋出此異常。此類是失敗或中斷的I/O操作生成的異常的通用類。ClassCastException:當(dāng)試圖將對(duì)象強(qiáng)制轉(zhuǎn)換為不是實(shí)例的子類時(shí),拋出該異常。ArrayStoreException:試圖將錯(cuò)誤類型的對(duì)象存儲(chǔ)到一個(gè)對(duì)象數(shù)組時(shí)拋出的異常。IllegalArgumentException:拋出的異常表明向方法傳遞了一個(gè)不合法或不正確的參數(shù)。ArithmeticException:當(dāng)出現(xiàn)異常的運(yùn)算條件時(shí),拋出此異常。例如,一個(gè)整數(shù)“除以零”時(shí),拋出此類的一個(gè)實(shí)例。 NegativeArraySizeException:如果應(yīng)用程序試圖創(chuàng)建大小為負(fù)的數(shù)組,則拋出該異常。NoSuchMethodException:無法找到某一特定方法時(shí),拋出該異常。SecurityException:由安全管理器拋出的異常,指示存在安全侵犯。UnsupportedOperationException:當(dāng)不支持請(qǐng)求的操作時(shí),拋出該異常。RuntimeExceptionRuntimeException:是那些可能在Java虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。
?
八、網(wǎng)絡(luò)?
79. http 響應(yīng)碼 301 和 302 代表的是什么?有什么區(qū)別??
答:301,302 都是HTTP狀態(tài)的編碼,都代表著某個(gè)URL發(fā)生了轉(zhuǎn)移。?
區(qū)別:??
301 redirect: 301 代表永久性轉(zhuǎn)移(Permanently Moved)。302 redirect: 302 代表暫時(shí)性轉(zhuǎn)移(Temporarily Moved )。?
80. forward 和 redirect 的區(qū)別??
Forward和Redirect代表了兩種請(qǐng)求轉(zhuǎn)發(fā)方式:直接轉(zhuǎn)發(fā)和間接轉(zhuǎn)發(fā)。?
直接轉(zhuǎn)發(fā)方式(Forward),客戶端和瀏覽器只發(fā)出一次請(qǐng)求,Servlet、HTML、JSP或其它信息資源,由第二個(gè)信息資源響應(yīng)該請(qǐng)求,在請(qǐng)求對(duì)象request中,保存的對(duì)象對(duì)于每個(gè)信息資源是共享的。?
間接轉(zhuǎn)發(fā)方式(Redirect)實(shí)際是兩次HTTP請(qǐng)求,服務(wù)器端在響應(yīng)第一次請(qǐng)求的時(shí)候,讓瀏覽器再向另外一個(gè)URL發(fā)出請(qǐng)求,從而達(dá)到轉(zhuǎn)發(fā)的目的。?
舉個(gè)通俗的例子:?
直接轉(zhuǎn)發(fā)就相當(dāng)于:“A找B借錢,B說沒有,B去找C借,借到借不到都會(huì)把消息傳遞給A”;?
間接轉(zhuǎn)發(fā)就相當(dāng)于:"A找B借錢,B說沒有,讓A去找C借"。?
81. 簡(jiǎn)述 tcp 和 udp的區(qū)別??
TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接。TCP提供可靠的服務(wù)。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付,即不保證可靠交付。Tcp通過校驗(yàn)和,重傳控制,序號(hào)標(biāo)識(shí),滑動(dòng)窗口、確認(rèn)應(yīng)答實(shí)現(xiàn)可靠傳輸。如丟包時(shí)的重發(fā)控制,還可以對(duì)次序亂掉的分包進(jìn)行順序控制。UDP具有較好的實(shí)時(shí)性,工作效率比TCP高,適用于對(duì)高速傳輸和實(shí)時(shí)性有較高的通信或廣播通信。每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信。TCP對(duì)系統(tǒng)資源要求較多,UDP對(duì)系統(tǒng)資源要求較少。
82. tcp 為什么要三次握手,兩次不行嗎?為什么??
為了實(shí)現(xiàn)可靠數(shù)據(jù)傳輸, TCP 協(xié)議的通信雙方, 都必須維護(hù)一個(gè)序列號(hào), 以標(biāo)識(shí)發(fā)送出去的數(shù)據(jù)包中, 哪些是已經(jīng)被對(duì)方收到的。 三次握手的過程即是通信雙方相互告知序列號(hào)起始值, 并確認(rèn)對(duì)方已經(jīng)收到了序列號(hào)起始值的必經(jīng)步驟。?
如果只是兩次握手, 至多只有連接發(fā)起方的起始序列號(hào)能被確認(rèn), 另一方選擇的序列號(hào)則得不到確認(rèn)。?
83. 說一下 tcp 粘包是怎么產(chǎn)生的??
①. 發(fā)送方產(chǎn)生粘包?
采用TCP協(xié)議傳輸數(shù)據(jù)的客戶端與服務(wù)器經(jīng)常是保持一個(gè)長(zhǎng)連接的狀態(tài)(一次連接發(fā)一次數(shù)據(jù)不存在粘包),雙方在連接不斷開的情況下,可以一直傳輸數(shù)據(jù);但當(dāng)發(fā)送的數(shù)據(jù)包過于的小時(shí),那么TCP協(xié)議默認(rèn)的會(huì)啟用Nagle算法,將這些較小的數(shù)據(jù)包進(jìn)行合并發(fā)送(緩沖區(qū)數(shù)據(jù)發(fā)送是一個(gè)堆壓的過程);這個(gè)合并過程就是在發(fā)送緩沖區(qū)中進(jìn)行的,也就是說數(shù)據(jù)發(fā)送出來它已經(jīng)是粘包的狀態(tài)了。?
?
②. 接收方產(chǎn)生粘包?
接收方采用TCP協(xié)議接收數(shù)據(jù)時(shí)的過程是這樣的:數(shù)據(jù)到底接收方,從網(wǎng)絡(luò)模型的下方傳遞至傳輸層,傳輸層的TCP協(xié)議處理是將其放置接收緩沖區(qū),然后由應(yīng)用層來主動(dòng)獲取(C語言用recv、read等函數(shù));這時(shí)會(huì)出現(xiàn)一個(gè)問題,就是我們?cè)诔绦蛑姓{(diào)用的讀取數(shù)據(jù)函數(shù)不能及時(shí)的把緩沖區(qū)中的數(shù)據(jù)拿出來,而下一個(gè)數(shù)據(jù)又到來并有一部分放入的緩沖區(qū)末尾,等我們讀取數(shù)據(jù)時(shí)就是一個(gè)粘包。(放數(shù)據(jù)的速度 > 應(yīng)用層拿數(shù)據(jù)速度)??
?
84. OSI 的七層模型都有哪些??
應(yīng)用層:網(wǎng)絡(luò)服務(wù)與最終用戶的一個(gè)接口。表示層:數(shù)據(jù)的表示、安全、壓縮。會(huì)話層:建立、管理、終止會(huì)話。傳輸層:定義傳輸數(shù)據(jù)的協(xié)議端口號(hào),以及流控和差錯(cuò)校驗(yàn)。網(wǎng)絡(luò)層:進(jìn)行邏輯地址尋址,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇。數(shù)據(jù)鏈路層:建立邏輯連接、進(jìn)行硬件地址尋址、差錯(cuò)校驗(yàn)等功能。物理層:建立、維護(hù)、斷開物理連接。
85. get 和 post 請(qǐng)求有哪些區(qū)別??
GET在瀏覽器回退時(shí)是無害的,而POST會(huì)再次提交請(qǐng)求。GET產(chǎn)生的URL地址可以被Bookmark,而POST不可以。GET請(qǐng)求會(huì)被瀏覽器主動(dòng)cache,而POST不會(huì),除非手動(dòng)設(shè)置。GET請(qǐng)求只能進(jìn)行url編碼,而POST支持多種編碼方式。GET請(qǐng)求參數(shù)會(huì)被完整保留在瀏覽器歷史記錄里,而POST中的參數(shù)不會(huì)被保留。GET請(qǐng)求在URL中傳送的參數(shù)是有長(zhǎng)度限制的,而POST么有。對(duì)參數(shù)的數(shù)據(jù)類型,GET只接受ASCII字符,而POST沒有限制。GET比POST更不安全,因?yàn)閰?shù)直接暴露在URL上,所以不能用來傳遞敏感信息。GET參數(shù)通過URL傳遞,POST放在Request body中。
86. 如何實(shí)現(xiàn)跨域??
方式一:圖片ping或script標(biāo)簽跨域?
圖片ping常用于跟蹤用戶點(diǎn)擊頁面或動(dòng)態(tài)廣告曝光次數(shù)。 script標(biāo)簽可以得到從其他來源數(shù)據(jù),這也是JSONP依賴的根據(jù)。??
方式二:JSONP跨域?
JSONP(JSON with Padding)是數(shù)據(jù)格式JSON的一種“使用模式”,可以讓網(wǎng)頁從別的網(wǎng)域要數(shù)據(jù)。根據(jù) XmlHttpRequest 對(duì)象受到同源策略的影響,而利用 <script>元素的這個(gè)開放策略,網(wǎng)頁可以得到從其他來源動(dòng)態(tài)產(chǎn)生的JSON數(shù)據(jù),而這種使用模式就是所謂的 JSONP。用JSONP抓到的數(shù)據(jù)并不是JSON,而是任意的JavaScript,用 JavaScript解釋器運(yùn)行而不是用JSON解析器解析。所有,通過Chrome查看所有JSONP發(fā)送的Get請(qǐng)求都是js類型,而非XHR。??
?
缺點(diǎn):?
只能使用Get請(qǐng)求不能注冊(cè)success、error等事件監(jiān)聽函數(shù),不能很容易的確定JSONP請(qǐng)求是否失敗JSONP是從其他域中加載代碼執(zhí)行,容易受到跨站請(qǐng)求偽造的攻擊,其安全性無法確保
方式三:CORS?
Cross-Origin Resource Sharing(CORS)跨域資源共享是一份瀏覽器技術(shù)的規(guī)范,提供了 Web 服務(wù)從不同域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,確保安全的跨域數(shù)據(jù)傳輸。現(xiàn)代瀏覽器使用CORS在API容器如XMLHttpRequest來減少HTTP請(qǐng)求的風(fēng)險(xiǎn)來源。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。服務(wù)器一般需要增加如下響應(yīng)頭的一種或幾種:?
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400?
跨域請(qǐng)求默認(rèn)不會(huì)攜帶Cookie信息,如果需要攜帶,請(qǐng)配置下述參數(shù):?
"Access-Control-Allow-Credentials": true
// Ajax設(shè)置
"withCredentials": true?
方式四:window.name+iframe?
window.name通過在iframe(一般動(dòng)態(tài)創(chuàng)建i)中加載跨域HTML文件來起作用。然后,HTML文件將傳遞給請(qǐng)求者的字符串內(nèi)容賦值給window.name。然后,請(qǐng)求者可以檢索window.name值作為響應(yīng)。?
iframe標(biāo)簽的跨域能力;window.name屬性值在文檔刷新后依舊存在的能力(且最大允許2M左右)。
每個(gè)iframe都有包裹它的window,而這個(gè)window是top window的子窗口。contentWindow屬性返回<iframe>元素的Window對(duì)象。你可以使用這個(gè)Window對(duì)象來訪問iframe的文檔及其內(nèi)部DOM。?
<!--?
?下述用端口?
?10000表示:domainA
?10001表示:domainB
-->
?
<!-- localhost:10000 -->
<script>
? var iframe = document.createElement('iframe');
? iframe.style.display = 'none'; // 隱藏
?
? var state = 0; // 防止頁面無限刷新
? iframe.onload = function() {
? ? ? if(state === 1) {
? ? ? ? ? console.log(JSON.parse(iframe.contentWindow.name));
? ? ? ? ? // 清除創(chuàng)建的iframe
? ? ? ? ? iframe.contentWindow.document.write('');
? ? ? ? ? iframe.contentWindow.close();
? ? ? ? ? document.body.removeChild(iframe);
? ? ? } else if(state === 0) {
? ? ? ? ? state = 1;
? ? ? ? ? // 加載完成,指向當(dāng)前域,防止錯(cuò)誤(proxy.html為空白頁面)
? ? ? ? ? // Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame.
? ? ? ? ? iframe.contentWindow.location = 'http://localhost:10000/proxy.html';
? ? ? }
? };
?
? iframe.src = 'http://localhost:10001';
? document.body.appendChild(iframe);
</script>
?
<!-- localhost:10001 -->
<!DOCTYPE html>
...
<script>
? window.name = JSON.stringify({a: 1, b: 2});
</script>
</html>
?
方式五:window.postMessage()?
HTML5新特性,可以用來向其他所有的 window 對(duì)象發(fā)送消息。需要注意的是我們必須要保證所有的腳本執(zhí)行完才發(fā)送 MessageEvent,如果在函數(shù)執(zhí)行的過程中調(diào)用了它,就會(huì)讓后面的函數(shù)超時(shí)無法執(zhí)行。?
下述代碼實(shí)現(xiàn)了跨域存儲(chǔ)localStorage?
<!--?
?下述用端口?
?10000表示:domainA
?10001表示:domainB
-->
?
<!-- localhost:10000 -->
<iframe src="http://localhost:10001/msg.html" name="myPostMessage" style="display:none;">
</iframe>
?
<script>
? function main() {
? ? ? LSsetItem('test', 'Test: ' + new Date());
? ? ? LSgetItem('test', function(value) {
? ? ? ? ? console.log('value: ' + value);
? ? ? });
? ? ? LSremoveItem('test');
? }
?
? var callbacks = {};
? window.addEventListener('message', function(event) {
? ? ? if (event.source === frames['myPostMessage']) {
? ? ? ? ? console.log(event)
? ? ? ? ? var data = /^#localStorage#(\d+)(null)?#([\S\s]*)/.exec(event.data);
? ? ? ? ? if (data) {
? ? ? ? ? ? ? if (callbacks[data[1]]) {
? ? ? ? ? ? ? ? ? callbacks[data[1]](data[2] === 'null' ? null : data[3]);
? ? ? ? ? ? ? }
? ? ? ? ? ? ? delete callbacks[data[1]];
? ? ? ? ? }
? ? ? }
? }, false);
?
? var domain = '*';
? // 增加
? function LSsetItem(key, value) {
? ? ? var obj = {
? ? ? ? ? setItem: key,
? ? ? ? ? value: value
? ? ? };
? ? ? frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
? }
? // 獲取
? function LSgetItem(key, callback) {
? ? ? var identifier = new Date().getTime();
? ? ? var obj = {
? ? ? ? ? identifier: identifier,
? ? ? ? ? getItem: key
? ? ? };
? ? ? callbacks[identifier] = callback;
? ? ? frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
? }
? // 刪除
? function LSremoveItem(key) {
? ? ? var obj = {
? ? ? ? ? removeItem: key
? ? ? };
? ? ? frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
? }
</script>
?
<!-- localhost:10001 -->
<script>
? window.addEventListener('message', function(event) {
? ? console.log('Receiver debugging', event);
? ? if (event.origin == 'http://localhost:10000') {
? ? ? var data = JSON.parse(event.data);
? ? ? if ('setItem' in data) {
? ? ? ? localStorage.setItem(data.setItem, data.value);
? ? ? } else if ('getItem' in data) {
? ? ? ? var gotItem = localStorage.getItem(data.getItem);
? ? ? ? event.source.postMessage(
? ? ? ? ? '#localStorage#' + data.identifier +
? ? ? ? ? (gotItem === null ? 'null#' : '#' + gotItem),
? ? ? ? ? event.origin
? ? ? ? );
? ? ? } else if ('removeItem' in data) {
? ? ? ? localStorage.removeItem(data.removeItem);
? ? ? }
? ? }
? }, false);
</script>?
注意Safari一下,會(huì)報(bào)錯(cuò):?
?
?Blocked a frame with origin “http://localhost:10001” from accessing a frame with origin “http://localhost:10000“. Protocols, domains, and ports must match.?
?
避免該錯(cuò)誤,可以在Safari瀏覽器中勾選開發(fā)菜單==>停用跨域限制。或者只能使用服務(wù)器端轉(zhuǎn)存的方式實(shí)現(xiàn),因?yàn)镾afari瀏覽器默認(rèn)只支持CORS跨域請(qǐng)求。?
方式六:修改document.domain跨子域?
前提條件:這兩個(gè)域名必須屬于同一個(gè)基礎(chǔ)域名!而且所用的協(xié)議,端口都要一致,否則無法利用document.domain進(jìn)行跨域,所以只能跨子域?
在根域范圍內(nèi),允許把domain屬性的值設(shè)置為它的上一級(jí)域。例如,在”aaa.xxx.com”域內(nèi),可以把domain設(shè)置為 “xxx.com” 但不能設(shè)置為 “xxx.org” 或者”com”。?
?
?現(xiàn)在存在兩個(gè)域名aaa.xxx.com和bbb.xxx.com。在aaa下嵌入bbb的頁面,由于其document.name不一致,無法在aaa下操作bbb的js。可以在aaa和bbb下通過js將document.name = 'xxx.com';設(shè)置一致,來達(dá)到互相訪問的作用。?
?
方式七:WebSocket?
WebSocket protocol 是HTML5一種新的協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,同時(shí)允許跨域通訊,是server push技術(shù)的一種很棒的實(shí)現(xiàn)。相關(guān)文章,請(qǐng)查看:WebSocket、WebSocket-SockJS?
需要注意:WebSocket對(duì)象不支持DOM 2級(jí)事件偵聽器,必須使用DOM 0級(jí)語法分別定義各個(gè)事件。?
方式八:代理?
同源策略是針對(duì)瀏覽器端進(jìn)行的限制,可以通過服務(wù)器端來解決該問題?
DomainA客戶端(瀏覽器) ==> DomainA服務(wù)器 ==> DomainB服務(wù)器 ==> DomainA客戶端(瀏覽器)?
來源:blog.csdn.net/ligang2585116/article/details/73072868?
87.說一下 JSONP 實(shí)現(xiàn)原理??
jsonp 即 json+padding,動(dòng)態(tài)創(chuàng)建script標(biāo)簽,利用script標(biāo)簽的src屬性可以獲取任何域下的js腳本,通過這個(gè)特性(也可以說漏洞),服務(wù)器端不在返貨json格式,而是返回一段調(diào)用某個(gè)函數(shù)的js代碼,在src中進(jìn)行了調(diào)用,這樣實(shí)現(xiàn)了跨域。?
?
九、設(shè)計(jì)模式?
88. 說一下你熟悉的設(shè)計(jì)模式??
參考:常用的設(shè)計(jì)模式匯總,超詳細(xì)!?
89. 簡(jiǎn)單工廠和抽象工廠有什么區(qū)別??
簡(jiǎn)單工廠模式:?
這個(gè)模式本身很簡(jiǎn)單而且使用在業(yè)務(wù)較簡(jiǎn)單的情況下。一般用于小項(xiàng)目或者具體產(chǎn)品很少擴(kuò)展的情況(這樣工廠類才不用經(jīng)常更改)。?
它由三種角色組成:?
工廠類角色:這是本模式的核心,含有一定的商業(yè)邏輯和判斷邏輯,根據(jù)邏輯不同,產(chǎn)生具體的工廠產(chǎn)品。如例子中的Driver類。抽象產(chǎn)品角色:它一般是具體產(chǎn)品繼承的父類或者實(shí)現(xiàn)的接口。由接口或者抽象類來實(shí)現(xiàn)。如例中的Car接口。具體產(chǎn)品角色:工廠類所創(chuàng)建的對(duì)象就是此角色的實(shí)例。在java中由一個(gè)具體類實(shí)現(xiàn),如例子中的Benz、Bmw類。
來用類圖來清晰的表示下的它們之間的關(guān)系:?
抽象工廠模式:?
先來認(rèn)識(shí)下什么是產(chǎn)品族: 位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。?
?
圖中的BmwCar和BenzCar就是兩個(gè)產(chǎn)品樹(產(chǎn)品層次結(jié)構(gòu));而如圖所示的BenzSportsCar和BmwSportsCar就是一個(gè)產(chǎn)品族。他們都可以放到跑車家族中,因此功能有所關(guān)聯(lián)。同理BmwBussinessCar和BenzBusinessCar也是一個(gè)產(chǎn)品族。?
可以這么說,它和工廠方法模式的區(qū)別就在于需要?jiǎng)?chuàng)建對(duì)象的復(fù)雜程度上。而且抽象工廠模式是三個(gè)里面最為抽象、最具一般性的。抽象工廠模式的用意為:給客戶端提供一個(gè)接口,可以創(chuàng)建多個(gè)產(chǎn)品族中的產(chǎn)品對(duì)象。?
而且使用抽象工廠模式還要滿足一下條件:?
系統(tǒng)中有多個(gè)產(chǎn)品族,而系統(tǒng)一次只可能消費(fèi)其中一族產(chǎn)品同屬于同一個(gè)產(chǎn)品族的產(chǎn)品以其使用。
來看看抽象工廠模式的各個(gè)角色(和工廠方法的如出一轍):?
抽象工廠角色: 這是工廠方法模式的核心,它與應(yīng)用程序無關(guān)。是具體工廠角色必須實(shí)現(xiàn)的接口或者必須繼承的父類。在java中它由抽象類或者接口來實(shí)現(xiàn)。具體工廠角色:它含有和具體業(yè)務(wù)邏輯有關(guān)的代碼。由應(yīng)用程序調(diào)用以創(chuàng)建對(duì)應(yīng)的具體產(chǎn)品的對(duì)象。在java中它由具體的類來實(shí)現(xiàn)。抽象產(chǎn)品角色:它是具體產(chǎn)品繼承的父類或者是實(shí)現(xiàn)的接口。在java中一般有抽象類或者接口來實(shí)現(xiàn)。具體產(chǎn)品角色:具體工廠角色所創(chuàng)建的對(duì)象就是此角色的實(shí)例。在java中由具體的類來實(shí)現(xiàn)。
?
十、Spring / Spring MVC?
90. 為什么要使用 spring??
1.簡(jiǎn)介?
目的:解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性功能:使用基本的JavaBean代替EJB,并提供了更多的企業(yè)應(yīng)用功能范圍:任何Java應(yīng)用
簡(jiǎn)單來說,Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架。?
2.輕量 ?
從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個(gè)大小只有1MB多的JAR文件里發(fā)布。并且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應(yīng)用中的對(duì)象不依賴于Spring的特定類。?
3.控制反轉(zhuǎn) ?
Spring通過一種稱作控制反轉(zhuǎn)(IoC)的技術(shù)促進(jìn)了松耦合。當(dāng)應(yīng)用了IoC,一個(gè)對(duì)象依賴的其它對(duì)象會(huì)通過被動(dòng)的方式傳遞進(jìn)來,而不是這個(gè)對(duì)象自己創(chuàng)建或者查找依賴對(duì)象。你可以認(rèn)為IoC與JNDI相反——不是對(duì)象從容器中查找依賴,而是容器在對(duì)象初始化時(shí)不等對(duì)象請(qǐng)求就主動(dòng)將依賴傳遞給它。?
4.面向切面 ?
Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。?
5.容器?
Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器,你可以配置你的每個(gè)bean如何被創(chuàng)建——基于一個(gè)可配置原型(prototype),你的bean可以創(chuàng)建一個(gè)單獨(dú)的實(shí)例或者每次需要時(shí)都生成一個(gè)新的實(shí)例——以及它們是如何相互關(guān)聯(lián)的。然而,Spring不應(yīng)該被混同于傳統(tǒng)的重量級(jí)的EJB容器,它們經(jīng)常是龐大與笨重的,難以使用。?
6.框架?
Spring可以將簡(jiǎn)單的組件配置、組合成為復(fù)雜的應(yīng)用。在Spring中,應(yīng)用對(duì)象被聲明式地組合,典型地是在一個(gè)XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等等),將應(yīng)用邏輯的開發(fā)留給了你。?
所有Spring的這些特征使你能夠編寫更干凈、更可管理、并且更易于測(cè)試的代碼。它們也為Spring中的各種模塊提供了基礎(chǔ)支持。?
91. 解釋一下什么是 aop??
AOP(Aspect-Oriented Programming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向?qū)ο缶幊?#xff09;的補(bǔ)充和完善。OOP引入封裝、繼承和多態(tài)性等概念來建立一種對(duì)象層次結(jié)構(gòu),用以模擬公共行為的一個(gè)集合。當(dāng)我們需要為分散的對(duì)象引入公共行為的時(shí)候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系。例如日志功能。日志代碼往往水平地散布在所有對(duì)象層次中,而與它所散布到的對(duì)象的核心功能毫無關(guān)系。對(duì)于其他類型的代碼,如安全性、異常處理和透明的持續(xù)性也是如此。這種散布在各處的無關(guān)的代碼被稱為橫切(cross-cutting)代碼,在OOP設(shè)計(jì)中,它導(dǎo)致了大量代碼的重復(fù),而不利于各個(gè)模塊的重用。?
而AOP技術(shù)則恰恰相反,它利用一種稱為“橫切”的技術(shù),剖解開封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類的公共行為封裝到一個(gè)可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡(jiǎn)單地說,就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。AOP代表的是一個(gè)橫向的關(guān)系,如果說“對(duì)象”是一個(gè)空心的圓柱體,其中封裝的是對(duì)象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內(nèi)部的消息。而剖開的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開的切面復(fù)原,不留痕跡。?
使用“橫切”技術(shù),AOP把軟件系統(tǒng)分為兩個(gè)部分:核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)。業(yè)務(wù)處理的主要流程是核心關(guān)注點(diǎn),與之關(guān)系不大的部分是橫切關(guān)注點(diǎn)。橫切關(guān)注點(diǎn)的一個(gè)特點(diǎn)是,他們經(jīng)常發(fā)生在核心關(guān)注點(diǎn)的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。Aop 的作用在于分離系統(tǒng)中的各種關(guān)注點(diǎn),將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離開來。正如Avanade公司的高級(jí)方案構(gòu)架師Adam Magee所說,AOP的核心思想就是“將應(yīng)用程序中的商業(yè)邏輯同對(duì)其提供支持的通用服務(wù)進(jìn)行分離。”?
92. 解釋一下什么是 ioc??
IOC是Inversion of Control的縮寫,多數(shù)書籍翻譯成“控制反轉(zhuǎn)”。?
1996年,Michael Mattson在一篇有關(guān)探討面向?qū)ο罂蚣艿奈恼轮?#xff0c;首先提出了IOC 這個(gè)概念。對(duì)于面向?qū)ο笤O(shè)計(jì)及編程的基本思想,前面我們已經(jīng)講了很多了,不再贅述,簡(jiǎn)單來說就是把復(fù)雜系統(tǒng)分解成相互合作的對(duì)象,這些對(duì)象類通過封裝以后,內(nèi)部實(shí)現(xiàn)對(duì)外部是透明的,從而降低了解決問題的復(fù)雜度,而且可以靈活地被重用和擴(kuò)展。?
IOC理論提出的觀點(diǎn)大體是這樣的:借助于“第三方”實(shí)現(xiàn)具有依賴關(guān)系的對(duì)象之間的解耦。如下圖:?
?
大家看到了吧,由于引進(jìn)了中間位置的“第三方”,也就是IOC容器,使得A、B、C、D這4個(gè)對(duì)象沒有了耦合關(guān)系,齒輪之間的傳動(dòng)全部依靠“第三方”了,全部對(duì)象的控制權(quán)全部上繳給“第三方”IOC容器,所以,IOC容器成了整個(gè)系統(tǒng)的關(guān)鍵核心,它起到了一種類似“粘合劑”的作用,把系統(tǒng)中的所有對(duì)象粘合在一起發(fā)揮作用,如果沒有這個(gè)“粘合劑”,對(duì)象與對(duì)象之間會(huì)彼此失去聯(lián)系,這就是有人把IOC容器比喻成“粘合劑”的由來。?
我們?cè)賮碜鰝€(gè)試驗(yàn):把上圖中間的IOC容器拿掉,然后再來看看這套系統(tǒng):?
?
我們現(xiàn)在看到的畫面,就是我們要實(shí)現(xiàn)整個(gè)系統(tǒng)所需要完成的全部?jī)?nèi)容。這時(shí)候,A、B、C、D這4個(gè)對(duì)象之間已經(jīng)沒有了耦合關(guān)系,彼此毫無聯(lián)系,這樣的話,當(dāng)你在實(shí)現(xiàn)A的時(shí)候,根本無須再去考慮B、C和D了,對(duì)象之間的依賴關(guān)系已經(jīng)降低到了最低程度。所以,如果真能實(shí)現(xiàn)IOC容器,對(duì)于系統(tǒng)開發(fā)而言,這將是一件多么美好的事情,參與開發(fā)的每一成員只要實(shí)現(xiàn)自己的類就可以了,跟別人沒有任何關(guān)系!?
我們?cè)賮砜纯?#xff0c;控制反轉(zhuǎn)(IOC)到底為什么要起這么個(gè)名字?我們來對(duì)比一下:?
軟件系統(tǒng)在沒有引入IOC容器之前,如圖1所示,對(duì)象A依賴于對(duì)象B,那么對(duì)象A在初始化或者運(yùn)行到某一點(diǎn)的時(shí)候,自己必須主動(dòng)去創(chuàng)建對(duì)象B或者使用已經(jīng)創(chuàng)建的對(duì)象B。無論是創(chuàng)建還是使用對(duì)象B,控制權(quán)都在自己手上。?
軟件系統(tǒng)在引入IOC容器之后,這種情形就完全改變了,如圖3所示,由于IOC容器的加入,對(duì)象A與對(duì)象B之間失去了直接聯(lián)系,所以,當(dāng)對(duì)象A運(yùn)行到需要對(duì)象B的時(shí)候,IOC容器會(huì)主動(dòng)創(chuàng)建一個(gè)對(duì)象B注入到對(duì)象A需要的地方。?
通過前后的對(duì)比,我們不難看出來:對(duì)象A獲得依賴對(duì)象B的過程,由主動(dòng)行為變?yōu)榱吮粍?dòng)行為,控制權(quán)顛倒過來了,這就是“控制反轉(zhuǎn)”這個(gè)名稱的由來。?
93. spring 有哪些主要模塊??
Spring框架至今已集成了20多個(gè)模塊。這些模塊主要被分如下圖所示的核心容器、數(shù)據(jù)訪問/集成,、Web、AOP(面向切面編程)、工具、消息和測(cè)試模塊。?
?
更多信息:howtodoinjava.com/java-spring-framework-tutorials/?
94. spring 常用的注入方式有哪些??
Spring通過DI(依賴注入)實(shí)現(xiàn)IOC(控制反轉(zhuǎn)),常用的注入方式主要有三種:?
構(gòu)造方法注入setter注入基于注解的注入
95. spring 中的 bean 是線程安全的嗎??
Spring容器中的Bean是否線程安全,容器本身并沒有提供Bean的線程安全策略,因此可以說spring容器中的Bean本身不具備線程安全的特性,但是具體還是要結(jié)合具體scope的Bean去研究。?
96. spring 支持幾種 bean 的作用域??
當(dāng)通過spring容器創(chuàng)建一個(gè)Bean實(shí)例時(shí),不僅可以完成Bean實(shí)例的實(shí)例化,還可以為Bean指定特定的作用域。Spring支持如下5種作用域:?
singleton:單例模式,在整個(gè)Spring IoC容器中,使用singleton定義的Bean將只有一個(gè)實(shí)例prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時(shí),都將產(chǎn)生一個(gè)新的Bean實(shí)例request:對(duì)于每次HTTP請(qǐng)求,使用request定義的Bean都將產(chǎn)生一個(gè)新實(shí)例,即每次HTTP請(qǐng)求將會(huì)產(chǎn)生不同的Bean實(shí)例。只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效session:對(duì)于每次HTTP Session,使用session定義的Bean豆?jié){產(chǎn)生一個(gè)新實(shí)例。同樣只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效globalsession:每個(gè)全局的HTTP Session,使用session定義的Bean都將產(chǎn)生一個(gè)新實(shí)例。典型情況下,僅在使用portlet context的時(shí)候有效。同樣只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效
其中比較常用的是singleton和prototype兩種作用域。對(duì)于singleton作用域的Bean,每次請(qǐng)求該Bean都將獲得相同的實(shí)例。容器負(fù)責(zé)跟蹤Bean實(shí)例的狀態(tài),負(fù)責(zé)維護(hù)Bean實(shí)例的生命周期行為;如果一個(gè)Bean被設(shè)置成prototype作用域,程序每次請(qǐng)求該id的Bean,Spring都會(huì)新建一個(gè)Bean實(shí)例,然后返回給程序。在這種情況下,Spring容器僅僅使用new 關(guān)鍵字創(chuàng)建Bean實(shí)例,一旦創(chuàng)建成功,容器不在跟蹤實(shí)例,也不會(huì)維護(hù)Bean實(shí)例的狀態(tài)。?
如果不指定Bean的作用域,Spring默認(rèn)使用singleton作用域。Java在創(chuàng)建Java實(shí)例時(shí),需要進(jìn)行內(nèi)存申請(qǐng);銷毀實(shí)例時(shí),需要完成垃圾回收,這些工作都會(huì)導(dǎo)致系統(tǒng)開銷的增加。因此,prototype作用域Bean的創(chuàng)建、銷毀代價(jià)比較大。而singleton作用域的Bean實(shí)例一旦創(chuàng)建成功,可以重復(fù)使用。因此,除非必要,否則盡量避免將Bean被設(shè)置成prototype作用域。?
97. spring 自動(dòng)裝配 bean 有哪些方式??
Spring容器負(fù)責(zé)創(chuàng)建應(yīng)用程序中的bean同時(shí)通過ID來協(xié)調(diào)這些對(duì)象之間的關(guān)系。作為開發(fā)人員,我們需要告訴Spring要?jiǎng)?chuàng)建哪些bean并且如何將其裝配到一起。?
spring中bean裝配有兩種方式:?
隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配在java代碼或者XML中進(jìn)行顯示配置
當(dāng)然這些方式也可以配合使用。?
98. spring 事務(wù)實(shí)現(xiàn)方式有哪些??
編程式事務(wù)管理對(duì)基于 POJO 的應(yīng)用來說是唯一選擇。我們需要在代碼中調(diào)用beginTransaction()、commit()、rollback()等事務(wù)管理相關(guān)的方法,這就是編程式事務(wù)管理。基于 TransactionProxyFactoryBean 的聲明式事務(wù)管理基于 @Transactional 的聲明式事務(wù)管理基于 Aspectj AOP 配置事務(wù)
99. 說一下 spring 的事務(wù)隔離??
事務(wù)隔離級(jí)別指的是一個(gè)事務(wù)對(duì)數(shù)據(jù)的修改與另一個(gè)并行的事務(wù)的隔離程度,當(dāng)多個(gè)事務(wù)同時(shí)訪問相同數(shù)據(jù)時(shí),如果沒有采取必要的隔離機(jī)制,就可能發(fā)生以下問題:?
臟讀:一個(gè)事務(wù)讀到另一個(gè)事務(wù)未提交的更新數(shù)據(jù)。幻讀:例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,比如這種修改涉及到表中的“全部數(shù)據(jù)行”。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入“一行新數(shù)據(jù)”。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還存在沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣。不可重復(fù)讀:比方說在同一個(gè)事務(wù)中先后執(zhí)行兩條一模一樣的select語句,期間在此次事務(wù)中沒有執(zhí)行過任何DDL語句,但先后得到的結(jié)果不一致,這就是不可重復(fù)讀。
100. 說一下 spring mvc 運(yùn)行流程??
Spring MVC運(yùn)行流程圖:?
?
Spring運(yùn)行流程描述:?
1. 用戶向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求被Spring 前端控制Servelt DispatcherServlet捕獲;?
2. DispatcherServlet對(duì)請(qǐng)求URL進(jìn)行解析,得到請(qǐng)求資源標(biāo)識(shí)符(URI)。然后根據(jù)該URI,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對(duì)象(包括Handler對(duì)象以及Handler對(duì)象對(duì)應(yīng)的攔截器),最后以HandlerExecutionChain對(duì)象的形式返回;?
3. DispatcherServlet 根據(jù)獲得的Handler,選擇一個(gè)合適的HandlerAdapter;(附注:如果成功獲得HandlerAdapter后,此時(shí)將開始執(zhí)行攔截器的preHandler(...)方法)?
4.? 提取Request中的模型數(shù)據(jù),填充Handler入?yún)?#xff0c;開始執(zhí)行Handler(Controller)。 在填充Handler的入?yún)⑦^程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:?
HttpMessageConveter: 將請(qǐng)求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對(duì)象,將對(duì)象轉(zhuǎn)換為指定的響應(yīng)信息數(shù)據(jù)轉(zhuǎn)換:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer、Double等數(shù)據(jù)根式化:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)格式化。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等數(shù)據(jù)驗(yàn)證: 驗(yàn)證數(shù)據(jù)的有效性(長(zhǎng)度、格式等),驗(yàn)證結(jié)果存儲(chǔ)到BindingResult或Error中
5.? Handler執(zhí)行完成后,向DispatcherServlet 返回一個(gè)ModelAndView對(duì)象;?
6.? 根據(jù)返回的ModelAndView,選擇一個(gè)適合的ViewResolver(必須是已經(jīng)注冊(cè)到Spring容器中的ViewResolver)返回給DispatcherServlet ;?
7. ViewResolver 結(jié)合Model和View,來渲染視圖;?
8. 將渲染結(jié)果返回給客戶端。?
101. spring mvc 有哪些組件??
Spring MVC的核心組件:?
DispatcherServlet:中央控制器,把請(qǐng)求給轉(zhuǎn)發(fā)到具體的控制類Controller:具體處理請(qǐng)求的控制器HandlerMapping:映射處理器,負(fù)責(zé)映射中央處理器轉(zhuǎn)發(fā)給controller時(shí)的映射策略ModelAndView:服務(wù)層返回的數(shù)據(jù)和視圖層的封裝類ViewResolver:視圖解析器,解析具體的視圖Interceptors :攔截器,負(fù)責(zé)攔截我們定義的請(qǐng)求然后做處理工作
102. @RequestMapping 的作用是什么??
RequestMapping是一個(gè)用來處理請(qǐng)求地址映射的注解,可用于類或方法上。用于類上,表示類中的所有響應(yīng)請(qǐng)求的方法都是以該地址作為父路徑。?
RequestMapping注解有六個(gè)屬性,下面我們把她分成三類進(jìn)行說明。?
value, method:?
value:指定請(qǐng)求的實(shí)際地址,指定的地址可以是URI Template 模式(后面將會(huì)說明);method:指定請(qǐng)求的method類型, GET、POST、PUT、DELETE等;
consumes,produces?
consumes:指定處理請(qǐng)求的提交內(nèi)容類型(Content-Type),例如application/json, text/html;produces:指定返回的內(nèi)容類型,僅當(dāng)request請(qǐng)求頭中的(Accept)類型中包含該指定類型才返回;
params,headers?
params: 指定request中必須包含某些參數(shù)值是,才讓該方法處理。headers:指定request中必須包含某些指定的header值,才能讓該方法處理請(qǐng)求。
103. @Autowired 的作用是什么??
《@Autowired用法詳解》?
?
十一、Spring Boot / Spring Cloud?
104. 什么是 spring boot??
在Spring框架這個(gè)大家族中,產(chǎn)生了很多衍生框架,比如 Spring、SpringMvc框架等,Spring的核心內(nèi)容在于控制反轉(zhuǎn)(IOC)和依賴注入(DI),所謂控制反轉(zhuǎn)并非是一種技術(shù),而是一種思想,在操作方面是指在spring配置文件中創(chuàng)建<bean>,依賴注入即為由spring容器為應(yīng)用程序的某個(gè)對(duì)象提供資源,比如 引用對(duì)象、常量數(shù)據(jù)等。?
SpringBoot是一個(gè)框架,一種全新的編程規(guī)范,他的產(chǎn)生簡(jiǎn)化了框架的使用,所謂簡(jiǎn)化是指簡(jiǎn)化了Spring眾多框架中所需的大量且繁瑣的配置文件,所以 SpringBoot是一個(gè)服務(wù)于框架的框架,服務(wù)范圍是簡(jiǎn)化配置文件。?
105. 為什么要用 spring boot??
Spring Boot使編碼變簡(jiǎn)單Spring Boot使配置變簡(jiǎn)單Spring Boot使部署變簡(jiǎn)單Spring Boot使監(jiān)控變簡(jiǎn)單Spring的不足
106. spring boot 核心配置文件是什么??
Spring Boot提供了兩種常用的配置文件:?
properties文件yml文件
107. spring boot 配置文件有哪幾種類型?它們有什么區(qū)別??
Spring Boot提供了兩種常用的配置文件,分別是properties文件和yml文件。相對(duì)于properties文件而言,yml文件更年輕,也有很多的坑。可謂成也蕭何敗蕭何,yml通過空格來確定層級(jí)關(guān)系,使配置文件結(jié)構(gòu)跟清晰,但也會(huì)因?yàn)槲⒉蛔愕赖目崭穸茐牧藢蛹?jí)關(guān)系。?
108. spring boot 有哪些方式可以實(shí)現(xiàn)熱部署??
SpringBoot熱部署實(shí)現(xiàn)有兩種方式:?
①. 使用spring loaded?
在項(xiàng)目中添加如下代碼:?
<build>
? ? ? ? <plugins>
? ? ? ? ? ? <plugin>
? ? ? ? ? ? ? ? <!-- springBoot編譯插件-->
? ? ? ? ? ? ? ? <groupId>org.springframework.boot</groupId>
? ? ? ? ? ? ? ? <artifactId>spring-boot-maven-plugin</artifactId>
? ? ? ? ? ? ? ? <dependencies>
? ? ? ? ? ? ? ? ? ? <!-- spring熱部署 -->
? ? ? ? ? ? ? ? ? ? <!-- 該依賴在此處下載不下來,可以放置在build標(biāo)簽外部下載完成后再粘貼進(jìn)plugin中 -->
? ? ? ? ? ? ? ? ? ? <dependency>
? ? ? ? ? ? ? ? ? ? ? ? <groupId>org.springframework</groupId>
? ? ? ? ? ? ? ? ? ? ? ? <artifactId>springloaded</artifactId>
? ? ? ? ? ? ? ? ? ? ? ? <version>1.2.6.RELEASE</version>
? ? ? ? ? ? ? ? ? ? </dependency>
? ? ? ? ? ? ? ? </dependencies>
? ? ? ? ? ? </plugin>
? ? ? ? </plugins>
? ? </build>?
添加完畢后需要使用mvn指令運(yùn)行:?
首先找到IDEA中的Edit configurations ,然后進(jìn)行如下操作:(點(diǎn)擊左上角的"+",然后選擇maven將出現(xiàn)右側(cè)面板,在紅色劃線部位輸入如圖所示指令,你可以為該指令命名(此處命名為MvnSpringBootRun))?
點(diǎn)擊保存將會(huì)在IDEA項(xiàng)目運(yùn)行部位出現(xiàn),點(diǎn)擊綠色箭頭運(yùn)行即可?
?
??
②. 使用spring-boot-devtools?
在項(xiàng)目的pom文件中添加依賴:?
?<!--熱部署jar-->
?<dependency>
? ? ?<groupId>org.springframework.boot</groupId>
? ? ?<artifactId>spring-boot-devtools</artifactId>
?</dependency>?
然后:使用 shift+ctrl+alt+"/" (IDEA中的快捷鍵) 選擇"Registry" 然后勾選 compiler.automake.allow.when.app.running?
109. jpa 和 hibernate 有什么區(qū)別??
JPA Java Persistence API,是Java EE 5的標(biāo)準(zhǔn)ORM接口,也是ejb3規(guī)范的一部分。Hibernate,當(dāng)今很流行的ORM框架,是JPA的一個(gè)實(shí)現(xiàn),但是其功能是JPA的超集。JPA和Hibernate之間的關(guān)系,可以簡(jiǎn)單的理解為JPA是標(biāo)準(zhǔn)接口,Hibernate是實(shí)現(xiàn)。那么Hibernate是如何實(shí)現(xiàn)與JPA的這種關(guān)系的呢。Hibernate主要是通過三個(gè)組件來實(shí)現(xiàn)的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。hibernate-annotation是Hibernate支持annotation方式配置的基礎(chǔ),它包括了標(biāo)準(zhǔn)的JPA annotation以及Hibernate自身特殊功能的annotation。hibernate-core是Hibernate的核心實(shí)現(xiàn),提供了Hibernate所有的核心功能。hibernate-entitymanager實(shí)現(xiàn)了標(biāo)準(zhǔn)的JPA,可以把它看成hibernate-core和JPA之間的適配器,它并不直接提供ORM的功能,而是對(duì)hibernate-core進(jìn)行封裝,使得Hibernate符合JPA的規(guī)范。
110. 什么是 spring cloud??
從字面理解,Spring Cloud 就是致力于分布式系統(tǒng)、云服務(wù)的框架。?
Spring Cloud 是整個(gè) Spring 家族中新的成員,是最近云服務(wù)火爆的必然產(chǎn)物。?
Spring Cloud 為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具,例如:?
配置管理服務(wù)注冊(cè)與發(fā)現(xiàn)斷路器智能路由服務(wù)間調(diào)用負(fù)載均衡微代理控制總線一次性令牌全局鎖領(lǐng)導(dǎo)選舉分布式會(huì)話集群狀態(tài)分布式消息……
使用 Spring Cloud 開發(fā)人員可以開箱即用的實(shí)現(xiàn)這些模式的服務(wù)和應(yīng)用程序。這些服務(wù)可以任何環(huán)境下運(yùn)行,包括分布式環(huán)境,也包括開發(fā)人員自己的筆記本電腦以及各種托管平臺(tái)。?
111. spring cloud 斷路器的作用是什么??
在Spring Cloud中使用了Hystrix 來實(shí)現(xiàn)斷路器的功能,斷路器可以防止一個(gè)應(yīng)用程序多次試圖執(zhí)行一個(gè)操作,即很可能失敗,允許它繼續(xù)而不等待故障恢復(fù)或者浪費(fèi) CPU 周期,而它確定該故障是持久的。斷路器模式也使應(yīng)用程序能夠檢測(cè)故障是否已經(jīng)解決,如果問題似乎已經(jīng)得到糾正,應(yīng)用程序可以嘗試調(diào)用操作。?
斷路器增加了穩(wěn)定性和靈活性,以一個(gè)系統(tǒng),提供穩(wěn)定性,而系統(tǒng)從故障中恢復(fù),并盡量減少此故障的對(duì)性能的影響。它可以幫助快速地拒絕對(duì)一個(gè)操作,即很可能失敗,而不是等待操作超時(shí)(或者不返回)的請(qǐng)求,以保持系統(tǒng)的響應(yīng)時(shí)間。如果斷路器提高每次改變狀態(tài)的時(shí)間的事件,該信息可以被用來監(jiān)測(cè)由斷路器保護(hù)系統(tǒng)的部件的健康狀況,或以提醒管理員當(dāng)斷路器跳閘,以在打開狀態(tài)。?
112. spring cloud 的核心組件有哪些??
①. 服務(wù)發(fā)現(xiàn)——Netflix Eureka?
一個(gè)RESTful服務(wù),用來定位運(yùn)行在AWS地區(qū)(Region)中的中間層服務(wù)。由兩個(gè)組件組成:Eureka服務(wù)器和Eureka客戶端。Eureka服務(wù)器用作服務(wù)注冊(cè)服務(wù)器。Eureka客戶端是一個(gè)java客戶端,用來簡(jiǎn)化與服務(wù)器的交互、作為輪詢負(fù)載均衡器,并提供服務(wù)的故障切換支持。Netflix在其生產(chǎn)環(huán)境中使用的是另外的客戶端,它提供基于流量、資源利用率以及出錯(cuò)狀態(tài)的加權(quán)負(fù)載均衡。?
②. 客服端負(fù)載均衡——Netflix Ribbon?
Ribbon,主要提供客戶側(cè)的軟件負(fù)載均衡算法。Ribbon客戶端組件提供一系列完善的配置選項(xiàng),比如連接超時(shí)、重試、重試算法等。Ribbon內(nèi)置可插拔、可定制的負(fù)載均衡組件。?
③. 斷路器——Netflix Hystrix?
斷路器可以防止一個(gè)應(yīng)用程序多次試圖執(zhí)行一個(gè)操作,即很可能失敗,允許它繼續(xù)而不等待故障恢復(fù)或者浪費(fèi) CPU 周期,而它確定該故障是持久的。斷路器模式也使應(yīng)用程序能夠檢測(cè)故障是否已經(jīng)解決。如果問題似乎已經(jīng)得到糾正,應(yīng)用程序可以嘗試調(diào)用操作。?
④. 服務(wù)網(wǎng)關(guān)——Netflix Zuul?
類似nginx,反向代理的功能,不過netflix自己增加了一些配合其他組件的特性。?
⑤. 分布式配置——Spring Cloud Config?
這個(gè)還是靜態(tài)的,得配合Spring Cloud Bus實(shí)現(xiàn)動(dòng)態(tài)的配置更新。?
?
未完待續(xù),不定時(shí)更新!?
?
歡迎大家關(guān)注我的公眾號(hào):Java團(tuán)長(zhǎng),面試題更新之后可以在第一時(shí)間獲取~
總結(jié)
以上是生活随笔為你收集整理的[转载] 2020最新Java面试题,常见面试题及答案汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux环境OpenRASP使用教程,
- 下一篇: arithmetic java_Java