1. 程式人生 > 實用技巧 >Java面經

Java面經

作者:希望秋招拿到offer
連結:https://www.nowcoder.com/discuss/452732?type=0&order=0&pos=33&page=3&channel=-1&source_id=discuss_center_0_nctrack
來源:牛客網

1、牛客刷題

●RabbitMQ有以下幾種工作模式 :
簡單模式:一個生產者,一個消費者

work模式:一個生產者,多個消費者,每個消費者獲取到的訊息唯一。

訂閱模式:一個生產者傳送的訊息會被多個消費者獲取。

路由模式:傳送訊息到交換機並且要指定路由key ,消費者指定路由key將佇列繫結到交換機

topic模式:將路由鍵和某模式進行匹配,此時佇列需要繫結在一個模式上
RPC

String,Stringbuffer,StringBuilder的區別

String:

  • String類是一個不可變的類,一旦建立就不可以修改。
  • String是final類,不能被繼承
  • String實現了equals()方法和hashCode()方法

StringBuffer:

  • 繼承自AbstractStringBuilder,是可變類。
  • StringBuffer是執行緒安全的
  • 可以通過append方法動態構造資料。

StringBuilder:

  • 繼承自AbstractStringBuilder,是可變類。

  • StringBuilder是非線性安全的。

  • 執行效率比StringBuffer高。

String s 與new String的區別

複製程式碼
1 2 String str ="whx"; String newStr =new String ("whx");

String str ="whx"

先在常量池中查詢有沒有"whx" 這個物件,如果有,就讓str指向那個"whx".如果沒有,在常量池中新建一個“whx”物件,並讓str指向在常量池中新建的物件"whx"。

String newStr =new String ("whx");

是在堆中建立的物件"whx" ,在棧中建立堆中"whx" 物件的記憶體地址。

反射的原理,反射建立類例項的三種方式是什麼

Java反射機制:

​ Java 的反射機制是指在執行狀態中,對於任意一個類都能夠知道這個類所有的屬性和方法; 並且對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取資訊以及動態呼叫物件方法的功能成為Java語言的反射機制

獲取 Class 類物件三種方式:

  • 使用 Class.forName 靜態方法
  • 使用類的.class 方法
  • 使用例項物件的 getClass() 方法

JDK動態代理與cglib實現的區別

  • java動態代理是利用反射機制生成一個實現代理介面的匿名類,在呼叫具體方法前呼叫InvokeHandler處理。
  • cglib動態代理是利用asm開源包,對代理物件類的class檔案載入進來,通過修改其位元組碼生成子類來處理。
  • JDK動態代理只能對實現了介面的類生成代理,而不能針對類
  • cglib是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法。因為是繼承,所以該類或方法最好不要宣告成final

談談序列化與反序列化

  • 序列化是指將物件轉換為位元組序列的過程,而反序列化則是將位元組序列轉換為物件的過程。
  • Java物件序列化是將實現了Serializable介面的物件轉換成一個位元組序列,能夠通過網路傳輸、檔案儲存等方式傳輸 ,傳輸過程中卻不必擔心資料在不同機器、不同環境下發生改變,也不必關心位元組的順序或其他任何細節,並能夠在以後將這個位元組序列完全恢復為原來的物件。

分散式結構,怎麼保證資料一致性

  1. 規避分散式事務——業務整合

  2. 經典方案 - eBay 模式

2、資料庫相關

MySQL

●SQL注入
SQL注入就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字串,最終達到欺騙伺服器執行惡意的SQL命令。
1)SQL注入攻擊的總體思路

​ ●尋找到SQL注入的位置
​ ●判斷伺服器型別和後臺資料庫型別
​ ●針對不同的伺服器和資料庫特點進行SQL注入攻擊
2)應對方法
​ ●使用正則表示式過濾傳入的引數
​ ●引數繫結
​ ●使用預編譯手段,繫結引數是最好的防SQL注入的方法。

● 請你說明一下 left join 和 right join 的區別?

left join(左聯接) :返回包括左表中的所有記錄和右表中聯結欄位相等的記錄
right join(右聯接) :返回包括右表中的所有記錄和左表中聯結欄位相等的記錄

●事務是什麼

​ 事務是應用程式中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要麼全部成功,要麼一個都不做。

● 資料庫ACID的特性。

原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。

一致性指事務前後資料的完整性必須保持一致。

隔離性指多個使用者併發訪問資料庫時,一個使用者的事務不能被其他使用者的事務所幹擾,多個併發事務之間資料要相互隔離。

永續性是指一個事務一旦提交,它對資料庫中資料的改變就是永久性的,即便資料庫發生故障也不應該對其有任何影響。

● 請你介紹一下,資料庫的三個正規化?

第一正規化(1NF):強調的是列的原子性,即列不能夠再分成其他幾列

第二正規化(2NF):首先滿足 1NF,另外包含兩部分內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。

第三正規化(3NF):首先是滿足2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況

● 請你介紹一下資料庫的隔離級別

隔離級別髒讀(Dirty Read)不可重複讀(NonRepeatable Read)幻讀(Phantom Read)
未提交讀 可能 可能 可能
已提交讀 不可能 可能 可能
可重複讀 不可能 不可能 可能
可序列化 不可能 不可能 不可能

未提交讀(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的資料。

已提交讀(Read Committed):只能讀取到已經提交的資料。Oracle等多數資料庫預設都是該級別 (不重複讀)。

可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀。

序列讀(Serializable):完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞。

資料庫的髒讀、幻讀、不可重複讀

1.髒讀:

指一個事務A正在訪問資料,並且對該資料進行了修改,但是這種修改還沒有提交到資料庫中(也可能因為某些原因Rollback了)。這時候另外一個事務B也訪問這個資料,然後使用了這個被A修改的資料,那麼這個資料就是髒的,並不是資料庫中真實的資料。這就被稱作髒讀。(事務A讀到了事務B未提交的資料)

解決辦法:把資料庫事務隔離級別調整到READ_COMMITTED

即讓使用者在更新時鎖定資料庫,阻止其他使用者讀取,直到更新全部完成才讓你讀取。

2.幻讀:

指一個事務A對一個表中的資料進行了修改,而且該修改涉及到表中所有的資料行;同時另一個事務B也在修改表中的資料,該修改是向表中插入一行新資料。那麼經過這一番操作之後,操作事務A的使用者就會發現表中還有沒修改的資料行,就像發生了幻覺一樣。這就被稱作幻讀。(事務A修改資料,事務B插入資料,A發現表中還沒有修改的資料行)

解決辦法:把資料庫事務隔離級別調整到SERIALIZABLE_READ

3.不可重複讀:

指在一個事務A內,多次讀同一個資料,但是事務A沒有結束時,另外一個事務B也訪問該同一資料。那麼在事務A的兩次讀資料之間,由於事務B的修改導致事務A兩次讀到的資料可能是不一樣的。這就發生了在一個事務內兩次讀到的資料不一樣,這就被稱作不可重複讀。(事務A多次讀資料,事務B訪問資料,A讀到了B修改的資料,導致兩次讀到的資料不一樣

解決辦法:把資料庫事務隔離級別調整到REPEATABLE_READ

級別高低:髒讀 < 不可重複讀 < 幻讀

所以設定了最高級別的SERIALIZABLE_READ就不需要設定其他的了,即解決了幻讀問題那麼髒度和不可重複讀自然就都解決了。

● 請你簡單介紹一下,資料庫水平切分與垂直切分

垂直拆分就是要把表按模組劃分到不同資料庫表中,單表大資料量依然存在效能瓶頸

水平切分就是要把一個表按照某種規則把資料劃分到不同表或資料庫裡。

通俗理解:水平拆分行,行資料拆分到不同表中, 垂直拆分列,表資料拆分到不同表中

● 請你講講 Statement 和 Prepared Statement 的區別?哪個效能更好?

與Statement相比,①PreparedStatement介面代表預編譯的語句,它主要的優勢在於可以減少SQL的編譯錯誤並增加SQL的安全性(減少SQL注射攻擊的可能性);②PreparedStatement中的SQL語句是可以帶引數的,避免了用字串連線拼接SQL語句的麻煩和不安全;③當批量處理SQL或頻繁執行相同的查詢時,PreparedStatement有明顯的效能上的優勢,由於資料庫可以將編譯優化後的SQL語句快取起來,下次執行相同結構的語句時就會很快

mysql資料庫的索引型別

索引資料結構:二叉樹紅黑樹、hash表、B-tree

1、普通索引當一張表,把某個列設為主鍵的時候,則該列就是主鍵索引

2、唯一索引索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。

3、主鍵索引是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。

4、組合索引指多個欄位上建立的索引,只有在查詢條件中使用了建立索引時的第一個欄位,索引才會被使用。使用組合索引時遵循最左字首集合。

5、全文索引主要用來查詢文字中的關鍵字,而不是直接與索引中的值相比較。

InnoDB索引實現(聚集)

  • 資料檔案本身就是索引檔案
  • 表資料檔案本身就是按B+樹組織的一個索引結構檔案
  • 聚集索引的葉子節點包含了完整的資料記錄
  • 表必須有主鍵,且推薦使用整型的自增主鍵
  • 普通索引結構葉子節點儲存的是主鍵值

InnoDB主鍵索引查詢流程:通過.ibd檔案找到對應的索引,索引的value即為那行對應的完整資料

聚集索引和非聚集索引的區別?

聚集索引:表中那行資料的索引和資料都合併在一起了。

非聚集索引:表中那行資料的索引和資料是分開儲存的。

一個 SQL 執行的很慢,我們要分兩種情況討論:

1、偶爾很慢,則有如下原因

(1)、資料庫在重新整理髒頁,例如 redo log 寫滿了需要同步到磁碟。

(2)、執行的時候,遇到鎖,如表鎖、行鎖。

2、這條 SQL 語句一直執行的很慢,則有如下原因。

(1)、沒有用上索引:例如該欄位沒有索引;由於對欄位進行運算、函式操作導致無法用索引。

(2)、資料庫選錯了索引。

Redis

redis常見的資料結構以及應用場景:

String:key -value快取應用,最常規的set/get操作,value可以是String也可以是數字。一般做一些複雜的計數功能的快取。

Hash:field-value對映表,儲存使用者資訊和商品資訊

List:list分頁查詢

Set:實現差,並,交集操作,比如共同喜好等

Sorted set:使用者列表,禮物排行榜,彈幕訊息

快取雪崩

快取同一時間大面積失效,所有請求都落到資料庫造成短時間內承受大量請求而崩掉

如何解決快取雪崩?在快取的時候給過期時間加上一個隨機值,這樣就會大幅度的減少快取在同一時間過期。

對於“Redis掛掉了,請求全部走資料庫”這種情況,我們可以有以下的思路:

事發前:實現Redis的高可用(主從架構+Sentinel 或者Redis Cluster),儘量避免Redis掛掉這種情況發生。

事發中:設定本地快取(ehcache)+限流(hystrix),儘量避免我們的資料庫***掉(起碼能保證我們的服務還是能正常工作的)

事發後:redis持久化,重啟後自動從磁碟上載入資料,快速恢復快取資料。

快取穿透

惡意請求快取中不存在的資料,所有求情都落到資料庫造成短時間內承受大量請求而崩掉

如何解決快取穿透?

(一)利用互斥鎖,快取失效的時候,先去獲得鎖,得到鎖了,再去請求資料庫。沒得到鎖,則休眠一段時間重試

(二)採用非同步更新策略,無論key是否取到值,都直接返回。value值中維護一個快取失效時間,快取如果過期,非同步起一個執行緒去讀資料庫,更新快取。需要做快取預熱(專案啟動前,先載入快取)操作。

(三)提供一個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。如果不合法,則直接返回。

Redis和資料庫雙寫一致性?

首先,採取正確更新策略,先更新資料庫,再刪快取。其次,因為可能存在刪除快取失敗的問題,提供一個補償措施即可,例如利用訊息佇列。

採用延時雙刪策略

(1)先淘汰快取
(2)再寫資料庫(這兩步和原來一樣)
(3)休眠1秒,再次淘汰快取

Redis的記憶體淘汰機制:Redis提供了8種記憶體淘汰策略

  1. volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
  2. volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰
  3. volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
  4. allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的key(這個是最常用的)
  5. allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
  6. no-eviction:禁止驅逐資料,也就是說當記憶體不足以容納新寫入資料時,新寫入操作會報錯。
  7. volatile-lfu:從已設定過期時間的資料集(server.db[i].expires)中挑選最不經常使用的資料淘汰
  8. allkeys-lfu:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最不經常使用的key

如何解決 Redis 的併發競爭 Key 問題
所謂 Redis 的併發競爭 Key 的問題也就是多個系統同時對一個 key 進行操作,最後執行的順序和我們期望的順序不同,導致了結果的不同!推薦一種方案:分散式鎖(zookeeper 和 redis 都可以實現分散式鎖)。

基於zookeeper臨時有序節點可以實現的分散式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。

redis 持久化機制(怎麼保證 redis 掛掉之後再重啟資料可以進行恢復)

1、快照(snapshotting)持久化(RDB)

Redis可以通過建立快照來獲得儲存在記憶體裡面的資料在某個時間點上的副本。Redis建立快照之後,可以對快照進行備份,可以將快照複製到其他伺服器從而建立具有相同資料的伺服器副本(Redis主從結構,主要用來提高Redis效能),還可以將快照留在原地以便重啟伺服器的時候使用。快照持久化是Redis預設採用的持久化方式,在redis.conf配置檔案中預設有此下配置
2、AOF(append-only file)持久化

與快照持久化相比,AOF持久化 的實時性更好,因此已成為主流的持久化方案。預設情況下Redis沒有開啟AOF方式的持久化,可以通過appendonly引數開啟.Redis 4.0 開始支援 RDB 和 AOF 的混合持久化(預設關閉,可以通過配置項 aof-use-rdb-preamble 開啟)。

● 請問,為什麼 redis 讀寫速率快、效能好?

Redis是純記憶體資料庫,相對於讀寫磁碟,讀寫記憶體的速度就不是幾倍幾十倍了,一般hash查詢可以達到每秒百萬次的數量級。

多路複用IO,“多路”指的是多個網路連線,“複用”指的是複用同一個執行緒。採用多路 I/O 複用技術可以讓單個執行緒高效的處理多個連線請求(儘量減少網路IO的時間消耗)。可以直接理解為:單執行緒的原子操作,避免上下文切換的時間和效能消耗;加上對記憶體中資料的處理速度,很自然的提高redis的吞吐量。

3、SSM

1、spring

● 請問什麼是IoC和DI?並且簡要說明一下DI是如何實現的?

IoC叫控制反轉,DI叫依賴注入。控制反轉是把傳統上由程式程式碼直接操控的物件的呼叫權交給容器通過容器來實現物件元件的裝配和管理。"控制反轉"就是對元件物件控制權的轉移,從程式程式碼本身轉移到了外部容器,由容器來建立物件並管理物件之間的依賴關係。依賴注入的基本原則是應用元件不應該負責查詢資源或者其他依賴的協作物件。配置物件的工作應該由容器負責,查詢資源的邏輯應該從應用元件的程式碼中抽取出來,交給容器來完成。DI是對IoC更準確的描述,即元件之間的依賴關係由容器在執行期決定,即由容器動態的將某種依賴關係注入到元件之中。
依賴注入可以通過setter方法注入(設值注入)、構造器注入和介面注入三種方式來實現,Spring支援setter注入和構造器注入,通常使用構造器注入來注入必須的依賴關係,對於可選的依賴關係,則setter注入是更好的選擇,setter注入需要類提供無參構造器或者無參的靜態工廠方法來建立物件。

依賴注入是從應用程式的角度在描述:應用程式依賴容器建立並注入它所需要的外部資源;

控制反轉是從容器的角度在描述:容器控制應用程式,由容器反向的嚮應用程式注入應用程式所需要的外部資源。

● 請說明一下springIOC原理是什麼?如果你要實現IOC需要怎麼做?請簡單描述一下實現步驟

①IoC這是spring的核心,由spring來負責控制物件的生命週期和物件間的關係

IoC的一個在系統執行中,動態的向某個物件提供它所需要的其他物件。這一點是通過DI來實現的。比如物件A需要操作資料庫,有了 spring我們就只需要告訴spring,A中需要一個Connection,至於這個Connection怎麼構造,何時構造,A不需要知道。在系統執行時,spring會在適當的時候製造一個Connection,然後像***一樣,注射到A當中,這樣就完成了對各個物件之間關係的控制。A需要依賴 Connection才能正常執行,而這個Connection是由spring注入到A中的,依賴注入的名字就這麼來的。那麼DI是如何實現的呢? Java 1.3之後一個重要特徵是反射(reflection),它允許程式在執行的時候動態的生成物件、執行物件的方法、改變物件的屬性,spring就是通過反射來實現注入的。

②實現IOC的步驟

定義用來描述bean的配置的Java類、解析bean的配置、遍歷存放HashMap物件

● 請談一談Spring中自動裝配的方式有哪些?

  • no:不進行自動裝配,手動設定Bean的依賴關係。
  • byName:根據Bean的名字進行自動裝配。
  • byType:根據Bean的型別進行自動裝配。
  • constructor:類似於byType,不過是應用於構造器的引數,如果正好有一個Bean與構造器的引數型別相同則可以自動裝配,否則會導致錯誤。
  • autodetect:如果有預設的構造器,則通過constructor的方式進行自動裝配,否則使用byType的方式進行自動裝配。

bean的生命週期

● 請簡要說明一下IOC和AOP是什麼?

控制反轉(IoC)與依賴注入(DI)是同一個概念,引入IOC的目的:(1)脫開、降低類之間的耦合;(2)倡導面向介面程式設計、實施依賴倒換原則; (3)提高系統可插入、可測試、可修改等特性。

具體做法:(1)將bean之間的依賴關係儘可能地抓換為關聯關係;

(2)將對具體類的關聯儘可能地轉換為對Java interface的關聯,而不是與具體的服務物件相關聯;

(3)Bean例項具體關聯相關Java interface的哪個實現類的例項,在配置資訊的元資料中描述;

(4)由IoC元件(或稱容器)根據配置資訊,例項化具體bean類、將bean之間的依賴關係注入進來。

AOP,即面向切面程式設計,它利用一種稱為"橫切"的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其命名為"Aspect",所謂"切面"是那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組之間的耦合度,並有利於未來的可操作性和可維護性。

使用"橫切"技術,AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如許可權認證、日誌、事物。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開。

● 請問Spring支援的事務管理類型有哪些?以及你在專案中會使用哪種方式?

Spring支援程式設計式事務管理宣告式事務管理。許多Spring框架的使用者選擇宣告式事務管理,因為這種方式和應用程式的關聯較少,因此更加符合輕量級容器的概念。宣告式事務管理要優於程式設計式事務管理,儘管在靈活性方面它弱於程式設計式事務管理,因為程式設計式事務允許你通過程式碼控制業務。

● 你如何理解AOP中的連線點(Joinpoint)、切點(Pointcut)、增強(Advice)、引介(Introduction)、織入(Weaving)、切面(Aspect)這些概念?

a. 連線點(Joinpoint):程式執行的某個特定位置(如:某個方法呼叫前、呼叫後,方法丟擲異常後)。一個類或一段程式程式碼擁有一些具有邊界性質的特定點,這些程式碼中的特定點就是連線點。
b. 切點:如果連線點相當於資料中的記錄,那麼切點相當於查詢條件,一個切點可以匹配多個連線點。
c. 增強(Advice):增強是織入到目標類連線點上的一段程式程式碼。

d. 引介(Introduction):引介是一種特殊的增強,它為類新增一些屬性和方法。
e. 織入(Weaving):織入是將增強新增到目標類具體連線點上的過程,AOP有三種織入方式
f. 切面:切面是由切點和增強(引介)組成的,它包括了對橫切關注功能的定義,也包括了對連線點的定義。

● 請問AOP的原理是什麼?

AOP指面向切面程式設計,用於處理系統中分佈於各個模組的橫切關注點,比如事務管理、日誌、快取等等。AOP實現的關鍵在於AOP框架自動建立的AOP代理,AOP代理主要分為靜態代理和動態代理,靜態代理的代表為AspectJ;而動態代理則以Spring AOP為代表。通常使用AspectJ的編譯時增強實現AOP,AspectJ是靜態代理的增強,所謂的靜態代理就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強。

Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。

JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個介面。核心是InvocationHandler介面和Proxy類。如果目標類沒有實現介面,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。

CGLIB(Code Generation Library),是一個程式碼生成的類庫,可以在執行時動態的生成某個類的子類

● 請問aop的應用場景有哪些?

Authentication 許可權 ,Caching 快取 ,Context passing 內容傳遞 ,Error handling 錯誤處理 ,Lazy loading 懶載入 ,Debugging 除錯 ,logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準,Performance optimization 效能優化 ,Persistence 持久化 ,Resource pooling 資源池 ,Synchronization 同步,Transactions 事務。

● Spring框架為企業級開發帶來的好處有哪些?

  • 非侵入式:支援基於POJO的程式設計模式,不強制性的要求實現Spring框架中的介面或繼承Spring框架中的類。
  • IoC容器:IoC容器幫助應用程式管理物件以及物件之間的依賴關係,物件之間的依賴關係如果發生了改變只需要修改配置檔案而不是修改程式碼,因為程式碼的修改可能意味著專案的重新構建和完整的迴歸測試。
  • AOP:將所有的橫切關注功能封裝到切面中通過配置的方式將橫切關注功能動態新增到目的碼上,進一步實現了業務邏輯和系統服務之間的分離。另一方面,有了AOP程式設計師可以省去很多自己寫代理類的工作。
  • MVC:Spring的MVC框架為Web表示層提供了更好的解決方案。
  • 事務管理:Spring以寬廣的胸懷接納多種持久層技術,並且為其提供了宣告式的事務管理,在不需要任何一行程式碼的情況下就能夠完成事務管理。
  • 其他:Spring為Java企業級開發提供了一站式選擇,你可以在需要的時候使用它的部分和全部,更重要的是,甚至可以在感覺不到Spring存在的情況下,在你的專案中使用Spring提供的各種優秀的功能。

Aop實現的幾種方式:

第一種:靜態織入,即在編譯時,就將各種涉及AOP攔截的程式碼注入到符合一定規則的類中,編譯後的程式碼與我們直接在RealA呼叫屬性或方法前後增加程式碼是相同的,只是這個工作交由編譯器來完成。

第二種:EMIT反射,即:通過Emit反射動態生成代理類

第三種:普通反射+利用Remoting的遠端訪問物件時的直實代理類來實現

Spring如何選擇用JDK還是CGLiB?

1)當Bean實現介面時,Spring就會用JDK的動態代理。

2)當Bean沒有實現介面時,Spring使用CGlib是實現。

● 請問持久層設計要考慮的問題有哪些?請談一下你用過的持久層框架都有哪些?

所謂"持久"就是將記憶體中的資料儲存到關係型資料庫、檔案系統、訊息佇列等提供持久化支援的裝置中。持久層就是系統中專注於實現資料持久化的相對獨立的層面。

持久層設計的目標包括:

  • 資料儲存邏輯的分離,提供抽象化的資料訪問介面。
  • 資料訪問底層實現的分離,可以在不修改程式碼的情況下切換底層實現。
  • 資源管理和排程的分離,在資料訪問層實現統一的資源排程(如快取機制)。
  • 資料抽象,提供更面向物件的資料操作。

● 請闡述一下實體物件的三種狀態是什麼?以及對應的轉換關係是什麼?

Hibernate文件中為Hibernate物件定義了四種狀態,分別是:瞬時態(new, or transient)、持久態(managed, or persistent)、遊狀態(detached)和移除態

瞬時態:當new一個實體物件後,這個物件處於瞬時態,即這個物件只是一個儲存臨時資料的記憶體區域,如果沒有變數引用這個物件,則會被JVM的垃圾回收機制回收。這個物件所儲存的資料與資料庫沒有任何關係,除非通過Session的save()、saveOrUpdate()、persist()、merge()方法把瞬時態物件與資料庫關聯,並把資料插入或者更新到資料庫,這個物件才轉換為持久態物件。
持久態:持久態物件的例項在資料庫中有對應的記錄,並擁有一個持久化標識(ID)。對持久態物件進行delete操作後,資料庫中對應的記錄將被刪除,那麼持久態物件與資料庫記錄不再存在對應關係,持久態物件變成移除態(可以視為瞬時態)。持久態物件被修改變更後,不會馬上同步到資料庫,直到資料庫事務提交。
遊離態:當Session進行了close()、clear()、evict()或flush()後,實體物件從持久態變成遊離態,物件雖然擁有持久和與資料庫對應記錄一致的標識值,但是因為物件已經從會話中清除掉,物件不在持久化管理之內,所以處於遊離態(也叫脫管態)。遊離態的物件與臨時狀態物件是十分相似的,只是它還含有持久化標識。

● 請說明一下鎖機制的作用是什麼?並且簡述一下Hibernate的悲觀鎖和樂觀鎖機制是什麼?

有些業務邏輯在執行過程中要求對資料進行排他性的訪問,於是需要通過一些機制保證在此過程中資料被鎖住不會被外界修改,這就是所謂的鎖機制。
Hibernate支援悲觀鎖和樂觀鎖兩種鎖機制。悲觀鎖,顧名思義悲觀的認為在資料處理過程中極有可能存在修改資料的併發事務(包括本系統的其他事務或來自外部系統的事務),於是將處理的資料設定為鎖定狀態。悲觀鎖必須依賴資料庫本身的鎖機制才能真正保證資料訪問的排他性,樂觀鎖,顧名思義,對併發事務持樂觀態度(認為對資料的併發操作不會經常性的發生),通過更加寬鬆的鎖機制來解決由於悲觀鎖排他性的資料訪問對系統性能造成的嚴重影響。

依賴注入的注入方式

1、使用建構函式提供2、使用set方法提供3、使用註解提供

建立bean的方式

1、使用預設建構函式2、使用普通工廠中的方法建立物件3、使用工廠中的靜態方法建立物件

Aspectj對AOP的實現:

1)註冊bean 2)配置aop 3)定義切入點 4)定義切面(哪種通知)

Spring如何解決迴圈依賴

spring中迴圈依賴有三種情況:

  1、構造器注入形成的迴圈依賴。也就是beanB需要在beanA的建構函式中完成初始化,beanA也需要在beanB的建構函式中完成舒適化,這種情況的結果就是兩個bean都不能完成初始化,迴圈依賴難以解決。

  2、setter注入構成的迴圈依賴。beanA需要在beanB的setter方法中完成初始化,beanB也需要在beanA的setter方法中完成初始化,spring設計的機制主要就是解決這種迴圈依賴

  3、prototype作用域bean的迴圈依賴。這種迴圈依賴同樣無法解決,因為spring不會快取‘prototype’作用域的bean,而spring中迴圈依賴的解決正是通過快取來實現的。

spring只能解決setter注入構成的依賴,第二種情況中迴圈依賴的解決方案:

  步驟一:beanA進行初始化,並且將自己進行初始化的狀態記錄下來,並提前向外暴露一個單例工程方法,從而使其他bean能引用到該bean

  步驟二:beanA中有beanB的依賴,於是開始初始化beanB。

  步驟三:初始化beanB的過程中又發現beanB依賴了beanA,於是又進行beanA的初始化,這時發現beanA已經在進行初始化了,程式發現了存在的迴圈依賴,然後通過步驟一中暴露的單例工程方法拿到beanA的引用(注意,此時的beanA只是完成了建構函式的注入但為完成其他步驟),從而beanB拿到beanA的引用,完成注入,完成了初始化,如此beanB的引用也就可以被beanA拿到,從而beanA也就完成了初始化。

Spring的載入過程

初始化環境—>載入配置檔案—>例項化Bean—>呼叫Bean顯示資訊

2、springmvc

1.SpringMVC的流程

(1)使用者傳送請求至前端控制器DispatcherServlet
(2)Dispatcher Servlet收到請求後,呼叫HandlerMapping處理器對映器,請求獲取Handler
(3)處理器對映器根據請求url獲取具體的處理器,返回給DispatcherServlet
(4)DispatcherServlet呼叫HandlerAdapter處理器介面卡
(5)處理器介面卡經過適配呼叫具體的處理器
(6)Hander執行完成返回ModelAndView
(7)HandlerAdapter將Handler執行結果ModelAndView返回給DispatcherServlet
(8)DispatcherServlet將ModelAndView傳給ViewResolver檢視解析器進行解析
(9)ViewResolver經過解析後返回具體View
(10)DispatcherServlet對View進行渲染檢視
(11)DispatcherServlet響應使用者

2.SpringMVC的主要元件?

(1)前端控制器DispatcherServlet(不需要程式設計師開發):接收請求、響應結果,相當於轉發器,有
了DispatcherServlet就減少了其它元件之間的耦合度。
(2)處理器對映器HandlerMapping(不需要程式設計師開發):根據請求的url來查詢Handler
(3)處理器介面卡HandlerAdapter:在編寫Handler的時候要按照HandlerAdapter要求的規則去編
寫,這樣介面卡HandlerAdapter才可以正確的去執行Handler。
(4)處理器Handler(需要程式設計師開發)
(5)檢視解析器ViewResolver(不需要程式設計師開發):進行檢視的解析,根據檢視邏輯名解析成真正
的檢視。
(6)檢視View(需要程式設計師開發jsp):View是一個介面,它的實現類支援不同的檢視型別

3.SpringMVC和Struts2的區別?

(1)SpringMVC的入口是一個servlet即前端控制器,而Struts2入口是一個filter過濾器
(2)SpringMVC是基於方法開發的,傳遞引數到方法的形參上,Struts2是基於類開發的,傳遞引數是
通過類的屬性。

4.SpringMVC怎麼樣設定重定向和轉發的?

(1)轉發:在返回值前面加forward,如forward:user.do?name=method4
(2)重定向:在返回值前面加redirect,如redirect:http://www.baidu.com

5.SpringMVC怎麼和ajax相互呼叫

通過jackson框架就可以把java裡面的物件直接轉化為js可以識別的json物件,具體步驟如下:

(1)加入jackson.jar

(2)在配置檔案中配置json的對映
(3)在接受Ajax方法裡面可以直接返回Object,List等,但方法前面要加上@ResponseBody

6.如何解決post請求中亂碼問題,get的又如何處理?

(1)解決post請求亂碼問題
在web.xml中配置一個CharacterEncodingFilter過濾器,設定成utf-8;
(2)解決get請求亂碼問題
1.修改tomcat配置檔案新增編碼與工程編碼一致
2.對引數進行重新編碼:
String userName= new String(request.getParameter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat預設編碼,需要將tomcat編碼後的內容按utf-8編碼。

7.SpringMVC的控制器是不是單例模式,如果是,有什麼問題,怎麼解決?

單例模式:單例模式型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件

意圖:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。

主要解決:一個全域性使用的類頻繁地建立與銷燬。

何時使用:當您想控制例項數目,節省系統資源的時候。

如何解決:判斷系統是否已經有這個單例,如果有則返回,如果沒有則建立。

工廠模式

工廠模式提供了一種建立物件的最佳方式。在工廠模式中,我們在建立物件時不會對客戶端暴露建立邏輯,並且是通過使用一個共同的介面來指向新建立的物件

意圖:定義一個建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。

主要解決:主要解決介面選擇的問題。

何時使用:我們明確地計劃不同條件下建立不同例項時。

如何解決:讓其子類實現工廠介面,返回的也是一個抽象的產品。

是單例模式,所以在多執行緒訪問的時候有執行緒安全問題,不要用同步,會影響效能,解決方案是在控制
器裡面不能寫欄位。

8.SpringMVC常用的註解有哪些?

@RequestMapping:用於處理請求url對映的註解,可用於類或方法上。用於類上,則表示類中的所有
響應請求的方法都是以該地址作為父路徑。
@RequestBody:註解實現接受http請求的json資料,將json轉換為java物件。
@ResponseBody:註解實現將Controller方法返回的物件轉化為json物件響應給客戶。
@RestController:註解相當於@Controller+@ResponseBody
@RequestParam:在controller的方法中引數名與表單中的引數名不一致,使用@RequestParm實現參
數繫結
@RequestParam(name="username") String t_username
@PathVariable:Controller除了可以接受表單提交的資料之外,還可以獲取url中攜帶的變數,即路徑
變數

9.如果在攔截請求中,我想攔截get方式提交的方法,怎麼配置?

可以在@RequestMapping註解裡面加上method=RequestMethod.GET

10.如果想在攔截的方法裡面得到從前臺傳入的引數,怎麼得到?

直接在形參裡面宣告這個引數就可以,但必須名字和傳過來的引數一樣。

11.SpringMVC中函式的返回值是什麼?

返回值可以有多種型別,有String,void,和ModelAndView。

12.SpringMVC用什麼物件從後臺向前臺傳遞資料?

通過ModelMap物件,可以在這個物件裡面呼叫put方法,把物件加到裡面,前臺就可以通過el表示式
拿到。

13.註解原理

​ 註解本質上是一個繼承了Annotation的特殊介面,其具體實現類是Java執行時生成的動態代理類。我們
通過反射獲取註解時,返回的是Java執行時生成的動態代理物件。通過代理對像呼叫自定義註解的方
***最終呼叫AnnotationInvocaitonHandle的invoke方法。該方***從memberValues這個Map中
索引出對應的值。而memberValues的來源是java常量池。

3、mybatis

一、什麼是Mybatis?

  1. Mybatis是一個半ORM(物件關係對映),它內部封裝了JDBC,開發時只需要關注SQL語句本身,不
    需要再花費精力去處理載入驅動、建立連線、建立statement等繁雜的過程。程式設計師直接編寫原生態
    sql,可以嚴格控制sql執行效能,靈活度高。
  2. Mybatis可以使用XML或註解來配置和對映原生資訊,將POJO對映成資料庫中的記錄,避免了幾乎所
    有的JDBC程式碼和手動設定引數以及獲取結果集。

二、Mybatis的優點

1.基於SQL語句程式設計,相當靈活,不會對應用程式或者資料庫的現有設計造成任何影響,SQL寫在XML
裡,解除sql與程式程式碼的耦合,便於統一管理。提供xml標籤,支援編寫動態SQL語句,並可重用。
2.與JDBC相比,減少了50%以上的程式碼量,消除了JDBC大量冗餘的程式碼,不需要手動開關連線。
3.很好的與各種資料庫相容(因為Mybatis使用JDBC來連線資料庫,所以只要JDBC支援的資料庫
MyBatis都支援)。
4.能夠與Spring很好的整合。

三、Mybatis框架的缺點:

1.SQL語句的編寫工作量較大,尤其當欄位多、關聯表多時,編寫SQL語句的功底有一定要求。
2.SQL語句依賴於資料庫,導致資料庫移植性差,不能隨意更換資料庫。

四、Mybatis與Hibernate有哪些不同?
1.Mybatis和Hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程式設計師自己編寫Sql語句。
2.Mybatis直接編寫原生態sql,可以嚴格控制sql執行效能,靈活度高,非常適合關係資料模型要求不高
的軟體開發,因為這類軟體需求變化頻繁,一但需求變化要求迅速輸出成功。
3.Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體,如果用hibernate
開發可以節省很多程式碼,提高效率。

四、#{}和${}的區別是什麼?

{}是預編譯處理,${}是字串替換

Mybatis在處理#{}時會將sql中的#{}替換為?號,呼叫PreparedStatement的set方法來賦值。
Mybatis在處理${}時,就是把¥{}替換成變數的值。
使用#{}可以有效的防止SQL注入,提高系統安全性。

五、當實體類中的屬性名和表中的欄位名不一樣,怎麼辦?

1.定義欄位名的別名,讓欄位名的別名和實體類的屬性名一致。
2.通過來對映欄位名和屬性名一一對應

六、模糊查詢like語句該怎麼寫?

1.在Java程式碼中新增sql萬用字元。
2.在sql語句中拼接萬用字元,會引起sql注入

七、通常一個XML對映檔案,都會寫一個Dao介面與之對應,請問這個Dao介面

的工作原理是什麼?Dao接口裡的方法,引數不同時,方法能過載嗎?
1.Dao介面也即是Mapper介面,介面的全限名,就是對映檔案中namespace的值;介面的方法名,就
是對映檔案中Mapper的Statement的id值;介面方法內的引數,就是傳遞給sql的引數。
2.Mapper介面是沒有實現類的,當呼叫介面方法時,介面全限名+方法名拼接字串作為key值,可唯
一定位一個MapperStatement。

八、Mybatis的XML對映檔案中,不同的XML對映檔案,id是否可以重複?

不同的XML對映檔案,如果配置了namespace,那麼id可以重複,如果沒有配置namespace,那麼id
不能重複。
原因是namespace+id是作為map的key使用的,如果沒有namespace,就剩下id,那麼,id重複會導
致資料互相覆蓋。有了namespace,自然id就可以重複,namespace不同,namespace+id自然也就
不同。

九、為什麼說Mybatis是半自動ORM對映工具?它與全自動的區別在哪裡?

Hibernate屬於全自動ORM對映工具,使用Hibernate查詢關聯物件或者關聯集合物件時,可以根據對
象關係模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯物件或關聯集合物件時,需要手動編
寫sql來完成,所以,稱之為半自動ORM對映工具。

十、MyBatis實現一對一有幾種方式?具體怎麼操作的?

有聯合查詢和巢狀查詢,聯合查詢是幾個表聯合查詢,只查詢一次,通過resultMap裡面配置
association節點配置一對一的類就可以完成。
巢狀查詢是先查一個表,根據這個表裡面的結果的外來鍵id,再去另一個表裡查詢資料,也是通過
association配置,但另外一個表的查詢通過select屬性配置。

十二、使用MyBatis的mapper介面呼叫時有哪些要求?

1.Mapper介面方法名和mapper.xml中定義的每個sql的id相同。
2.Mapper介面方法的輸入引數型別和mapper.xml中定義的每個sql的parameterType的型別相同。
3.Mapper介面方法的輸出引數型別和mapper.xml中定義的每個sql的resultType的型別相同。
4.Mapper.xml檔案中namespace即是mapper介面的類路徑。

十三、mybatis的延遲載入

延遲載入:在真正使用資料時才發起查詢,不用的時候不查詢,按需載入

立即載入:不管用不用,只要一呼叫方法,馬上發起查詢

十四、Mybatis的一級快取和二級快取?

1)一級快取 Mybatis的一級快取是指SQLSession,一級快取的作用域是SQlSession, Mybits預設開啟一級快取。 在同一個SqlSession中,執行相同的SQL查詢時;第一次會去查詢資料庫,並寫在快取中,第二次會直接從快取中取。 當執行SQL時候兩次查詢中間發生了增刪改的操作,則SQLSession的快取會被清空。 每次查詢會先去快取中找,如果找不到,再去資料庫查詢,然後把結果寫到快取中。 Mybatis的內部快取使用一個HashMap,key為hashcode+statementId+sql語句。Value為查詢出來的結果集對映成的java物件。 SqlSession執行insert、update、delete等操作commit後會清空該SQLSession快取。

2)二級快取是mapper級別的,Mybatis預設是沒有開啟二級快取的。 第一次呼叫mapper下的SQL去查詢使用者的資訊,查詢到的資訊會存放代該mapper對應的二級快取區域。 第二次呼叫namespace下的mapper對映檔案中,相同的sql去查詢使用者資訊,會去對應的二級快取內取結果。 如果呼叫相同namespace下的mapepr對映檔案中增刪改sql,並執行了commit操作

一級快取:也稱為本地快取,用於儲存使用者在一次會話過程中查詢的結果,使用者一次會話中只能使用一個sqlSession,一級快取是自動開啟的,不允許關閉。

二級快取:也稱為全域性快取,是mapper級別的快取,是針對一個表的查結果的儲存,可以共享給所有針對這張表的查詢的使用者。也就是說對於mapper級別的快取不同的sqlsession是可以共享的。

JDBC程式設計有哪些不足之處,Mybatis是如何解決這些問題的?

1) 資料庫連線的建立、釋放頻繁造成系統資源浪費從而影響了效能,如果使用資料庫連線池就可以解決這個問題。當然JDBC同樣能夠使用資料來源。
解決:在SQLMapConfig.xml中配置資料連線池,使用資料庫連線池管理資料庫連線。

2) SQL語句在寫程式碼中不容易維護,事件需求中SQL變化的可能性很大,SQL變動需要改變JAVA程式碼。解決:將SQL語句配置在mapper.xml檔案中與java程式碼分離。

3) 向SQL語句傳遞引數麻煩,因為SQL語句的where條件不一定,可能多,也可能少,佔位符需要和引數一一對應。解決:Mybatis自動將java物件對映到sql語句。

4) 對結果集解析麻煩,sql變化導致解析程式碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成pojo物件解析比較方便。解決:Mbatis自動將SQL執行結果對映到java物件。

Mybatis程式設計步驟 ?

Step1:建立SQLSessionFactory Step2:通過SQLSessionFactory建立SQLSession Step3:通過SQLSession執行資料庫操作 Step4:呼叫session.commit()提交事物 Step5:呼叫session.close()關閉會話

MyBatis與hibernate有哪些不同 ?

1)Mybatis MyBatis 是支援定製化 SQL、儲存過程以及高階對映的一種持久層框架。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。Mybatis它不完全是一個ORM(物件關係對映)框架;它需要程式設計師自己編寫部分SQL語句。 mybatis可以通過xml或者註解的方式靈活的配置要執行的SQL語句,並將java物件和SQL語句對映生成最終的執行的SQL,最後將SQL執行的結果在對映生成java物件。 Mybatis程式設計師可以直接的編寫原生態的SQL語句,可以控制SQL執行效能,靈活度高,適合軟體需求變換頻繁的企業。 缺點:Mybatis無法做到資料庫無關性,如果需要實現支援多種資料庫的軟體,則需要自定義多套SQL對映檔案,工作量大。 2) Hibernate Hibernate是支援定製化 SQL、儲存過程以及高階對映的一種持久層框架。 Hibernate物件-關係對映能力強,資料庫的無關性好,Hirberate可以自動生成SQL語句,對於關係模型要求高的軟體,如果用HIrbernate開發可以節省很多時間。

SQLMapConfig.xml中配置有哪些內容?

複製程式碼
1 2 3 4 5 6 7 8 9 10 11 properties(屬性) settings(配置) typeAliases(類型別名) typeHandlers(型別處理器) objectFactory(物件工廠) plugins(外掛) environments(環境集合屬性物件) environment(環境子屬性物件) transactionManager(事務管理) dataSource(資料來源) mappers(對映器)

Mybatis動態SQL?

傳統的JDBC的方法,在組合SQL語句的時候需要去拼接,稍微不注意就會少少了一個空格,標點符號,都會導致系統錯誤。Mybatis的動態SQL就是為了解決這種問題而產生的;Mybatis的動態SQL語句值基於OGNL表示式的,方便在SQL語句中實現某些邏輯;可以使用標籤組合成靈活的sql語句,提供開發的效率。

ORM:

物件關係對映(Object Relational Mapping,簡稱ORM),提供了概念性的、易於理解的模型化資料的方法,目的是想像操作物件一樣操作資料庫.因為資料庫不是面向物件的,所以需要程式設計進行對映.

Mabatis三劍客分別是:mybatis-generator、mybatis-plugin、mybatis-pagehelper

4、配置檔案總結

web.xml**
1.配置一個全域性的引數:指定spring容器的配置檔案applicationContext.xml路徑。
2.編碼過濾器。
3.配置***,建立spring容器物件。
4.前端控制器,指定配置檔案spring-mvc.xml路徑
spring-mvc.xml
1.掃描包,建立類物件。
2.檢視解析器。
3.註解驅動。
4.自定義型別轉換器。
5.檔案上傳。
6.攔截器。
7.靜態資源放行。
applicationContext.xml
持久層配置
1.引入資料庫外部屬性檔案。
2.建立資料來源物件。
3.建立sqlSessionFactory物件:以前在測試類中使用構建者模式建立SessionFactory物件,引入
SqlMapConfig.xml檔案。
4.掃描dao層介面的包,建立動態代理物件,存入spring容器中。
業務層配置
5.掃描包,建立業務層所有類物件。
6.宣告式事務
1)事務管理類物件
2)事務增強物件
3)aop配置:切面配置

在使用springmvc框架的時候,在處理json的時候需要用到spring框架特有的註解@ResponseBody或
者@RestController註解,這兩個註解都會處理返回的資料格式,使用了該型別註解後返回的不再是視
圖,不會進行轉跳,而是返回json或xml資料格式,輸出在頁面上。
那麼,這兩個註解在使用上有什麼區別呢?
@ResponseBody,一般是使用在單獨的方法上的,需要哪個方法返回json資料格式,就在哪個方法
上使用,具有針對性。
@RestController,一般是使用在類上的,它表示的意思其實就是結合了@Controller和
@ResponseBody兩個註解,
如果哪個類下的所有方法需要返回json資料格式的,就在哪個類上使用該註解,具有統一性;需要注意
的是,使用了@RestController註解之後,其本質相當於在該類的所有方法上都統一使用了
@ResponseBody註解,所以該類下的所有方法都會返回json資料格式,輸出在頁面上,而不會再返回
檢視。

4、spring cloud

​ SpringCloud將現在非常流行的一些技術整合到一起,實現了諸如:配置管理,服務發現,智慧路由,負載均衡,熔斷器,控制匯流排,叢集狀態等等功能。

1、元件

1、Eureka:註冊中心

Eureka就好比是滴滴,負責管理、記錄服務提供者的資訊。服務呼叫者無需自己尋找服務,而是把自己的需求告訴Eureka,然後Eureka會把符合你需求的服務告訴你。

同時,服務提供方與Eureka之間通過“心跳”機制進行監控,當某個服務提供方出現問題,Eureka自然會把它從服務列表中剔除。這就實現了服務的自動註冊、發現、狀態監控。

基本架構:

  • Eureka:就是服務註冊中心(可以是一個叢集),對外暴露自己的地址
  • 提供者:啟動後向Eureka註冊自己資訊(地址,提供什麼服務)
  • 消費者:向Eureka訂閱服務,Eureka會將對應服務的所有提供者地址列表傳送給消費者,並且定期更新
  • 心跳(續約):提供者定期通過http方式向Eureka重新整理自己的狀態

Eureka架構中的三個核心角色:

  • 服務註冊中心

    Eureka的服務端應用,提供服務註冊和發現功能,就是剛剛我們建立的eureka-demo

  • 服務提供者

    提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現,只要對外提供的是Rest風格服務即可。本例中就是我們實現的user-service-demo

  • 服務消費者

    消費應用從註冊中心獲取服務列表,從而得知每個服務方的資訊,知道去哪裡呼叫服務方。本例中就是我們實現的consumer-demo

2、Zuul:服務閘道器

​ 服務閘道器是微服務架構中一個不可或缺的部分。通過服務閘道器統一向外系統提供REST API的過程中,除了具備服務路由、均衡負載功能之外,它還具備了許可權控制等功能。Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務架構提供了前門保護的作用,同時將許可權控制這些較重的非業務邏輯內容遷移到服務路由層面,使得服務叢集主體能夠具備更高的可複用性和可測試性。在微服務架構中,Zuul就是守門的大Boss!一夫當關,萬夫莫開!

​ 不管是來自於客戶端(PC或移動端)的請求,還是服務內部呼叫。一切對服務的請求都會經過Zuul這個閘道器,然後再由閘道器來實現 鑑權、動態路由等等操作。Zuul就是我們服務的統一入口。

Zuul中預設就已經集成了Ribbon負載均衡和Hystix熔斷機制。但是所有的超時策略都是走的預設值,比如熔斷超時時間只有1S,很容易就觸發了

3、Ribbon:負載均衡

負載均衡是我們處理高併發、緩解網路壓力和進行伺服器擴容的重要手段之一。但是,一般情況下我們
所說的負載均衡通常都是指伺服器端負載均衡,伺服器端負載均衡又分為兩種:一種是硬體負載均衡,
還有一種是軟體負載均衡

4、Feign:服務呼叫

Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣。你不用再自己拼接url,拼接引數等等操作,一切都交給Feign去做。

Feign中本身已經集成了Ribbon依賴和自動配置、Feign預設也有對Hystix的整合、Spring Cloud Feign 支援對請求和響應進行GZIP壓縮,以減少通訊過程中的效能損耗。

5、Hystix:熔斷器

雪崩效應:
在微服務架構中通常會有多個服務層呼叫,基礎服務的故障可能會導致級聯故障,進而造成整個系統不
可用的情況,這種現象被稱為雪崩效應。雪崩效應是一種因服務提供者的不可用導致服務消費者 的不可
用,並將不可用逐漸放大的過程。
A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者,A不可用引起了B的不可用,並將不可
用像滾雪球一樣放大到C和D時,雪崩效應就形成了。

Hystix是Netflix開源的一個延遲和容錯庫,用於隔離訪問遠端服務、第三方庫,防止出現級聯失敗。當有服務出現異常時,直接進行失敗回滾,服務降級處理:

當服務繁忙時,如果服務出現異常,不是粗暴的直接報錯,而是返回一個友好的提示,雖然拒絕了使用者的訪問,但是會返回一個結果。

這就好比去買魚,平常超市買魚會額外贈送殺魚的服務。等到逢年過節,超時繁忙時,可能就不提供殺魚服務了,這就是服務的降級。

系統特別繁忙時,一些次要服務暫時中斷,優先保證主要服務的暢通,一切資源優先讓給主要服務來使用,在雙十一、618時,京東天貓都會採用這樣的策略。

使用步驟:匯入依賴--->Feign的客戶端--->開啟feign的功能--->啟動測試

2、FastDFS

3、單點登入

單點登入又叫做sso,是在互相信任的多個系統中,只需要輸入一次使用者名稱密碼,就可以直接登入其它
互相信任的系統。
使用場景:
傳統企業專案:作系統許可權整合
網際網路專案:soa分散式架構下,是多個專案,如果跨專案跳轉訪問能夠自動認證。
單點登入伺服器,專案中配置cas的客戶端工具包,就可以不用寫程式碼實現單點登入。
cas和springSecurity整合到品優購專案中:整合前:
springSecurity的作用:

認證:判斷使用者名稱和密碼是否正確
賦權:使用者登入後,應該具有什麼樣的訪問許可權
整合後:
springSecurity:
賦權,使用者登入後,應該具有什麼樣的訪問許可權,使用者的認證工作交給cas,因為cas更擅長。
cas:判斷使用者名稱密碼是否正確,cas更擅長認證工作,因為它能完成在多個互相信任的系統中,只要在
一個系統中登入後,在其它系統中就不需要再次輸入使用者名稱密碼就能夠自動認證。

4、什麼是叢集?

叢集就是多臺機器,是一種線上的部署方案,很多機器加起來,效能就比一臺機器強,一般用這種部署
方案來解決高併發,高可用,容災,叢集也有不同的叫法,負載均衡叢集,高可用叢集,擴容叢集等。
什麼是分散式
分散式也叫做SOA,是一種設計方案,以前使用所有模組在一個專案中的寫法,叫做垂直架構,後來由
於網際網路的興起,為了模組間的解耦和擴充套件性以及部署的靈活性,會將一個專案按照模組進行拆分,一
個模組就是一個專案這種設計方案叫做分散式架構,也叫做SOA架構。
什麼是負載均衡器以及作用?
負載均衡器就是為了解決高併發而生的一種解決方案,它的作用就是接收所有請求,並將請求分發給
tomcat叢集,這樣均勻分佈請求到很多tomcat中,可以解決高併發。
負載均衡器的分類:
硬負載:硬負載就是硬體,很貴,需要花錢購買,常用的硬負載機器有f5,netsclaer。優點就是效能好
軟負載:軟體,***,需要部署在linux作業系統上,常用的有nginx,lvs優點就是***,缺點
就是效能沒有硬負載好,nginx一般單機可以抗住每秒5萬的請求量。
nginx反向代理配置:
一個nginx充當代理人的角色,而後面的tomcat不是叢集就是單臺tomcat部署的我們一個專案,這種部
署方案nginx就相當於我們專案的代理人,叫做反向代理配置。
nginx負載均衡配置:
一個nginx,對應tomcat叢集,也就是多個tomcat,這多個tomcat中部署的是同一個專案,nginx就可
以將請求均勻的分發給tomcat叢集來處理請求,這種配置叫做負載均衡配置。

5、什麼是docker?

docker是一種容器化技術,也可以說是一種虛擬化技術。通俗的理解就是一個高效能,Linux伺服器上
才能用的虛擬機器軟體。docker跟vmware虛擬機器區別:
docker:
Linux伺服器上才可以用,高效能,docker虛擬出來的虛擬機器只能是linux系統
vmware:
window版虛擬機器軟體,低效能,vmware可以虛擬出windows,linux,centos,unix等系統。
我們在企業用docker做什麼用?
使用docker進行部署,降低企業運營部署成本,基本實現零成本部署。
docker解決了部署的時候,同一臺機器軟體版本差異化造成的衝突問題。
docker對於硬體資源的管理,非常擅長,能更好的發揮每一臺機器的效能。

spring cloud和rpc框架的區別
Dubbo RPC:基於TCP或HTTP的遠端過程呼叫(就像在本地呼叫一樣),RPC強調的是遠端呼叫。
spring cloud:基於springboot,而springboot是基於HTTP協議REST風格的RPC。

對比:
1、協議:服務間通訊協議不同,Dubbo是基於TCP協議的rpc,spring cloud基於http協議。
2、RPC避免了上面提到的原生RPC帶來的問題。REST相比RPC更為靈活,SpringCloud不存在程式碼級別的強依賴
3、效率:由於協議的不同,呼叫的效率相比之下Dubbo比SpringCLoud效率高。
4、技術開放性:SpringCLoud基於http協議,由於http的協議更方便於多語言情況下的整合,提供服務方可以用任意語言開發服務。
5、spring cloud是微服務生態,包括完整的微服務相關的元件工具集,而RPC是遠端呼叫的技術,僅僅是微服務的一部分,而dubbo框架正是RPC的實現框架。
6、Spring Cloud還提供了包括Netflix Eureka、hystrix、feign、Spring Boot Admin 、Sleuth、config、stream、security、sleuth等分散式服務解決方案,而Dubbo為了擁抱融入Spring Cloud生態,Dubbo也在積極規劃和演進適配SpringCloud生態的新版本。

5、spring boot

一、熱部署

熱部署是指當我們修改程式碼後,服務能自動載入新修改的內容,這樣大大提高了 我們開發的效率,否則
每次都要手動重啟,這樣就比較耗時。

二、使用lombok

在之前編寫的程式碼中,我們寫了很多bean,這裡面加了很多set、get方法,這些方法冗餘,但卻也不可
缺少。可以使用lombok包,通過該工具,就不用在bean原始碼中手動新增set、get方法了,除此之外
equals、hashcode、toString方法也無需手動在原始碼中添加了。

三、什麼是SpringBoot?

SpringBoot是Spring開源組織下的子專案,是Spring元件一站式解決方案,主要是簡化了使用Spring的
難度,簡省了繁重的配置,提供了各種啟動器,開發者能快速上手。

四、SpringBoot有哪些有哪些優點?

1.減少開發,測試時間和努力
2.使用JavaConfig有助於避免使用XML
3.避免大量的Maven匯入和各種版本衝突。

五、SpringBoot的核心配置檔案有哪幾個?它們的區別是什麼?

SpringBoot的核心配置檔案是application和bootstrap配置檔案
application:主要用於Spring Boot專案的自動化配置。
@Controller
@ResponseBody
@RestController

六、SpringBoot的配置檔案有哪幾種格式?它們有什麼區別?

.properties和.yml,它們的區別主要是書寫格式不同。

七、Spring Boot的核心註解是哪個?它主要由哪幾個註解組成的?

@SpringBootApplication是SpringBoot的核心註解,主要組合包含了以下3個註解:
1.@SpringBootConfiguration:組合了@Configuration註解,實現配置檔案的功能。
2.@EnableAutoConfiguration:開啟自動配置的功能,也可以關閉某個自動配置的選項,如關閉資料
源自動配置功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
3.@ComponentScan:Spring元件掃描

八、開啟Spring Boot特性有哪幾種方式?

1.繼承spring-boot-start-parent專案
2.匯入spring-boot-dependencies專案依賴

九、Spring Boot需要獨立的容器執行嗎?

可以不需要,內建了Tomcat/Jetty等容器。

十、執行SpringBoot有哪幾種方式?

1、打包用命令或者放到容器中執行。
2、用Maven/Gradle外掛執行。
3.直接執行main方法。

十一、SpringBoot自動配置原理是什麼?

註解@EnableAutoConfiguration,@Configuration,@ConditionalOnClass就是自動配置的核心,首先
它得是一個配置檔案,其次根據類路徑下是否有這個類去自動配置。

十二、SpringBoot實現分頁和排序

使用Spring Data-JPA可以實現將可分頁的org.springframework.data.domain.Pageable傳遞給儲存庫
方法。

十三、如何實現Spring Boot應用程式的安全性?

使用spring-boot-starter-security依賴項,並且必須新增安全配置。

十四、如何整合Spring Boot和ActiveMQ?

使用spring-boot-start-activemq依賴關係。它只需要很少的配置,並且不需要樣板程式碼。

十五、SpringBoot中的監視器是什麼?

Spring boot actuator是spring啟動框架中的重要功能之一。spring boot監視器可幫助您訪問生產環境
中正在執行 的應用程式的當前狀態。

十六、什麼是Swagger?你用Spring Boot實現了它嗎?

Swagger是用於生成Restful Web服務的視覺化表示的工具,規範和完整框架實現。它使文件能夠以與
伺服器相同的速度更新。

十七、如何使用Spring Boot實現異常處理?

Spring提供了一種使用ControllerAdvice處理異常的非常有用的方法。我們通過實現一個
ControlerAdvice類,來處理控制器類丟擲的所有異常。

十八、RequestMapping和GetMapping的不同之處在哪裡?

RequestMapping具有類屬性的,可以進行GET\POST\PUT或者其它的註釋中具有的請求方法
GetMapping是GET請求方法中的一個特例。它只是RequestMapping的一個延伸,目的是為了提高清
晰度。

十九、Spring Boot可以相容老Spring專案嗎?如何做?

可以相容,使用@ImportResource註解匯入老Spring專案配置檔案。

二十、包含Spring boot應用有哪些方法?

在生產中使用Https使用Snyk檢查你的依賴關係
升級到最新版本
啟用CSRF保護
使用內容安全策略防止XSS攻擊。

1.關於快取
快取和CDN:CDN是內容分發網路,其實,可以把它看做是一個內容快取伺服器,不同的運營商,自己使用的CDN(快取策略)是不一樣的。我們將訪問的資源存放在離我們最近的CDN伺服器上,通過HTTP協議中的cache-contol:max-age來設定快取時間。當我們下次訪問同一資源的時候,通過判斷快取資料是否過期來判斷是否重新向源站發出請求。
3.斷點續傳以及多執行緒下載
請求時設定了一個請求頭range的範圍,伺服器響應Accept-Range欄位表示是否接受斷點續傳,content-Range返回接受的範圍即檔案大小,進行判斷後,返回請求的範圍資料,及響應碼。

6、計算機網路

計算機網路七層模型
應用層(資料)、表示層(資料)、會話層(資料)、傳輸層(資料報文)、網路層 (資料分組)、資料鏈路層 (幀)、物理層 (位元)

TCP/IP四層模型
應用層 :應用程序 ->檔案傳輸協議(FTP)、域名服務(DNS)、超文字傳輸協議(HTTP)
傳輸層:TCP /UDP
網路層:ICMP/IGMP/ARP/RARP/IP 網路協議 IP
網路介面層:網路介面

1.Http和Https的區別
Http協議執行在TCP之上,明文傳輸,客戶端和伺服器都無法驗證對方的身份;Https運行於SSL之上,SSL運行於TCP之上,是添加了加密和認證機制的Http
埠不同:http和https使用不同的連線方式,用的埠也不一樣,前者是80埠,後者是443埠;
資源消耗不同:和http通訊相比,https通訊會由於加減密處理消耗更多的CPU和記憶體資源;
開銷:https通訊需要證書,而證書一般需要向認證機構購買。
https的加密機制是一種共享金鑰加密和公開加密並用的混合加密機制。

2.對稱加密與非對稱加密
對稱加密是指加密和解密使用同一個金鑰的方式,這種方式存在的最大的問題就是金鑰傳送問題,即如
何安全的將金鑰發給對方;而非對稱加密是指使用一對非對稱金鑰,即公鑰和私鑰,公鑰可以隨意發
布,但私鑰只有自己知道。傳送密文的一方使用對方的公鑰進行加密處理,對方接收到加密資訊,使用
自己的私鑰進行解密。

3.三次握手和四次揮手

tcp的幾個狀態:

複製程式碼
1 2 3 4 5 SYN表示建立連線, FIN表示關閉連線, ACK表示響應, PSH表示有資料傳輸, RST表示連線重置!

(1)三次握手(我要和你建立連線,你真的要和我建立連線麼,我真的要和你建立連線,成功):
1.第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client
進入syn_sent狀態,等待Server確認。
2.第二次握手:Server收到資料包後由標誌位SYN=1知道Client請求建立連線,Server將標誌位SYN和
ACK都置為1,ack=J+1,隨機產生一個值seq=K,並將該資料包傳送給Client以確認連線請求,Server進
入syn_rcvd狀態。
3.第三次握手:Client收到確認後,檢查ack=J+1,ACK是否為1,如果正確則將標誌位ACK為1,
ack=K+1,並將該資料包傳送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連線建
立成功,Client和Server進入established狀態,完成三次握手,隨後Client和Server之間可以開始傳輸
資料了。

(2)四次揮手(我要和你斷開連線;好的,斷吧。我也要和你斷開連線;好的,斷吧)
第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送,Client進入fin_wait_1狀態。
第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個
FIN佔用一個序號),Server進入Close_wait狀態。此時TCP連線處於半關閉狀態,即客戶端已經沒有要
傳送的資料了,但服務端若傳送資料,則客戶端仍要接收。
第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送,Server進入Last_ack狀態。
第四次揮手:Client收到FIN後,Client進入Time_wait狀態,接著傳送一個ACK給Server,確認序號為
收到序號+1,Server進入Closed狀態,完成四次揮手。

4.域名系統(服務)協議(DNS)是一種分散式網路目錄服務,主要用於域名與 IP 地址的相互轉換,以及控制因特網的電子郵件的傳送。

5.子網掩碼:是一種用來指明一個IP地址的哪些位標識的是主機所在的子網,以及哪些位標識的是主機的位掩碼,子網掩碼只有一個作用,就是將某個IP地址劃分成網路地址和主機地址兩部分

6.閘道器:閘道器又稱網間聯結器、協議轉換器。閘道器在網路層以上實現網路互連,是複雜的網路互連裝置,僅用於兩個高層協議不同的網路互連。閘道器既可以用於廣域網互連,也可以用於區域網互連。 閘道器是一種充當轉換重任的計算機系統或裝置。

7、TCP與UDP區別總結:

1、TCP面向連線(如打電話要先撥號建立連線);UDP是無連線的,即傳送資料之前不需要建立連線

2、TCP提供可靠的服務。通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付

3、UDP具有較好的實時性,工作效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。

4、每一條TCP連線只能是點到點的;UDP支援一對一,一對多,多對一和多對多的互動通訊

5、TCP對系統資源要求較多,UDP對系統資源要求較少。

7、Java基礎

● int和Integer有什麼區別?

為了程式設計的方便還是引入了基本資料型別,但是為了能夠將這些基本資料型別當成物件操作,Java為每一個基本資料型別都引入了對應的包裝型別(wrapper class),int的包裝類就是Integer,從Java 5開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換。

Java 提供兩種不同的型別:引用型別和原始型別(或內建型別)。Int是java的原始資料型別,Integer是java為int提供的封裝類。
- 原始型別: boolean,char,byte,short,int,long,float,double
- 包裝型別:Boolean,Character,Byte,Short,Integer,Long,Float,Double

請你談談大O符號(big-O notation)並給出不同資料結構的例子

​ 大O符號描述了當資料結構裡面的元素增加的時候,演算法的規模或者是效能在最壞的場景下有多麼好。
大O符號也可用來描述其他的行為,比如:記憶體消耗。因為集合類實際上是資料結構,我們一般使用大O符號基於時間,記憶體和效能來選擇最好的實現。大O符號表示一個程式執行時所需要的漸進時間複雜度上界。

● 請你解釋什麼是值傳遞和引用傳遞?

值傳遞是對基本型變數而言的,傳遞的是該變數的一個副本,改變副本不影響原變數.
引用傳遞一般是對於物件型變數而言的,傳遞的是該物件地址的一個副本, 並不是原物件本身 。 所以對引用物件進行操作會同時改變原物件.一般認為java內的傳遞都是值傳遞.

請你說說Lamda表示式的優缺點。

優點:1. 簡潔。2. 非常容易平行計算。3. 可能代表未來的程式設計趨勢。

缺點:1. 若不用平行計算,很多時候計算速度沒有比傳統的 for 迴圈快。(平行計算有時需要預熱才顯示出效率優勢)2. 不容易除錯。3. 若其他程式設計師沒有學過 lambda 表示式,程式碼不容易讓其他語言的程式設計師看懂。

● 你知道java8的新特性嗎,請簡單介紹一下

Lambda 表示式 − Lambda允許把函式作為一個方法的引數

方法引用− 方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼。

預設方法− 預設方法就是一個在接口裡面有了一個實現的方法。

新工具− 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。

==與equlas有什麼區別?

==

  • 如果是基本型別,判斷它們值是否相等;
  • 如果是引用物件,判斷兩個物件指向的記憶體地址是否相同。

equals

  • 如果是字串,表示判斷字串內容是否相同;
  • 如果是object物件的方法,比較的也是引用的記憶體地址值;
  • 如果自己的類重寫equals方法,可以自定義兩個物件是否相等。

final關鍵字

當用final修飾一個類時,表明這個類不能被繼承。“使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。

對於一個final變數,如果是基本資料型別的變數,則其數值一旦在初始化之後便不能更改;如果是引用型別的變數,則在對其初始化之後便不能再讓其指向另一個物件。

● 介面和抽象類的區別是什麼?

Java提供和支援建立抽象類和介面。它們的實現有共同點,不同點在於:
介面中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法
類可以實現很多個介面,但是隻能繼承一個抽象類
類可以不實現抽象類和介面宣告的所有方法,當然,在這種情況下,類也必須得宣告成是抽象的。
抽象類可以在不提供介面方法實現的情況下實現介面。
Java介面中宣告的變數預設都是final的。抽象類可以包含非final的變數。
Java介面中的成員函式預設是public的。抽象類的成員函式可以是private,protected或者是public。
介面是絕對抽象的,不可以被例項化。抽象類也不可以被例項化,如果它包含main方法的話是可以被呼叫的。

● 請你說說Iterator和ListIterator的區別?
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以後向。
ListIterator實現了Iterator介面,幷包含其他的功能:增加元素,替換元素,獲取前一個和後一個元素的索引

● 請問什麼是java序列化?以及如何實現java序列化?

序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化。可以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。序列化是為了解決在對物件流進行讀寫操作時所引發的問題。

java記憶體模型(Java Memory Model)是java虛擬機器規範定義的,用來遮蔽掉java程式在各種不同的硬體和作業系統對記憶體的訪問的差異,這樣就可以實現java程式在各種不同的平臺上都能達到記憶體訪問的一致性。可以避免像c++等直接使用物理硬體和作業系統的記憶體模型在不同作業系統和硬體平臺下表現不同,比如有些c/c++程式可能在windows平臺執行正常,而在linux平臺卻執行有問題。

8、web

● 請談一談JSP有哪些內建物件?以及這些物件的作用分別是什麼?

JSP有9個內建物件:

  • request:封裝客戶端的請求,其中包含來自GET或POST請求的引數;
  • response:封裝伺服器對客戶端的響應;
  • pageContext:通過該物件可以獲取其他物件;
  • session:封裝使用者會話的物件;
  • application:封裝伺服器執行環境的物件;
  • out:輸出伺服器響應的輸出流物件;
  • config:Web應用的配置物件;
  • page:JSP頁面本身(相當於Java程式中的this);
  • exception:封裝頁面丟擲異常的物件。

● 請簡要說明一下JSP和Servlet有哪些相同點和不同點?另外他們之間的聯絡又是什麼呢?

JSP 是Servlet技術的擴充套件,本質上是Servlet的簡易方式,更強調應用的外表表達。JSP編譯後是”類servlet”。Servlet和JSP最主要的不同點在於,Servlet的應用邏輯是在Java檔案中,並且完全從表示層中的HTML裡分離開來。而JSP的情況是Java和HTML可以組合成一個副檔名為.jsp的檔案。JSP側重於檢視,Servlet主要用於控制邏輯

Netty和Tomcat

最大的區別就在於通訊協議,Tomcat是基於Http協議的,他的實質是一個基於http協議的web容器,但是Netty不一樣,他能通過程式設計自定義各種協議,因為netty能夠通過codec自己來編碼/解碼位元組流,完成類似redis訪問的功能,這就是netty和tomcat最大的不同。

● 請談談你對Javaweb開發中的***的理解?

***模型涉及以下三個物件,

(1)事件:使用者對元件的一個操作,稱之為一個事件
(2)事件源:發生事件的元件就是事件源
(3)事件***(處理器):監聽並負責處理事件的方法

執行順序:

1、給事件源註冊***
2、元件接受外部作用,也就是事件被觸發
3、元件產生一個相應的事件物件,並把此物件傳遞給與之關聯的事件處理器
4、事件處理器啟動,並執行相關的程式碼來處理該事件。

● 請問過濾器有哪些作用?以及過濾器的用法又是什麼呢?

過濾器(filter)是從Servlet 2.3規範開始增加的功能,對Web應用來說,過濾器是一個駐留在伺服器端的Web元件,它可以擷取客戶端和伺服器之間的請求與響應資訊,並對這些資訊進行過濾。當Web容器接受到一個對資源的請求時,它將判斷是否有過濾器與這個資源相關聯。如果有,那麼容器將把請求交給過濾器進行處理。在過濾器中,你可以改變請求的內容,或者重新設定請求的報頭資訊,然後再將請求傳送給目標資源。

● 請回答一下servlet的生命週期是什麼。servlet是否為單例以及原因是什麼?

Servlet 通過呼叫 init () 方法進行初始化。

Servlet 呼叫 service() 方法來處理客戶端的請求。

Servlet 通過呼叫 destroy() 方法終止(結束)。

最後,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。

Servlet單例項,減少了產生servlet的開銷;

● 請你說說,cookie 和 session 的區別?

1、cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。

2、cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙,考慮到安全應當使用session。

3、session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能,考慮到減輕伺服器效能方面,應當使用COOKIE。

4、單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。

● 說說你對get和post請求,並且說說它們之間的區別?

①get請求用來從伺服器上獲得資源,而post是用來向伺服器提交資料
②get將表單中資料按照name=value的形式,新增到action 所指向的URL 後面,並且兩者使用"?"連線,而各個變數之間使用"&"連線;post是將表單中的資料放在HTTP協議的請求頭或訊息體中,傳遞到action所指向URL;
③get傳輸的資料要受到URL長度限制(1024位元組);post可以傳輸大量的資料,上傳檔案通常要使用post方式;
④使用get時引數會顯示在位址列上,如果這些資料不是敏感資料可以使用get;對於敏感資料還是應用使用post;

● 請談談,轉發和重定向之間的區別?

forward是容器中控制權的轉向,是伺服器請求資源,伺服器直接訪問目標地址的URL,把那個URL 的響應內容讀取過來,然後把這些內容再發給瀏覽器,瀏覽器根本不知道伺服器傳送的內容是從哪兒來的,所以它的位址列中還是原來的地址。

redirect就是伺服器端根據邏輯,傳送一個狀態碼,告訴瀏覽器重新去請求那個地址,因此從瀏覽器的位址列中可以看到跳轉後的連結地址,很明顯redirect無法訪問到伺服器保護起來資源,但是可以從一個網站redirect到其他網站。forward更加高效,在有些情況下,比如需要訪問一個其它伺服器上的資源,則必須使用重定向

解決session共享問題

方法一、使用Nginx讓它繫結ip,配置Nginx。

方法二、使用spring session+redis的方法解決session共享問題

9、電商專案

1、跨域?

當一個資源去訪問另一個不同域名或者同域名不同埠的資源時,就會發出跨域請求。如果此時另一個資源不允許其進行跨域資源訪問,那麼訪問的那個資源就會遇到跨域問題。

因為跨域問題是瀏覽器對於ajax請求的一種安全限制:一個頁面發起的ajax請求,只能是於當前頁同域名的路徑,這能有效的阻止跨站攻擊。

2、非同步查詢工具axios

非同步查詢資料,自然是通過ajax查詢,大家首先想起的肯定是jQuery。但jQuery與MVVM的思想不吻合

3、解決跨域問題的方案

Jsonp:最早的解決方案,利用script標籤可以跨域的原理實現。缺點:需要服務的支援、只能發起GET請求

nginx反向代理:利用nginx反向代理把跨域為不跨域,支援各種請求方式。缺點:需要在nginx進行額外配置

CORS(跨域資源共享):規範化的跨域請求解決方案,安全可靠。

優勢:在服務端進行控制是否允許跨域,可自定義規則、支援各種請求方式

缺點:會產生額外的請求

同源策略

是瀏覽器的安全策略。是一種約定,是瀏覽器最核心最基本的安全功能。如果沒有同源策略,瀏覽器很容易收到XSS,CSRF攻擊。保證使用者資訊保安,防止惡意網站竊取資料

同源指“協議+域名(主機)+埠”三者相同。任一不同,都屬於非同源。即使不同域名對應同一IP地址也非同源。

4、服務治理(SOA)

​ 當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基於訪問壓力實時管理叢集容量,提高叢集利用率。此時,用於提高機器利用率的資源排程和治理中心(SOA)是關鍵

服務治理要做什麼?

  • 服務註冊中心,實現服務自動註冊和發現,無需人為記錄服務地址
  • 服務自動訂閱,服務列表自動推送,服務呼叫透明化,無需關心依賴關係
  • 動態監控服務狀態監控報告,人為控制服務狀態

5、遠端呼叫方式

無論是微服務還是SOA,都面臨著服務間的遠端呼叫。常見的遠端呼叫方式有以下幾種:

  • RPC:Remote Produce Call遠端過程呼叫,類似的還有RMI。自定義資料格式,基於原生TCP通訊,速度快,效率高。早期的webservice,現在熱門的dubbo,都是RPC的典型

  • Http:http其實是一種網路傳輸協議,基於TCP,規定了資料傳輸的格式。現在客戶端瀏覽器與服務端通訊基本都是採用Http協議。也可以用來進行遠端服務呼叫。缺點是訊息封裝臃腫。

    現在熱門的Rest風格,就可以通過http協議來實現。

微服務,更加強調的是獨立、自治、靈活。而RPC方式的限制較多,因此微服務框架中,一般都會採用基於Http的Rest風格服務。

6、Nginx

nginx可以作為web伺服器,但更多的時候,我們把它作為閘道器,因為它具備閘道器必備的功能:

反向代理、負載均衡、動態路由、請求過濾。

Web伺服器分2類:

  • web應用伺服器,如:tomcat、resin、jetty
  • web伺服器,如:Apache 伺服器、Nginx、IIS

區分:web伺服器不能解析jsp等頁面,只能處理js、css、html等靜態資源。
併發:web伺服器的併發能力遠高於web應用伺服器。

nginx作為反向代理

什麼是反向代理?

  • 代理:通過客戶機的配置,實現讓一臺代理伺服器代理客戶機,客戶的所有請求都交給代理伺服器
  • 反向代理:用一臺伺服器,代理真實伺服器,使用者訪問時,不再是訪問真實伺服器,而是代理伺服器。

nginx可以當做反向代理伺服器來使用:

  • 我們需要提前在nginx中配置好反向代理的規則,不同的請求,交給不同的真實伺服器處理
  • 當請求到達nginx,nginx會根據已經定義的規則進行請求的轉發,從而實現路由功能
  • 利用反向代理,就可以解決我們前面所說的埠問題

10、資料結構與演算法

1、雜湊

HashMap的底層實現

  • 底層由連結串列+陣列實現
  • 可以儲存null鍵和null值
  • 線性不安全
  • 初始容量為16,擴容每次都是2的n次冪(保證位運算)
  • 載入因子為0.75,當Map中元素總數超過Entry陣列的0.75,觸發擴容操作.
  • 併發情況下,HashMap進行put操作會引起死迴圈,導致CPU利用率接近100%

HashMap底層是陣列和連結串列的結合。HashMap通過key的HashCode經過擾動函式處理過後得到Hash
值,然後通過位運算判斷當前元素存放的位置,如果當前位置存在元素的話,就判斷該元素與要存入的元素的hash值以及key是否相同,如果相同的話,直接覆蓋,不相同就通過拉鍊法解決衝突。當Map中的元素總數超過Entry陣列的0.75時,觸發擴容操作,為了減少連結串列長度,元素分配更均勻。

HashMap基於雜湊思想,實現對資料的讀寫。當我們將鍵值對傳遞給put()方法時,它呼叫 鍵物件的hashCode()方法來計算hashcode,然後後找到bucket位置來儲存值物件。當獲取物件時,通過鍵物件的equals()方法找到正確的鍵值對,然後返回值物件。HashMap使用連結串列 來解決碰撞問題,當發生碰撞了,物件將會儲存在連結串列的下一個節點中。HashMap在每個 連結串列節點中儲存鍵值對物件。當兩個不同的鍵物件的hashcode相同時,它們會儲存在同一個 bucket位置的連結串列中,可通過鍵物件的equals()方法用來找到鍵值對。如果連結串列大小超過閾 值( 8),連結串列就會被改造為樹形結構。
————————————————rehash解決多次擴容後資料分配問題

JDK1.8 以後在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為 8)時,將連結串列轉化為紅黑樹,以減少搜尋時間。 (一個是連結串列的長度達到8個,一個是陣列的長度達到64個)

那為什麼選擇8才會選擇使用紅黑樹

為了配合使用分佈良好的hashCode,樹節點很少使用。並且在理想狀態下,受隨機分佈的hashCode影響,連結串列中的節點遵循泊松分佈,而且根據統計,連結串列中節點數是8的概率已經接近千分之一,而且此時連結串列的效能已經很差了。所以在這種比較罕見和極端的情況下,才會把連結串列轉變為紅黑樹。因為連結串列轉換為紅黑樹也是需要消耗效能的,特殊情況特殊處理,為了挽回效能,權衡之下,才使用紅黑樹,提高效能。也就是大部分情況下,hashmap還是使用的連結串列,如果是理想的均勻分佈,節點數不到8,hashmap就自動擴容

雜湊衝突:如果兩個不同物件的hashCode相同,這種現象稱為hash衝突。

有以下的方式可以解決雜湊衝突:

  • 開放定址法
  • 再雜湊法
  • 鏈地址法
  • 建立公共溢位區

● 請你說明HashMap和Hashtable的區別?

HashMap和Hashtable都實現了Map介面,因此很多特性非常相似。但是,他們有以下不同點:
HashMap允許鍵和值是null,而Hashtable不允許鍵或者值是null。
Hashtable是同步的,而HashMap不是。HashMap更適合於單執行緒環境,而Hashtable適合於多執行緒環境。
HashMap提供了可供應用迭代的鍵的集合,因此,HashMap是快速失敗的。

HashMap和TreeMap的區別
HashMap:陣列方式儲存key/value,執行緒非安全,允許null作為key和value,key不可以重複,value
允許重複,不保證元素迭代順序是按照插入時的順序,key的hash值是先計算key的hashcode值,然後
再進行計算,每次擴容會重新計算key的hash值,會消耗資源,要求key必須重寫equals和hashcode方
法。它預設初始容量為16,載入因子0.75,擴容為舊容量的2倍,查詢元素快,如果key一樣則比較value,
如果value不一樣,則按照連結串列結構儲存value,就是一個key後面有多個value
TreeMap:基於紅黑樹的NavigableMap實現,執行緒非安全,不允許null,key不可以重複,value允許重
復,存入TreeMap的元素應當實現Comparable介面或者實現Comparator介面,會按照排序後的順序
迭代元素,兩個相比較key不得丟擲classCastException。主要用於存入元素的時候對元素進行自動排
序,迭代輸出的時候就按照排序順序輸出。

● 請你說明一下TreeMap的底層實現?

TreeMap 的實現就是紅黑樹資料結構,一棵自平衡的排序二叉樹,這樣就可以保證當需要快速檢索指定節點

紅黑樹的插入、刪除、遍歷時間複雜度都為O(lgN),所以效能上低於雜湊表。但是雜湊表無法提供鍵值對的有序輸出,紅黑樹因為是排序插入的,可以按照鍵的值的大小有序輸出。紅黑樹性質:

2、樹

紅黑樹的性質:

1.節點是紅色或黑色。

2.根節點是黑色。

3.每個葉子節點都是黑色的空節點(NIL節點)。

4 每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)

5.從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

平衡二叉樹的性質:

它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。這個方案很好的解決了二叉查詢樹退化成連結串列的問題,把插入,查詢,刪除的時間複雜度最好情況和最壞情況都維持在O(logN)。但是頻繁旋轉會使插入和刪除犧牲掉O(logN)左右的時間,不過相對二叉查詢樹來說,時間上穩定了很多。

區別:

1、紅黑樹放棄了追求完全平衡,追求大致平衡,在與平衡二叉樹的時間複雜度相差不大的情況下,保證每次插入最多隻需要三次旋轉就能達到平衡,實現起來也更為簡單。

2、平衡二叉樹追求絕對平衡,條件苛刻,實現起來比較麻煩,每次插入新節點之後需要旋轉的次數不能預知。

4、連結串列

● 請說明ArrayList和LinkedList的區別?

ArrayList和LinkedList都實現了List介面,他們有以下的不同點:
ArrayList是基於索引的資料介面,它的底層是陣列。它可以以O(1)時間複雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式儲存它的資料,每一個元素都和它的前一個和後一個元素連結在一起,在這種情況下,查詢某個元素的時間複雜度是O(n)。
相對於ArrayList,LinkedList的插入,新增,刪除操作速度更快,因為當元素被新增到集合任意位置的時候,不需要像陣列那樣重新計算大小或者是更新索引。
LinkedList比ArrayList更佔記憶體,因為LinkedList為每一個節點儲存了兩個引用,一個指向前一個元素,一個指向下一個元素。

● 請你講講陣列(Array)和列表(ArrayList)的區別?什麼時候應該使用Array而不是ArrayList?

Array可以包含基本型別和物件型別,ArrayList只能包含物件型別。

Array大小是固定的,ArrayList的大小是動態變化的。

ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

對於基本型別資料,集合使用自動裝箱來減少編碼工作量。但是,當處理固定大小的基本資料型別的時候,這種方式相對比較慢。

5、陣列

6、排序

7、堆與棧

8、佇列

9、高階演算法

11、分散式

分散式鎖的幾種常用實現方式

分散式的CAP理論告訴我們“任何一個分散式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分割槽容錯性(Partition tolerance),最多隻能同時滿足兩項。”所以,很多系統在設計之初就要對這三者做出取捨。在網際網路領域的絕大多數的場景中,都需要犧牲強一致性來換取系統的高可用性

針對分散式鎖的實現,目前比較常用的有以下幾種方案:

  • 基於資料庫實現分散式鎖:核心思想是在資料庫中建立一個表,表中包含方法名等欄位,並在方法名欄位上建立唯一索引,想要執行某個方法,就使用這個方法名向表中插入資料,成功插入則獲取鎖,執行完成後刪除對應的行資料釋放鎖。

  • 基於快取實現分散式鎖:實現思想:

    (1)獲取鎖的時候,使用setnx加鎖,並使用expire命令為鎖新增一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

    (2)獲取鎖的時候還設定一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

    (3)釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。

  • 基於Zookeeper實現分散式鎖

    ZooKeeper是一個為分散式應用提供一致***的開源元件,它內部是一個分層的檔案系統目錄樹結構,規定同一個目錄下只能有一個唯一檔名。(1)建立一個目錄mylock;
    (2)執行緒A想獲取鎖就在mylock目錄下建立臨時順序節點;
    (3)獲取mylock目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前執行緒順序號最小,獲得鎖;
    (4)執行緒B獲取所有節點,判斷自己不是最小節點,設定監聽比自己次小的節點;
    (5)執行緒A處理完,刪除自己的節點,執行緒B監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

什麼是分散式檔案系統:
1、傳統檔案系統管理的檔案就儲存在本機。
2、分散式檔案系統管理的檔案儲存在很多機器,這些機器通過網路連線,要被統一管理。無論是上傳
或是訪問檔案,都需要通過管理中心來訪問。
功能豐富:
檔案儲存、檔案同步、檔案訪問、存取負載均衡、線上擴容
適合有大容量儲存需求的應用或系統。
FastDFS兩個主要的角色:Tracker Server和Storage Server
Tracker Server:跟蹤伺服器,主要負責排程storage節點與client通訊,在訪問上起負載均衡的作用,
和記錄storage節點的允許狀態,是連線client和storage節點的樞紐。
Storage Server:儲存伺服器,儲存檔案和檔案的meta data(元資料),每個storage server會啟動一
個單獨的執行緒主動向Tracker cluster中每個tracker server報告其狀態資訊,包括磁碟使用情況,檔案同
步情況及檔案上傳下載次數統計等資訊。
Group:檔案組,多臺Strage Server的叢集。上傳一個檔案到同組內的一臺機器上後,FastDFS會將該
檔案即時同步到同組內的其它所有機器上,起到備份的作用。不同組的伺服器,儲存的資料不同,而且
相互獨立,不進行通訊。
Tracker Cluster:跟蹤伺服器的叢集,有一組Tracker Server(跟蹤伺服器)組成。
Storage Cluster:儲存叢集,有多個Group組成。
FastDFS上傳和下載流程
上傳:
1.Client通過Tracker server查詢可用的Storage server。
2.Tracker server向Client返回一臺可用的Storage server的IP地址和埠號。
3.Client通過Tracker server返回的IP地址和埠與其中一臺Storage server建立連線並進行檔案上傳。
4.上傳完成,Storage server返回Client一個檔案ID,檔案上傳結束。
下載:
1.Client通過Trackerserver查詢要下載檔案所在的Storage server。
2.Tracker server向Client返回包含指定檔案的某個Storage server的IP地址和埠號。
3.Client直接通過Tracker server返回的IP地址和埠與其中一臺Storage server建立連線並指定要下載
檔案。
4.下載檔案成功。

為什麼要使用RPC?組成部分?

在一個典型RPC的使用場景中,包含了服務發現、負載、容錯、網路傳輸、序列化等元件,而RPC的主要目標是更容易地構建分散式應用。為實現該目標,RPC框架需提供一種透明呼叫機制,讓使用者不必顯式的區分本地呼叫和遠端呼叫。

1 、服務定址2 、序列化和反序列化3 、網路傳輸

12、Linux

部署專案用到的linux命令:

1.進入tomcat的bin目錄 cd /data/apache-tomcat-6.0.39/bin

2.檢視tomcat的程序 ps -ef | grep tomcat

3.殺死程序 kill -9 + 程序數

檢視程序 2.1、ps -ef | grep xx 2.2、ps -aux | grep xxx(-aux顯示所有狀態)

檢視埠:1、netstat -anp | grep 埠號(狀態為LISTEN表示被佔用)

4.啟動專案 sh startup.sh

5.永久刪除檔案 rm -rf 檔案

6.複製檔案 cp -Rf 原路徑/ 目的路徑/

7.壓縮資料夾

解壓:tar zxvf FileName.tar.gz
壓縮:tar zcvf FileName.tar.gz DirName

8.解壓(安裝zip命令)* unzip 壓縮包

9.移動 mv +路徑/檔案 +要移到的路徑

9.從本機複製檔案到遠端 scp -r ROOT [email protected]:/data/apache-tomcat-6.0.39/webapps

scp -r 目錄名 遠端計算機使用者名稱@遠端計算機的ip:遠端計算機存放該目錄的路徑

13、併發程式設計

程序與執行緒的區別:

1、程序是資源分配的最小單位,執行緒是程式執行的最小單位(資源排程的最小單位)
2、程序有自己的獨立地址空間,每啟動一個程序,系統就會為它分配地址空間, 而執行緒是共享程序中的資料、地址空間
3、執行緒之間的通訊更方便,同一程序下的執行緒共享全域性變數、靜態變數等資料,而程序之間的通訊需要以通訊的方式(IPC)進行。
4、多程序程式更健壯,多執行緒程式只要有一個執行緒死掉,整個程序也死掉了,而一個程序死掉並不會對另外一個程序造成影響,因為程序有自己獨立的地址空間。

● 如何保證執行緒安全?

通過合理的時間排程,避開共享資源的存取衝突。另外,在並行任務設計上可以通過適當的策略,保證任務與任務之間不存在共享資源

● 執行緒同步和執行緒排程的相關方法。

- wait():使一個執行緒處於等待狀態,並且釋放所持有的物件的鎖;

- sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫此方法要處理異常;

- notify():喚醒一個處於等待狀態的執行緒,當然在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,而是由JVM確定喚醒哪個執行緒,而且與優先順序無關;

- notityAll():喚醒所有處於等待狀態的執行緒,該方法並不是將物件的鎖給所有執行緒,而是讓它們競爭,只有獲得鎖的執行緒才能進入就緒狀態;

*● Java中有幾種方法可以實現一個執行緒?用什麼關鍵字修飾同步方法? *

有四種實現方法,分別是繼承Thread類與實現Runnable介面,使用Callable和Future建立執行緒、使用執行緒池例如用Executor框架。

● 啟動一個執行緒是用run()還是start()?

啟動一個執行緒是呼叫start()方法,使執行緒所代表的虛擬處理機處於可執行狀態,這意味著它可以由JVM排程並執行。這並不意味著執行緒就會立即執行。run()方法可以產生必須退出的標誌來停止一個執行緒。

● 請說明一下sleep() 和 wait() 有什麼區別?

sleep是執行緒類(Thread)的方法,導致此執行緒暫停執行指定時間,把執行機會給其他執行緒,但是監控狀態依然保持,到時後會自動恢復。呼叫sleep不會釋放物件鎖。
wait是Object類的方法,對此物件呼叫wait方法導致本執行緒放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件發出notify方法(或notifyAll)後本執行緒才進入物件鎖定池準備獲得物件鎖進入執行狀態。

● 請分析一下同步方法和同步程式碼塊的區別是什麼?

區別:同步方法預設用this或者當前類class物件作為鎖;

同步程式碼塊可以選擇以什麼來加鎖,比同步方法要更細顆粒度,可以選擇只同步會發生同步問題的部分程式碼而不是整個方法。

● 請詳細描述一下執行緒從建立到死亡的幾種狀態都有哪些?

  1. 新建( new ):新建立了一個執行緒物件。

  2. 可執行( runnable ):執行緒物件建立後,其他執行緒(比如 main 執行緒)呼叫了該物件 的 start ()方法。該狀態的執行緒位於可執行執行緒池中,等待被執行緒排程選中,獲取 cpu 的使用權 。

  3. 執行( running ):可執行狀態( runnable )的執行緒獲得了 cpu 時間片( timeslice ) ,執行程式程式碼。

  4. 阻塞( block ):阻塞狀態是指執行緒因為某種原因放棄了 cpu 使用權,阻塞的情況分三種: 等待阻塞、同步阻塞、其他阻塞:

  5. 死亡( dead ):執行緒 run ()、 main () 方法執行結束,或者因異常退出了 run ()方法,則該執行緒結束生命週期。死亡的執行緒不可再次復生。

● 請問什麼是死鎖(deadlock)?

兩個執行緒或兩個以上執行緒都在等待對方執行完畢才能繼續往下執行的時候就發生了死鎖。結果就是這些執行緒都陷入了無限的等待中。如何避免執行緒死鎖?
只要破壞產生死鎖的四個條件中的其中一個就可以了。
破壞互斥條件:這個條件我們沒有辦法破壞,因為我們用鎖本來就是想讓他們互斥的(臨界資源需要互斥訪問)。
破壞請求與保持條件:一次性申請所有的資源。
破壞不剝奪條件:佔用部分資源的執行緒進一步申請其他資源時,如果申請不到,可以主動釋放它佔有的資源。
破壞迴圈等待條件:靠按序申請資源來預防。按某一順序申請資源,釋放資源則反序釋放

● JAVA中如何確保N個執行緒可以訪問N個資源,但同時又不導致死鎖?

使用多執行緒的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,並強制執行緒按照指定的順序獲取鎖。因此,如果所有的執行緒都是以同樣的順序加鎖和釋放鎖,就不會出現死鎖了。

常用執行緒池,執行緒池有哪幾個引數

Java通過Executors提供四種執行緒池,分別為:
1)newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
2)newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
3)newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。

4)newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

引數
corePoolSize :核心執行緒數量

maximumPoolSize :執行緒最大執行緒數

workQueue :阻塞佇列,儲存等待執行的任務 很重要 會對執行緒池執行產生重大影響

keepAliveTime :執行緒沒有任務時最多保持多久時間終止

unit :keepAliveTime的時間單位

threadFactory :執行緒工廠,用來建立執行緒

rejectHandler :當拒絕處理任務時的策略

執行緒池怎麼用

複製程式碼
1 2 ExecutorService cachePool = Executors.newCachedThreadPool(); cachePool.execute(getThread(i));

● Synchronized和lock

synchronized當它用來修飾一個方法或者一個程式碼塊的時候,能夠保證在同一時刻最多隻有一個執行緒執行該段程式碼。Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內建的語言實現;synchronized在發生異常時,會自動釋放執行緒佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成F死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;Lock可以讓等待鎖的執行緒響應中斷,而synchronized卻不行,使用synchronized時,等待的執行緒會一直等待下去,不能夠響應中斷;通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。

● Syncronized鎖,如果用這個關鍵字修飾一個靜態方法,鎖住了什麼?如果修飾成員方法,鎖住了什麼?

synchronized修飾靜態方法以及同步程式碼塊的synchronized (類.class)用法鎖的是類,執行緒想要執行對應同步程式碼,需要獲得類鎖。

synchronized修飾成員方法,執行緒獲取的是當前呼叫該方法的物件例項的物件鎖

synchronized 和 CAS 的區別

synchronized 採用的是 CPU 悲觀鎖機制,即執行緒獲得的是獨佔鎖, 其他執行緒只能依靠阻塞來等待執行緒釋放鎖。而在 CPU 轉換執行緒阻塞時會引起執行緒上下文切換,當有很多執行緒競爭鎖的時候,會引起 CPU 頻繁的上下文切換導致效率很低。儘管 Java1.6 為 synchronized 做了優化,增加了從偏向鎖到輕量級鎖再到重量級鎖的過度,但是在最終轉變為重量級鎖之後,效能仍然較低。

CAS 是比較並替換。它當中使用了3個基本運算元:記憶體地址 V,舊的預期值 A,要修改的新值 B。採用的是一種樂觀鎖的機制,它不會阻塞任何執行緒,所以在效率上,它會比 synchronized 要高。所謂樂觀鎖就是:每次不加鎖而是假設沒有衝突而去完成某項操作,如果因為衝突失敗就重試,直到成功為止。

所以,在併發量非常高的情況下,我們儘量的用同步鎖,而在其他情況下,我們可以靈活的採用 CAS 機制。

synchronized關鍵字和volatile關鍵字比較:

  • volatile關鍵字是執行緒同步的輕量級實現,所以volatile效能肯定比synchronized關鍵字要好。
  • 多執行緒訪問volatile關鍵字不會發生阻塞,而synchronized關鍵字可能會發生阻塞
  • volatile關鍵字能保證資料的可見性,但不能保證資料的原子性。synchronized關鍵字兩者都能保證。
  • volatile關鍵字主要用於解決變數在多個執行緒之間的可見性,而 synchronized關鍵字解決的是多個執行緒之間訪問資源的同步性。

執行緒池執行原理分析

1、建立一個執行緒池,在還沒有任務提交的時候,預設執行緒池裡面是沒有執行緒的。也可以呼叫prestartCoreThread方法,來預先建立一個核心執行緒。
2、執行緒池裡還沒有執行緒或者執行緒池裡存活的執行緒數小於核心執行緒數corePoolSize時,這時對於一個新提交的任務,執行緒池會建立一個執行緒去處理提交的任務。此時執行緒池裡面的執行緒會一直存活著,就算空閒時間超過了keepAliveTime,執行緒也不會被銷燬,而是一直阻塞在那裡一直等待任務佇列的任務來執行。
3、當執行緒池裡面存活的執行緒數已經等於corePoolSize了,對於一個新提交的任務,會被放進任務佇列workQueue排隊等待執行。而之前建立的執行緒並不會被銷燬,而是不斷的去拿阻塞佇列裡面的任務,當任務佇列為空時,執行緒會阻塞,直到有任務被放進任務佇列,執行緒拿到任務後繼續執行,執行完了過後會繼續去拿任務。這也是為什麼執行緒池佇列要是用阻塞佇列。
4、當執行緒池裡面存活的執行緒數已經等於corePoolSize了,並且任務佇列也滿了,這裡假設maximumPoolSize>corePoolSize(如果等於的話,就直接拒絕了),這時如果再來新的任務,執行緒池就會繼續建立新的執行緒來處理新的任務,知道執行緒數達到maximumPoolSize,就不會再建立了。這些新建立的執行緒執行完了當前任務過後,在任務佇列裡面還有任務的時候也不會銷燬,而是去任務佇列拿任務出來執行。在當前執行緒數大於corePoolSize過後,執行緒執行完當前任務,會有一個判斷當前執行緒是否需要銷燬的邏輯:如果能從任務佇列中拿到任務,那麼繼續執行,如果拿任務時阻塞(說明佇列中沒有任務),那超過keepAliveTime時間就直接返回null並且銷燬當前執行緒,直到執行緒池裡面的執行緒數等於corePoolSize之後才不會進行執行緒銷燬。
5、如果當前的執行緒數達到了maximumPoolSize,並且任務佇列也滿了,這種情況下還有新的任務過來,那就直接採用拒絕的處理器進行處理。預設的處理器邏輯是丟擲一個RejectedExecutionException異常。

● 請說明一下執行緒池有什麼優勢?

第一:降低資源消耗。第二:提高響應速度。第三:提高執行緒的可管理性

執行緒池的執行流程

首先判斷核心執行緒池裡的執行緒是否都在執行任務,如果不是則直接從核心執行緒池中建立一個執行緒來執行,如果都在忙則判斷任務佇列是否也滿了,沒滿的話將任務放進去等待執行,滿了就判斷執行緒池的全部執行緒是否都在忙,如果都在忙就交給飽和策略來處理,否則就建立一個執行緒來幫助核心執行緒處理任務。

執行緒阻塞

  • BIO,同步阻塞式IO,簡單理解:一個連線一個執行緒
  • NIO,同步非阻塞IO,簡單理解:一個請求一個執行緒
  • AIO,非同步非阻塞IO,簡單理解:一個有效請求一個執行緒

AQS原理

抽象的佇列式同步器,是除了java自帶的synchronized關鍵字之外的鎖機制,AQS的核心思想是,如果被請求的共享資源空閒,則將當前請求資源的執行緒設定為有效的工作執行緒,並將共享資源設定為鎖定狀態,如果被請求的共享資源被佔用,那麼就需要一套執行緒阻塞等待以及被喚醒時鎖分配的機制,這個機制AQS是用CLH佇列鎖實現的,即將暫時獲取不到鎖的執行緒加入到佇列中。
CLH佇列是一個虛擬的雙向佇列,虛擬的雙向佇列即不存在佇列例項,僅存在節點之間的關聯關係。
AQS是將每一條請求共享資源的執行緒封裝成一個CLH鎖佇列的一個結點(Node),來實現鎖的分配

14、JVM

主記憶體:多個執行緒共享的記憶體,方法區和堆屬於主記憶體區域。執行緒工作記憶體:每個執行緒獨享的記憶體。虛擬機器棧、本地方法棧、程式計數器屬於執行緒獨享的工作記憶體

Java建立物件的過程:

● JVM載入class檔案的原理是什麼?

JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader 是一個Java執行時系統元件。它負責在執行時查詢和裝入類檔案的類。

Java中的所有類都需要由類載入器裝載到JVM中才能執行。類載入器的工作就是把class檔案從硬碟讀取到記憶體中。

雙親委派機制:

如果一個類載入器收到了類載入請求,他並不會自己先去載入,而是把這個請求委託給父類的載入器去執行;

如果父類載入器還存在其父類載入器,則進一步向上委託,依次遞迴,請求最終達到頂層的啟動類載入器

如果父類載入器可以完成類載入任務就成功返回,如果父類載入器不能完成載入任務,子載入器互嘗試自己去載入

堆記憶體的分配策略

1物件優先在eden區分配,Eden區沒有足夠的空間,將觸發一次Minor GC。

2大物件直接進入老年代(為了避免為大物件分配記憶體時由於分配擔保機制帶來的複製而降低效率 ),

3長期存活的物件進入老年代

4動態物件年齡判斷:如果Survivor區中相同年齡的所有物件大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的物件可以直接進入到老年代,無需等到MaxTenuringThreshold中要求的年齡

5空間分配擔保:-XX: HandlePromotionFailure

Minor GC與Full GC分別在什麼時候發生?

觸發MinorGC(Young GC)

虛擬機器在進行minorGC之前會判斷老年代最大的可用連續空間是否大於新生代的所有物件總空間

1、如果大於的話,直接執行minorGC

2、如果小於,判斷是否開啟HandlerPromotionFailure,沒有開啟直接FullGC

3、如果開啟了HanlerPromotionFailure, JVM會判斷老年代的最大連續記憶體空間是否大於歷次晉升的大小,如果小於直接執行FullGC

觸發FullGC

  • 老年代空間不足

    如果建立一個大物件,Eden區域當中放不下這個大物件,會直接儲存在老年代當中,如果老年代空間也不足,就會觸發Full GC。為了避免這種情況,最好就是不要建立太大的物件。

  • 持久代空間不足

    如果有持久代空間的話,系統當中需要載入的類,呼叫的方法很多,同時持久代當中沒有足夠的空間,就出觸發一次Full GC

  • YGC出現promotion failure

Minor GC 和 Full GC 有什麼不同呢?
新生代 GC(Minor GC):指發生新生代的的垃圾收集動作,Minor GC 非常頻繁,回收速度一般也比較快。
老年代 GC(Major GC/Full GC):指發生在老年代的 GC,出現了 Major GC 經常會伴隨至少一次的 Minor
GC(並非絕對),Major GC 的速度一般會比 Minor GC 的慢 10 倍以上

分代收集器

老生代和新生代兩個區域,而新生代又會分為:Eden 區和兩個 Survivor區(From Survivor、To Survivor)

為什麼 Survivor 分割槽不能是 0 個?

如果 Survivor 是 0 的話,也就是說新生代只有一個 Eden 分割槽,每次垃圾回收之後,存活的物件都會進入老生代,這樣老生代的記憶體空間很快就被佔滿了,從而觸發最耗時的 Full GC ,顯然這樣的收集器的效率是我們完全不能接受的。

為什麼 Survivor 分割槽不能是 1 個?

如果 Survivor 分割槽是 1 個的話,假設我們把兩個區域分為 1:1,那麼任何時候都有一半的記憶體空間是閒置的,顯然空間利用率太低不是最佳的方案。但如果設定記憶體空間的比例是 8:2 ,只是看起來似乎“很好”,假設新生代的記憶體為 100 MB( Survivor 大小為 20 MB ),現在有 70 MB 物件進行垃圾回收之後,剩餘活躍的物件為 15 MB 進入 Survivor 區,這個時候新生代可用的記憶體空間只剩了 5 MB,這樣很快又要進行垃圾回收操作,顯然這種垃圾回收器最大的問題就在於,需要頻繁進行垃圾回收。

為什麼 Survivor 分割槽是 2 個?

如果 Survivor 分割槽有 2 個分割槽,我們就可以把 Eden、From Survivor、To Survivor 分割槽記憶體比例設定為 8:1:1 ,那麼任何時候新生代記憶體的利用率都 90% ,這樣空間利用率基本是符合預期的。再者就是虛擬機器的大部分物件都符合“朝生夕死”的特性,所以每次新物件的產生都在空間佔比比較大的 Eden 區,垃圾回收之後再把存活的物件方法存入 Survivor 區,如果是 Survivor 區存活的物件,那麼“年齡”就 +1 ,當年齡增長到 15 (可通過設定)物件就升級到老生代。

● 請說明一下垃圾回收的優點以及原理

使得Java程式設計師在編寫程式的時候不再需要考慮記憶體管理。由於有個垃圾回收機制,Java中的物件不再有"作用域"的概念,只有物件的引用才有"作用域"。垃圾回收可以有效的防止記憶體洩露,有效的使用可以使用的記憶體。垃圾回收器通常是作為一個單獨的低級別的執行緒執行,不可預知的情況下對記憶體堆中已經死亡的或者長時間沒有使用的物件進行清除和回收,程式設計師不能實時的呼叫垃圾回收器對某個物件或所有物件進行垃圾回收。不再會被使用的物件的記憶體不能被回收,就是記憶體洩露

判斷物件是否可回收的方法

引用計數法:給物件中新增一個引用計數器,每當有一個地方引用它,計數器就加 1;當引用失效,計數器就減 1;任何時候計數器為 0 的物件就是不可能再被使用的

可達性分析法:通過一系列的稱為 “GC Roots” 的物件作為起點,從這些節點開始向下搜尋,節點所走過
的路徑稱為引用鏈,當一個物件到 GC Roots 沒有任何引用鏈相連的話,則證明此物件是不可用的

強引用、軟引用、弱引用、虛引用(虛引用與軟引用和弱引用的區別、軟引用能帶來的好處)

1.強引用
以前我們使用的大部分引用實際上都是強引用,這是使用最普遍的引用。如果一個物件具有強引用,那就類似於必
不可少的生活用品,垃圾回收器絕不會回收它。當記憶體空 間不足,Java 虛擬機器寧願丟擲 OutOfMemoryError 錯
誤,使程式異常終止,也不會靠隨意回收具有強引用的物件來解決記憶體不足問題

2.軟引用

如果一個物件只具有軟引用,那就類似於可有可無的生活用品。如果記憶體空間足夠,垃圾回收器就不會回收它,如
果記憶體空間不足了,就會回收這些物件的記憶體。只要垃圾回收器沒有回收它,該物件就可以被程式使用。軟引用可
用來實現記憶體敏感的快取記憶體。
軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收,JAVA 虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中

3.弱引用

如果一個物件只具有弱引用,那就類似於可有可無的生活用品。弱引用與軟引用的區別在:只具有弱引用的物件
擁有更短暫的生命週期。在垃圾回收器執行緒掃描它 所管轄的記憶體區域的過程中,一旦發現了只具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於垃圾回收器是一個優先順序很低的執行緒, 因此不一定會很快發現那些只具有弱引用的物件。
弱引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果弱引用所引用的物件被垃圾回收,Java 虛擬機器就
會把這個弱引用加入到與之關聯的引用佇列中。

4.虛引用

虛引用主要用來跟蹤物件被垃圾回收的活動 ,在程式設計中一般很少使用弱引用與虛引用,使用軟引用的情況較多,因為軟引用可以加速 JVM對垃圾記憶體的回收速度,可以維護系統的執行安全,防止記憶體溢位等問題的產生**

如何判斷一個常量是廢棄常量
執行時常量池主要回收的是廢棄的常量。
假如在常量池中存在字串 "abc",如果當前沒有任何 String 物件引用該字串常量的話,就說明常量 "abc" 就是
廢棄常量,如果這時發生記憶體回收的話而且有必要的話,"abc" 就會被系統清理出常量池。

如何判斷一個類是無用的類
方法區主要回收的是無用的類,類需要同時滿足下面 3 個條件才能算是 無用的類
1、該類所有的例項都已經被回收,也就是 Java 堆中不存在該類的任何例項。
2、載入該類的 ClassLoader 已經被回收。
3、該類對應的 java.lang.Class 物件沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

垃圾回收演算法

1、標記-清除演算法
演算法分為“標記”和“清除”階段:首先標記出所有需要回收的物件,在標記完成後統一回收所有被標記的物件。它是
最基礎的收集演算法,效率也很高,但是會帶來兩個明顯的問題:\1. 效率問題\2. 空間問題

2、複製演算法
為了解決效率問題,“複製”收集演算法出現了。它可以將記憶體分為大小相同的兩塊,每次使用其中的一塊。當這一塊
的記憶體使用完後,就將還存活的物件複製到另一塊去,然後再把使用的空間一次清理掉。這樣就使每次的記憶體回收
都是對記憶體區間的一半進行回收。

3、標記-整理演算法
根據老年代的特點特出的一種標記演算法,標記過程仍然與“標記-清除”演算法一樣,但後續步驟不是直接對可回收物件回收,而是讓所有存活的物件向一端移動,然後直接清理掉端邊界以外的記憶體。

4、分代收集演算法
當前虛擬機器的垃圾收集都採用分代收集演算法,根據物件存活週期的不同將記憶體分為幾塊。一般將 java 堆分為新生代和老年代,這樣我們就可以根據各個年代的特點選擇合適的垃圾收集演算法
比如在新生代中,每次收集都會有大量物件死去,所以可以選擇複製演算法,只需要付出少量物件的複製成本就可以
完成每次垃圾收集。而老年代的物件存活機率是比較高的,而且沒有額外的空間對它進行分配擔保,所以我們必須
選擇標記-清除標記-整理演算法進行垃圾收集。

垃圾收集器

1、 Serial 收集器 它的 “單執行緒” 的意義不僅僅意味著它只會使用一條垃圾收集執行緒去完成垃圾收集工作,更重要的是它在進行垃圾收集工作的時候必須暫停其他所有的工作執行緒,直到它收集結束。 新生代採用複製演算法,老年代採用標記-整理演算法

2、ParNew 收集器其實就是 Serial 收集器的多執行緒版本,除了使用多執行緒進行垃圾收集外,其餘行為(控制引數、收集演算法、回收策略等等)和 Serial 收集器完全一樣

3 、Parallel Scavenge 收集器它關注點是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的關注點更多的是使用者執行緒的停頓時間(提高使用者體驗)。 新生代採用複製演算法,老年代採用標記-整理演算法

4、Serial Old 收集器,它是一個單執行緒收集器。它主要有兩大用途:一種用途是在 JDK1.5 以及以前的
版本中與 Parallel Scavenge 收集器搭配使用,另一種用途是作為 CMS 收集器的後備方案。

5 、Parallel Old 收集器

6 、CMS 收集器,是一種以獲取最短回收停頓時間為目標的收集器。它而非常符合在注重使用者體驗的應用上使用。CMS(Concurrent Mark Sweep)收集器是 HotSpot 虛擬機器第一款真正意義上的併發收集器,它第一次實現了讓垃圾收集執行緒與使用者執行緒(基本上)同時工作

7、G1 收集器是一款面向伺服器的垃圾收集器,主要針對配備多顆處理器及大容量記憶體的機器. 以極高概率滿
足 GC 停頓時間要求的同時,還具備高吞吐量效能特徵.

volatile的作用

保證共享變數的可見性:使用volatile修飾的變數,任何執行緒對其進行操作都是在主記憶體中進行的,不會產生副本,從而保證共享變數的可見性。防止區域性指令重排序happens-before規則中的volatile變數規則規定了一個執行緒先去寫一個volatile變數,然後一個執行緒去讀這個變數,那麼這個寫操作的結果一定對讀的這個執行緒可見。volatile如何防止指令重排序

volatile是通過記憶體屏障來防止指令重排序volatile防止指令重排序具體步驟:

在每個volatile寫操作的前面插入一個StoreStore屏障。在每個volatile寫操作的後面插入一個StoreLoad屏障。在每個volatile讀操作的後面插入一個LoadLoad屏障。在每個volatile讀操作的後面插入一個LoadStore屏障。

15、專案

認證授權是如何實現的? Spring security + Oauth2完成使用者認證及使用者授權。認證授權流程如下:
1、使用者請求認證服務完成身份認證。
2、認證服務下發使用者身份令牌和JWT令牌,擁有身份令牌表示身份合法,Jwt令牌用於完成授權。
3、使用者攜帶jwt令牌請求資源服務。
4、閘道器校驗使用者身份令牌的合法,不合法表示使用者沒有登入,如果合法則放行繼續訪問。
5、資源服務獲取jwt令牌,根據jwt令牌完成授權

認證與授權實現思路

如果系統的模組多,每個模組都需要就行授權與認證,所以選擇基於token的形式進行授權與認證,使用者根據使用者名稱密碼認證成功,然後獲取當前使用者角色的一系列許可權值,並以使用者名稱為key,許可權列表為value的形式存入redis快取中,根據使用者名稱相關資訊生成token返回,瀏覽器將token記錄到cookie中,每次呼叫api介面都預設將token攜帶到header請求頭中,Spring-security解析header頭獲取token資訊,解析token獲取當前使用者名稱,根據使用者名稱就可以從redis中獲取許可權列表,這樣Spring-security就能夠判斷當前請求是否有許可權訪問

使用rabbitMQ

1、平臺包括多個站點,頁面歸屬不同的站點,需求是釋出一個頁面應將該頁面釋出到所屬站點的伺服器上。
2、每個站點服務部署CMS Client程式,並與交換機繫結,繫結時指定站點Id為routingKey。
指定站點id為routingKey就可以實現cms client只能接收到所屬站點的頁面釋出訊息。
3、頁面釋出程式向MQ釋出訊息時指定頁面所屬站點Id為routingKey,根據routingKey將訊息發給指定的
CMS Client。

分散式事務:

1、在微服務中使用Spring 宣告式事務控制方式進行控制,在Service方法上新增@Transctional註解即可實現事務
控制,它控制的是MySQL的本地事務。
2、專案中存在分散式事務控制,比如下單支付、課程釋出等地址都用到了分散式事務。
專案實現分散式事務控制實現最終資料一致性,做法是:
a、將分散式事務拆分為多個本地事務。
b、提交事務前每個參與者要通過資料校驗,和資源預留。
c、由訊息佇列去通知多個事務參與者完成本地事務的提交。
d、提交失敗的本地事務會重試。

專案中課程搜尋採用ElasticSearch來完成。實現方法是:
1、使用 Logstash(logstash是ES下的一款開源軟體,它能夠同時 從多個來源採集資料、轉換資料)將MySQL中
的課程資訊讀取到ES中建立索引,使用IK分詞器進行分詞。
2、使用 Java High Level REST Client完成搜尋。
3、生產環境使用ES部署為叢集。

系統對異常的處理使用統一的異常處理流程。
1、自定義異常型別。
2、自定義錯誤程式碼及錯誤資訊。
3、對於可預知的異常由程式設計師在程式碼中主動丟擲自定義異常型別的異常,丟擲異常時需要指定錯誤程式碼。
4、對於不可預知的異常(執行時異常)由SpringMVC統一捕獲Exception型別的異常,由統一的異常捕獲類來解析處理,並轉換為與自定義異常型別一致的資訊格式(錯誤程式碼+錯誤資訊)。
5、可預知的異常及不可預知的執行時異常最終會採用統一的資訊格式(錯誤程式碼+錯誤資訊)來表示,最終也會隨請求響應給客戶端

http協議處理視訊流
http採用DASH傳輸視訊流,原理是DASH伺服器將視訊進行了切片,MPD是一個XML,為接收端播放器提供表示不同分片的URL、時序、位元率、清晰度等資訊。客戶端通過接受、解析MPD檔案作為自適應流的依據,客戶端基於MPD資訊為分片傳送HTTP請求,然後客戶端的媒體播放器為收到的分片進行解碼和播放。

你在開發中遇到什麼問題?是怎麼解決的?

例子:
在處理訂單時要用到定時任務,當時採用的是Spring Task來完成,由於一個訂單服務會部署多個,多個訂單服務
同時去處理任務會造成任務被重複處理的情況,如何解決任務的重複處理。
解決:
採用樂觀鎖解決,在任務表中設定一個version欄位記錄版本號,取出任務記錄同時拿到任務的版本號,執行前對
任務進行鎖定,具體的做法是執行update根據當前版本號將版本號加1,update成功表示鎖定任務成功,即可開始執行任務。

例子:

Redis伺服器 can not get resource from pool. 1000個執行緒併發還能跑,5000個執行緒的時候出現這種問題,查後臺debug日誌,發現redis 執行緒池不夠。剛開始設定的是:

解決:順便也改了一下jdbc 的連線池引數,最大空閒和最大連線數都改成1000.在測一下。可以

例子:

註冊中心和服務提供者叢集註冊失敗,啟動報錯

解決:修改yml檔案,修改啟動類上的註解,yml檔案縮進出了問題,服務端啟動類上應該添加註解@EnableEurekaServer,客戶端@EnableDiscoveryClient

例子:

xml檔案配置錯誤,頁面訪問一直無資料

解決:根據瀏覽器的開發工具,定位錯誤,檢查xml檔案的SQL,namespace,parameterType等是否正確,是否假如應有的註解

例子:

git合併衝突,甲乙都是根據point.java檔案進行開發,甲開發出來版本2,並且提交了程式碼,乙開發出來版本3,也需要提交程式碼,此時將會報錯存在衝突。因為甲提交版本之後,此時遠端的程式碼已經是版本2了,而乙是在版本1的基礎上進行開發出了版本3,所以乙想要提交程式碼,勢必要將自己的程式碼更新為版本2的程式碼,然後在進行提交

解決:拉去遠端程式碼,存在衝突,會報錯。此時我們需要將原生代碼暫存起來stash;更新原生代碼,將原生代碼版本更新和遠端的程式碼一致,將暫存的程式碼合併到更新後的程式碼後,有衝突的要手動解決衝突,然後提交解決衝突後的程式碼。Git<resolve conflict

例子:

支付介面採用微信的掃碼支付拿到需求後,首先去閱讀微信的介面文件,重點閱讀統一下單、支付結果通知、支付結果查詢三個介面。下載官方提供的sdk編寫單元測試用例測試每個介面。測試時沒有使用微信的沙箱測試,直接使用正式介面,將金額改的小一些進行測試。單元測試通過後開發整個支付功能,最終整合測試通過。

解決:訂單支付介面引數的簽名問題,當時是因為自己沒有仔細看介面文件導致少寫一個必填引數一直報簽名失敗,隨後將所有必填引數填寫完成,最終解決問題。

例子:

一個接口出現Bug你是怎麼除錯的?
1、介面的開發需要前端和服務端共同除錯,要仔細閱讀測試人員反映的bug資訊,判斷這個bug是服務端的bug還
前端的bug。通常服務介面開發完成會使用postman工具進行測試,測試沒有問題再提交到Git或SVN。
2、找到bug的出錯點就可以根據bug資訊進行修改。修改完成需要前後端再次連調測試,按照測試人員提交的測試流程重新進行測試,測試通過將此bug置為已解決。