●RabbitMQ有以下幾種工作模式 :
簡單模式:一個生產者,一個消費者
work模式:一個生產者,多個消費者,每個消費者獲取到的消息唯一。
訂閱模式:一個生產者發(fā)送的消息會被多個消費者獲取。
路由模式:發(fā)送消息到交換機并且要指定路由key ,消費者指定路由key將隊列綁定到交換機
topic模式:將路由鍵和某模式進行匹配,此時隊列需要綁定在一個模式上
RPC
String,Stringbuffer,StringBuilder的區(qū)別
String:
StringBuffer:
StringBuilder:
繼承自AbstractStringBuilder,是可變類。
StringBuilder是非線性安全的。
執(zhí)行效率比StringBuffer高。
String s 與new String的區(qū)別
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" ,在棧中創(chuàng)建堆中"whx" 對象的內存地址。
反射的原理,反射創(chuàng)建類實例的三種方式是什么
Java反射機制:
? Java 的反射機制是指在運行狀態(tài)中,對于任意一個類都能夠知道這個類所有的屬性和方法; 并且對于任意一個對象,都能夠調用它的任意一個方法;這種動態(tài)獲取信息以及動態(tài)調用對象方法的功能成為Java語言的反射機制
獲取 Class 類對象三種方式:
JDK動態(tài)代理與cglib實現(xiàn)的區(qū)別
談談序列化與反序列化
分布式結構,怎么保證數(shù)據(jù)一致性
規(guī)避分布式事務——業(yè)務整合
經典方案 - eBay 模式
●SQL注入
SQL注入就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執(zhí)行惡意的SQL命令。
1)SQL注入攻擊的總體思路
? ●尋找到SQL注入的位置
? ●判斷服務器類型和后臺數(shù)據(jù)庫類型
? ●針對不同的服務器和數(shù)據(jù)庫特點進行SQL注入攻擊
2)應對方法
? ●使用正則表達式過濾傳入的參數(shù)
? ●參數(shù)綁定
? ●使用預編譯手段,綁定參數(shù)是最好的防SQL注入的方法。
● 請你說明一下 left join 和 right join 的區(qū)別?
left join(左聯(lián)接) :返回包括左表中的所有記錄和右表中聯(lián)結字段相等的記錄
right join(右聯(lián)接) :返回包括右表中的所有記錄和左表中聯(lián)結字段相等的記錄
●事務是什么
? 事務是應用程序中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要么全部成功,要么一個都不做。
● 數(shù)據(jù)庫ACID的特性。
原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發(fā)生,要么都不發(fā)生。
一致性指事務前后數(shù)據(jù)的完整性必須保持一致。
隔離性指多個用戶并發(fā)訪問數(shù)據(jù)庫時,一個用戶的事務不能被其他用戶的事務所干擾,多個并發(fā)事務之間數(shù)據(jù)要相互隔離。
持久性是指一個事務一旦提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,即便數(shù)據(jù)庫發(fā)生故障也不應該對其有任何影響。
● 請你介紹一下,數(shù)據(jù)庫的三個范式?
第一范式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。
第二范式(2NF):首先滿足 1NF,另外包含兩部分內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴于主鍵,而不能只依賴于主鍵的一部分。
第三范式(3NF):首先是滿足2NF,另外非主鍵列必須直接依賴于主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴于非主鍵列 B,非主鍵列 B 依賴于主鍵的情況
● 請你介紹一下數(shù)據(jù)庫的隔離級別
隔離級別 | 臟讀(Dirty Read) | 不可重復讀(NonRepeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
未提交讀 | 可能 | 可能 | 可能 |
已提交讀 | 不可能 | 可能 | 可能 |
可重復讀 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
未提交讀(Read Uncommitted):允許臟讀,也就是可能讀取到其他會話中未提交事務修改的數(shù)據(jù)。
已提交讀(Read Committed):只能讀取到已經提交的數(shù)據(jù)。Oracle等多數(shù)數(shù)據(jù)庫默認都是該級別 (不重復讀)。
可重復讀(Repeated Read):可重復讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,該隔離級別消除了不可重復讀,但是還存在幻象讀。
串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞。
數(shù)據(jù)庫的臟讀、幻讀、不可重復讀
1.臟讀:
指一個事務A正在訪問數(shù)據(jù),并且對該數(shù)據(jù)進行了修改,但是這種修改還沒有提交到數(shù)據(jù)庫中(也可能因為某些原因Rollback了)。這時候另外一個事務B也訪問這個數(shù)據(jù),然后使用了這個被A修改的數(shù)據(jù),那么這個數(shù)據(jù)就是臟的,并不是數(shù)據(jù)庫中真實的數(shù)據(jù)。這就被稱作臟讀。(事務A讀到了事務B未提交的數(shù)據(jù))
解決辦法:把數(shù)據(jù)庫事務隔離級別調整到READ_COMMITTED
即讓用戶在更新時鎖定數(shù)據(jù)庫,阻止其他用戶讀取,直到更新全部完成才讓你讀取。
2.幻讀:
指一個事務A對一個表中的數(shù)據(jù)進行了修改,而且該修改涉及到表中所有的數(shù)據(jù)行;同時另一個事務B也在修改表中的數(shù)據(jù),該修改是向表中插入一行新數(shù)據(jù)。那么經過這一番操作之后,操作事務A的用戶就會發(fā)現(xiàn)表中還有沒修改的數(shù)據(jù)行,就像發(fā)生了幻覺一樣。這就被稱作幻讀。(事務A修改數(shù)據(jù),事務B插入數(shù)據(jù),A發(fā)現(xiàn)表中還沒有修改的數(shù)據(jù)行)
解決辦法:把數(shù)據(jù)庫事務隔離級別調整到SERIALIZABLE_READ
3.不可重復讀:
指在一個事務A內,多次讀同一個數(shù)據(jù),但是事務A沒有結束時,另外一個事務B也訪問該同一數(shù)據(jù)。那么在事務A的兩次讀數(shù)據(jù)之間,由于事務B的修改導致事務A兩次讀到的數(shù)據(jù)可能是不一樣的。這就發(fā)生了在一個事務內兩次讀到的數(shù)據(jù)不一樣,這就被稱作不可重復讀。(事務A多次讀數(shù)據(jù),事務B訪問數(shù)據(jù),A讀到了B修改的數(shù)據(jù),導致兩次讀到的數(shù)據(jù)不一樣)
解決辦法:把數(shù)據(jù)庫事務隔離級別調整到REPEATABLE_READ
級別高低:臟讀 < 不可重復讀 < 幻讀
所以設置了最高級別的SERIALIZABLE_READ就不需要設置其他的了,即解決了幻讀問題那么臟度和不可重復讀自然就都解決了。
● 請你簡單介紹一下,數(shù)據(jù)庫水平切分與垂直切分
垂直拆分就是要把表按模塊劃分到不同數(shù)據(jù)庫表中,單表大數(shù)據(jù)量依然存在性能瓶頸
水平切分就是要把一個表按照某種規(guī)則把數(shù)據(jù)劃分到不同表或數(shù)據(jù)庫里。
通俗理解:水平拆分行,行數(shù)據(jù)拆分到不同表中, 垂直拆分列,表數(shù)據(jù)拆分到不同表中。
● 請你講講 Statement 和 Prepared Statement 的區(qū)別?哪個性能更好?
與Statement相比,①PreparedStatement接口代表預編譯的語句,它主要的優(yōu)勢在于可以減少SQL的編譯錯誤并增加SQL的安全性(減少SQL注射攻擊的可能性);②PreparedStatement中的SQL語句是可以帶參數(shù)的,避免了用字符串連接拼接SQL語句的麻煩和不安全;③當批量處理SQL或頻繁執(zhí)行相同的查詢時,PreparedStatement有明顯的性能上的優(yōu)勢,由于數(shù)據(jù)庫可以將編譯優(yōu)化后的SQL語句緩存起來,下次執(zhí)行相同結構的語句時就會很快
mysql數(shù)據(jù)庫的索引類型
索引數(shù)據(jù)結構:二叉樹、紅黑樹、hash表、B-tree
1、普通索引當一張表,把某個列設為主鍵的時候,則該列就是主鍵索引
2、唯一索引索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。
3、主鍵索引是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。
4、組合索引指多個字段上創(chuàng)建的索引,只有在查詢條件中使用了創(chuàng)建索引時的第一個字段,索引才會被使用。使用組合索引時遵循最左前綴集合。
5、全文索引主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。
InnoDB索引實現(xiàn)(聚集)
InnoDB主鍵索引查找流程:通過.ibd文件找到對應的索引,索引的value即為那行對應的完整數(shù)據(jù)
聚集索引和非聚集索引的區(qū)別?
聚集索引:表中那行數(shù)據(jù)的索引和數(shù)據(jù)都合并在一起了。
非聚集索引:表中那行數(shù)據(jù)的索引和數(shù)據(jù)是分開存儲的。
一個 SQL 執(zhí)行的很慢,我們要分兩種情況討論:
1、偶爾很慢,則有如下原因
(1)、數(shù)據(jù)庫在刷新臟頁,例如 redo log 寫滿了需要同步到磁盤。
(2)、執(zhí)行的時候,遇到鎖,如表鎖、行鎖。
2、這條 SQL 語句一直執(zhí)行的很慢,則有如下原因。
(1)、沒有用上索引:例如該字段沒有索引;由于對字段進行運算、函數(shù)操作導致無法用索引。
(2)、數(shù)據(jù)庫選錯了索引。
redis常見的數(shù)據(jù)結構以及應用場景:
String:key -value緩存應用,最常規(guī)的set/get操作,value可以是String也可以是數(shù)字。一般做一些復雜的計數(shù)功能的緩存。
Hash:field-value映射表,存儲用戶信息和商品信息
List:list分頁查詢
Set:實現(xiàn)差,并,交集操作,比如共同喜好等
Sorted set:用戶列表,禮物排行榜,彈幕消息
緩存雪崩:
緩存同一時間大面積失效,所有請求都落到數(shù)據(jù)庫造成短時間內承受大量請求而崩掉
如何解決緩存雪崩?在緩存的時候給過期時間加上一個隨機值,這樣就會大幅度的減少緩存在同一時間過期。
對于“Redis掛掉了,請求全部走數(shù)據(jù)庫”這種情況,我們可以有以下的思路:
事發(fā)前:實現(xiàn)Redis的高可用(主從架構+Sentinel 或者Redis Cluster),盡量避免Redis掛掉這種情況發(fā)生。
事發(fā)中:設置本地緩存(ehcache)+限流(hystrix),盡量避免我們的數(shù)據(jù)庫***掉(起碼能保證我們的服務還是能正常工作的)
事發(fā)后:redis持久化,重啟后自動從磁盤上加載數(shù)據(jù),快速恢復緩存數(shù)據(jù)。
緩存穿透:
惡意請求緩存中不存在的數(shù)據(jù),所有求情都落到數(shù)據(jù)庫造成短時間內承受大量請求而崩掉
如何解決緩存穿透?
(一)利用互斥鎖,緩存失效的時候,先去獲得鎖,得到鎖了,再去請求數(shù)據(jù)庫。沒得到鎖,則休眠一段時間重試
(二)采用異步更新策略,無論key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存如果過期,異步起一個線程去讀數(shù)據(jù)庫,更新緩存。需要做緩存預熱(項目啟動前,先加載緩存)操作。
(三)提供一個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。如果不合法,則直接返回。
Redis和數(shù)據(jù)庫雙寫一致性?
首先,采取正確更新策略,先更新數(shù)據(jù)庫,再刪緩存。其次,因為可能存在刪除緩存失敗的問題,提供一個補償措施即可,例如利用消息隊列。
采用延時雙刪策略
(1)先淘汰緩存
(2)再寫數(shù)據(jù)庫(這兩步和原來一樣)
(3)休眠1秒,再次淘汰緩存
Redis的內存淘汰機制:Redis提供了8種內存淘汰策略
如何解決 Redis 的并發(fā)競爭 Key 問題
所謂 Redis 的并發(fā)競爭 Key 的問題也就是多個系統(tǒng)同時對一個 key 進行操作,最后執(zhí)行的順序和我們期望的順序不同,導致了結果的不同!推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現(xiàn)分布式鎖)。
基于zookeeper臨時有序節(jié)點可以實現(xiàn)的分布式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節(jié)點的目錄下,生成一個唯一的瞬時有序節(jié)點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節(jié)點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節(jié)點刪除即可。
redis 持久化機制(怎么保證 redis 掛掉之后再重啟數(shù)據(jù)可以進行恢復)
1、快照(snapshotting)持久化(RDB)
Redis可以通過創(chuàng)建快照來獲得存儲在內存里面的數(shù)據(jù)在某個時間點上的副本。Redis創(chuàng)建快照之后,可以對快照進行備份,可以將快照復制到其他服務器從而創(chuàng)建具有相同數(shù)據(jù)的服務器副本(Redis主從結構,主要用來提高Redis性能),還可以將快照留在原地以便重啟服務器的時候使用??煺粘志没荝edis默認采用的持久化方式,在redis.conf配置文件中默認有此下配置
2、AOF(append-only file)持久化
與快照持久化相比,AOF持久化 的實時性更好,因此已成為主流的持久化方案。默認情況下Redis沒有開啟AOF方式的持久化,可以通過appendonly參數(shù)開啟.Redis 4.0 開始支持 RDB 和 AOF 的混合持久化(默認關閉,可以通過配置項 aof-use-rdb-preamble
開啟)。
● 請問,為什么 redis 讀寫速率快、性能好?
Redis是純內存數(shù)據(jù)庫,相對于讀寫磁盤,讀寫內存的速度就不是幾倍幾十倍了,一般hash查找可以達到每秒百萬次的數(shù)量級。
多路復用IO,“多路”指的是多個網絡連接,“復用”指的是復用同一個線程。采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網絡IO的時間消耗)??梢灾苯永斫鉃椋簡尉€程的原子操作,避免上下文切換的時間和性能消耗;加上對內存中數(shù)據(jù)的處理速度,很自然的提高redis的吞吐量。
● 請問什么是IoC和DI?并且簡要說明一下DI是如何實現(xiàn)的?
IoC叫控制反轉,DI叫依賴注入??刂品崔D是把傳統(tǒng)上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現(xiàn)對象組件的裝配和管理。"控制反轉"就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器,由容器來創(chuàng)建對象并管理對象之間的依賴關系。依賴注入的基本原則是應用組件不應該負責查找資源或者其他依賴的協(xié)作對象。配置對象的工作應該由容器負責,查找資源的邏輯應該從應用組件的代碼中抽取出來,交給容器來完成。DI是對IoC更準確的描述,即組件之間的依賴關系由容器在運行期決定,即由容器動態(tài)的將某種依賴關系注入到組件之中。
依賴注入可以通過setter方法注入(設值注入)、構造器注入和接口注入三種方式來實現(xiàn),Spring支持setter注入和構造器注入,通常使用構造器注入來注入必須的依賴關系,對于可選的依賴關系,則setter注入是更好的選擇,setter注入需要類提供無參構造器或者無參的靜態(tài)工廠方法來創(chuàng)建對象。
依賴注入是從應用程序的角度在描述:應用程序依賴容器創(chuàng)建并注入它所需要的外部資源;
控制反轉是從容器的角度在描述:容器控制應用程序,由容器反向的向應用程序注入應用程序所需要的外部資源。
● 請說明一下springIOC原理是什么?如果你要實現(xiàn)IOC需要怎么做?請簡單描述一下實現(xiàn)步驟?
①IoC這是spring的核心,由spring來負責控制對象的生命周期和對象間的關系。
IoC的一個在系統(tǒng)運行中,動態(tài)的向某個對象提供它所需要的其他對象。這一點是通過DI來實現(xiàn)的。比如對象A需要操作數(shù)據(jù)庫,有了 spring我們就只需要告訴spring,A中需要一個Connection,至于這個Connection怎么構造,何時構造,A不需要知道。在系統(tǒng)運行時,spring會在適當?shù)臅r候制造一個Connection,然后像***一樣,注射到A當中,這樣就完成了對各個對象之間關系的控制。A需要依賴 Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這么來的。那么DI是如何實現(xiàn)的呢? Java 1.3之后一個重要特征是反射(reflection),它允許程序在運行的時候動態(tài)的生成對象、執(zhí)行對象的方法、改變對象的屬性,spring就是通過反射來實現(xiàn)注入的。
②實現(xiàn)IOC的步驟
定義用來描述bean的配置的Java類、解析bean的配置、遍歷存放HashMap對象
● 請談一談Spring中自動裝配的方式有哪些?
bean的生命周期
● 請簡要說明一下IOC和AOP是什么?
控制反轉(IoC)與依賴注入(DI)是同一個概念,引入IOC的目的:(1)脫開、降低類之間的耦合;(2)倡導面向接口編程、實施依賴倒換原則; (3)提高系統(tǒng)可插入、可測試、可修改等特性。
具體做法:(1)將bean之間的依賴關系盡可能地抓換為關聯(lián)關系;
(2)將對具體類的關聯(lián)盡可能地轉換為對Java interface的關聯(lián),而不是與具體的服務對象相關聯(lián);
(3)Bean實例具體關聯(lián)相關Java interface的哪個實現(xiàn)類的實例,在配置信息的元數(shù)據(jù)中描述;
(4)由IoC組件(或稱容器)根據(jù)配置信息,實例化具體bean類、將bean之間的依賴關系注入進來。
AOP,即面向切面編程,它利用一種稱為"橫切"的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其命名為"Aspect",所謂"切面"是那些與業(yè)務無關,卻為業(yè)務模塊所共同調用的邏輯或責任封裝起來,便于減少系統(tǒng)的重復代碼,降低模塊之間的耦合度,并有利于未來的可操作性和可維護性。
使用"橫切"技術,AOP把軟件系統(tǒng)分為兩個部分:核心關注點和橫切關注點。業(yè)務處理的主要流程是核心關注點,與之關系不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發(fā)生在核心關注點的多處,而各處基本相似,比如權限認證、日志、事物。AOP的作用在于分離系統(tǒng)中的各種關注點,將核心關注點和橫切關注點分離開。
● 請問Spring支持的事務管理類型有哪些?以及你在項目中會使用哪種方式?
Spring支持編程式事務管理和聲明式事務管理。許多Spring框架的用戶選擇聲明式事務管理,因為這種方式和應用程序的關聯(lián)較少,因此更加符合輕量級容器的概念。聲明式事務管理要優(yōu)于編程式事務管理,盡管在靈活性方面它弱于編程式事務管理,因為編程式事務允許你通過代碼控制業(yè)務。
● 你如何理解AOP中的連接點(Joinpoint)、切點(Pointcut)、增強(Advice)、引介(Introduction)、織入(Weaving)、切面(Aspect)這些概念?
a. 連接點(Joinpoint):程序執(zhí)行的某個特定位置(如:某個方法調用前、調用后,方法拋出異常后)。一個類或一段程序代碼擁有一些具有邊界性質的特定點,這些代碼中的特定點就是連接點。
b. 切點:如果連接點相當于數(shù)據(jù)中的記錄,那么切點相當于查詢條件,一個切點可以匹配多個連接點。
c. 增強(Advice):增強是織入到目標類連接點上的一段程序代碼。
d. 引介(Introduction):引介是一種特殊的增強,它為類添加一些屬性和方法。
e. 織入(Weaving):織入是將增強添加到目標類具體連接點上的過程,AOP有三種織入方式
f. 切面:切面是由切點和增強(引介)組成的,它包括了對橫切關注功能的定義,也包括了對連接點的定義。
● 請問AOP的原理是什么?
AOP指面向切面編程,用于處理系統(tǒng)中分布于各個模塊的橫切關注點,比如事務管理、日志、緩存等等。AOP實現(xiàn)的關鍵在于AOP框架自動創(chuàng)建的AOP代理,AOP代理主要分為靜態(tài)代理和動態(tài)代理,靜態(tài)代理的代表為AspectJ;而動態(tài)代理則以Spring AOP為代表。通常使用AspectJ的編譯時增強實現(xiàn)AOP,AspectJ是靜態(tài)代理的增強,所謂的靜態(tài)代理就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強。
Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理。
JDK動態(tài)代理通過反射來接收被代理的類,并且要求被代理的類必須實現(xiàn)一個接口。核心是InvocationHandler接口和Proxy類。如果目標類沒有實現(xiàn)接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標類。
CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態(tài)的生成某個類的子類
● 請問aop的應用場景有哪些?
Authentication 權限 ,Caching 緩存 ,Context passing 內容傳遞 ,Error handling 錯誤處理 ,Lazy loading 懶加載 ,Debugging 調試 ,logging, tracing, profiling and monitoring 記錄跟蹤 優(yōu)化 校準,Performance optimization 性能優(yōu)化 ,Persistence 持久化 ,Resource pooling 資源池 ,Synchronization 同步,Transactions 事務。
● Spring框架為企業(yè)級開發(fā)帶來的好處有哪些?
Aop實現(xiàn)的幾種方式:
第一種:靜態(tài)織入,即在編譯時,就將各種涉及AOP攔截的代碼注入到符合一定規(guī)則的類中,編譯后的代碼與我們直接在RealA調用屬性或方法前后增加代碼是相同的,只是這個工作交由編譯器來完成。
第二種:EMIT反射,即:通過Emit反射動態(tài)生成代理類
第三種:普通反射+利用Remoting的遠程訪問對象時的直實代理類來實現(xiàn)
Spring如何選擇用JDK還是CGLiB?
1)當Bean實現(xiàn)接口時,Spring就會用JDK的動態(tài)代理。
2)當Bean沒有實現(xiàn)接口時,Spring使用CGlib是實現(xiàn)。
● 請問持久層設計要考慮的問題有哪些?請談一下你用過的持久層框架都有哪些?
所謂"持久"就是將內存中的數(shù)據(jù)保存到關系型數(shù)據(jù)庫、文件系統(tǒng)、消息隊列等提供持久化支持的設備中。持久層就是系統(tǒng)中專注于實現(xiàn)數(shù)據(jù)持久化的相對獨立的層面。
持久層設計的目標包括:
● 請闡述一下實體對象的三種狀態(tài)是什么?以及對應的轉換關系是什么?
Hibernate文檔中為Hibernate對象定義了四種狀態(tài),分別是:瞬時態(tài)(new, or transient)、持久態(tài)(managed, or persistent)、游狀態(tài)(detached)和移除態(tài)
瞬時態(tài):當new一個實體對象后,這個對象處于瞬時態(tài),即這個對象只是一個保存臨時數(shù)據(jù)的內存區(qū)域,如果沒有變量引用這個對象,則會被JVM的垃圾回收機制回收。這個對象所保存的數(shù)據(jù)與數(shù)據(jù)庫沒有任何關系,除非通過Session的save()、saveOrUpdate()、persist()、merge()方法把瞬時態(tài)對象與數(shù)據(jù)庫關聯(lián),并把數(shù)據(jù)插入或者更新到數(shù)據(jù)庫,這個對象才轉換為持久態(tài)對象。
持久態(tài):持久態(tài)對象的實例在數(shù)據(jù)庫中有對應的記錄,并擁有一個持久化標識(ID)。對持久態(tài)對象進行delete操作后,數(shù)據(jù)庫中對應的記錄將被刪除,那么持久態(tài)對象與數(shù)據(jù)庫記錄不再存在對應關系,持久態(tài)對象變成移除態(tài)(可以視為瞬時態(tài))。持久態(tài)對象被修改變更后,不會馬上同步到數(shù)據(jù)庫,直到數(shù)據(jù)庫事務提交。
游離態(tài):當Session進行了close()、clear()、evict()或flush()后,實體對象從持久態(tài)變成游離態(tài),對象雖然擁有持久和與數(shù)據(jù)庫對應記錄一致的標識值,但是因為對象已經從會話中清除掉,對象不在持久化管理之內,所以處于游離態(tài)(也叫脫管態(tài))。游離態(tài)的對象與臨時狀態(tài)對象是十分相似的,只是它還含有持久化標識。
● 請說明一下鎖機制的作用是什么?并且簡述一下Hibernate的悲觀鎖和樂觀鎖機制是什么?
有些業(yè)務邏輯在執(zhí)行過程中要求對數(shù)據(jù)進行排他性的訪問,于是需要通過一些機制保證在此過程中數(shù)據(jù)被鎖住不會被外界修改,這就是所謂的鎖機制。
Hibernate支持悲觀鎖和樂觀鎖兩種鎖機制。悲觀鎖,顧名思義悲觀的認為在數(shù)據(jù)處理過程中極有可能存在修改數(shù)據(jù)的并發(fā)事務(包括本系統(tǒng)的其他事務或來自外部系統(tǒng)的事務),于是將處理的數(shù)據(jù)設置為鎖定狀態(tài)。悲觀鎖必須依賴數(shù)據(jù)庫本身的鎖機制才能真正保證數(shù)據(jù)訪問的排他性,樂觀鎖,顧名思義,對并發(fā)事務持樂觀態(tài)度(認為對數(shù)據(jù)的并發(fā)操作不會經常性的發(fā)生),通過更加寬松的鎖機制來解決由于悲觀鎖排他性的數(shù)據(jù)訪問對系統(tǒng)性能造成的嚴重影響。
依賴注入的注入方式:
1、使用構造函數(shù)提供2、使用set方法提供3、使用注解提供
創(chuàng)建bean的方式:
1、使用默認構造函數(shù)2、使用普通工廠中的方法創(chuàng)建對象3、使用工廠中的靜態(tài)方法創(chuàng)建對象
Aspectj對AOP的實現(xiàn):
1)注冊bean 2)配置aop 3)定義切入點 4)定義切面(哪種通知)
Spring如何解決循環(huán)依賴
spring中循環(huán)依賴有三種情況:
1、構造器注入形成的循環(huán)依賴。也就是beanB需要在beanA的構造函數(shù)中完成初始化,beanA也需要在beanB的構造函數(shù)中完成舒適化,這種情況的結果就是兩個bean都不能完成初始化,循環(huán)依賴難以解決。
2、setter注入構成的循環(huán)依賴。beanA需要在beanB的setter方法中完成初始化,beanB也需要在beanA的setter方法中完成初始化,spring設計的機制主要就是解決這種循環(huán)依賴
3、prototype作用域bean的循環(huán)依賴。這種循環(huán)依賴同樣無法解決,因為spring不會緩存‘prototype’作用域的bean,而spring中循環(huán)依賴的解決正是通過緩存來實現(xiàn)的。
spring只能解決setter注入構成的依賴,第二種情況中循環(huán)依賴的解決方案:
步驟一:beanA進行初始化,并且將自己進行初始化的狀態(tài)記錄下來,并提前向外暴露一個單例工程方法,從而使其他bean能引用到該bean
步驟二:beanA中有beanB的依賴,于是開始初始化beanB。
步驟三:初始化beanB的過程中又發(fā)現(xiàn)beanB依賴了beanA,于是又進行beanA的初始化,這時發(fā)現(xiàn)beanA已經在進行初始化了,程序發(fā)現(xiàn)了存在的循環(huán)依賴,然后通過步驟一中暴露的單例工程方法拿到beanA的引用(注意,此時的beanA只是完成了構造函數(shù)的注入但為完成其他步驟),從而beanB拿到beanA的引用,完成注入,完成了初始化,如此beanB的引用也就可以被beanA拿到,從而beanA也就完成了初始化。
Spring的加載過程
初始化環(huán)境—>加載配置文件—>實例化Bean—>調用Bean顯示信息
1.SpringMVC的流程
(1)用戶發(fā)送請求至前端控制器DispatcherServlet
(2)Dispatcher Servlet收到請求后,調用HandlerMapping處理器映射器,請求獲取Handler
(3)處理器映射器根據(jù)請求url獲取具體的處理器,返回給DispatcherServlet
(4)DispatcherServlet調用HandlerAdapter處理器適配器
(5)處理器適配器經過適配調用具體的處理器
(6)Hander執(zhí)行完成返回ModelAndView
(7)HandlerAdapter將Handler執(zhí)行結果ModelAndView返回給DispatcherServlet
(8)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析
(9)ViewResolver經過解析后返回具體View
(10)DispatcherServlet對View進行渲染視圖
(11)DispatcherServlet響應用戶
2.SpringMVC的主要組件?
(1)前端控制器DispatcherServlet(不需要程序員開發(fā)):接收請求、響應結果,相當于轉發(fā)器,有
了DispatcherServlet就減少了其它組件之間的耦合度。
(2)處理器映射器HandlerMapping(不需要程序員開發(fā)):根據(jù)請求的url來查找Handler
(3)處理器適配器HandlerAdapter:在編寫Handler的時候要按照HandlerAdapter要求的規(guī)則去編
寫,這樣適配器HandlerAdapter才可以正確的去執(zhí)行Handler。
(4)處理器Handler(需要程序員開發(fā))
(5)視圖解析器ViewResolver(不需要程序員開發(fā)):進行視圖的解析,根據(jù)視圖邏輯名解析成真正
的視圖。
(6)視圖View(需要程序員開發(fā)jsp):View是一個接口,它的實現(xiàn)類支持不同的視圖類型
3.SpringMVC和Struts2的區(qū)別?
(1)SpringMVC的入口是一個servlet即前端控制器,而Struts2入口是一個filter過濾器
(2)SpringMVC是基于方法開發(fā)的,傳遞參數(shù)到方法的形參上,Struts2是基于類開發(fā)的,傳遞參數(shù)是
通過類的屬性。
4.SpringMVC怎么樣設定重定向和轉發(fā)的?
(1)轉發(fā):在返回值前面加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.對參數(shù)進行重新編碼:
String userName= new String(request.getParameter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默認編碼,需要將tomcat編碼后的內容按utf-8編碼。
7.SpringMVC的控制器是不是單例模式,如果是,有什么問題,怎么解決?
單例模式:單例模式類型的設計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。這種模式涉及到一個單一的類,該類負責創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
意圖:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
主要解決:一個全局使用的類頻繁地創(chuàng)建與銷毀。
何時使用:當您想控制實例數(shù)目,節(jié)省系統(tǒng)資源的時候。
如何解決:判斷系統(tǒng)是否已經有這個單例,如果有則返回,如果沒有則創(chuàng)建。
工廠模式
工廠模式提供了一種創(chuàng)建對象的最佳方式。在工廠模式中,我們在創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象。
意圖:定義一個創(chuàng)建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創(chuàng)建過程延遲到子類進行。
主要解決:主要解決接口選擇的問題。
何時使用:我們明確地計劃不同條件下創(chuàng)建不同實例時。
如何解決:讓其子類實現(xiàn)工廠接口,返回的也是一個抽象的產品。
是單例模式,所以在多線程訪問的時候有線程安全問題,不要用同步,會影響性能,解決方案是在控制
器里面不能寫字段。
8.SpringMVC常用的注解有哪些?
@RequestMapping:用于處理請求url映射的注解,可用于類或方法上。用于類上,則表示類中的所有
響應請求的方法都是以該地址作為父路徑。
@RequestBody:注解實現(xiàn)接受http請求的json數(shù)據(jù),將json轉換為java對象。
@ResponseBody:注解實現(xiàn)將Controller方法返回的對象轉化為json對象響應給客戶。
@RestController:注解相當于@Controller+@ResponseBody
@RequestParam:在controller的方法中參數(shù)名與表單中的參數(shù)名不一致,使用@RequestParm實現(xiàn)參
數(shù)綁定
@RequestParam(name="username") String t_username
@PathVariable:Controller除了可以接受表單提交的數(shù)據(jù)之外,還可以獲取url中攜帶的變量,即路徑
變量
9.如果在攔截請求中,我想攔截get方式提交的方法,怎么配置?
可以在@RequestMapping注解里面加上method=RequestMethod.GET
10.如果想在攔截的方法里面得到從前臺傳入的參數(shù),怎么得到?
直接在形參里面聲明這個參數(shù)就可以,但必須名字和傳過來的參數(shù)一樣。
11.SpringMVC中函數(shù)的返回值是什么?
返回值可以有多種類型,有String,void,和ModelAndView。
12.SpringMVC用什么對象從后臺向前臺傳遞數(shù)據(jù)?
通過ModelMap對象,可以在這個對象里面調用put方法,把對象加到里面,前臺就可以通過el表達式
拿到。
13.注解原理
? 注解本質上是一個繼承了Annotation的特殊接口,其具體實現(xiàn)類是Java運行時生成的動態(tài)代理類。我們
通過反射獲取注解時,返回的是Java運行時生成的動態(tài)代理對象。通過代理對像調用自定義注解的方
***最終調用AnnotationInvocaitonHandle的invoke方法。該方***從memberValues這個Map中
索引出對應的值。而memberValues的來源是java常量池。
一、什么是Mybatis?
二、Mybatis的優(yōu)點
1.基于SQL語句編程,相當靈活,不會對應用程序或者數(shù)據(jù)庫的現(xiàn)有設計造成任何影響,SQL寫在XML
里,解除sql與程序代碼的耦合,便于統(tǒng)一管理。提供xml標簽,支持編寫動態(tài)SQL語句,并可重用。
2.與JDBC相比,減少了50%以上的代碼量,消除了JDBC大量冗余的代碼,不需要手動開關連接。
3.很好的與各種數(shù)據(jù)庫兼容(因為Mybatis使用JDBC來連接數(shù)據(jù)庫,所以只要JDBC支持的數(shù)據(jù)庫
MyBatis都支持)。
4.能夠與Spring很好的集成。
三、Mybatis框架的缺點:
1.SQL語句的編寫工作量較大,尤其當字段多、關聯(lián)表多時,編寫SQL語句的功底有一定要求。
2.SQL語句依賴于數(shù)據(jù)庫,導致數(shù)據(jù)庫移植性差,不能隨意更換數(shù)據(jù)庫。
四、Mybatis與Hibernate有哪些不同?
1.Mybatis和Hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句。
2.Mybatis直接編寫原生態(tài)sql,可以嚴格控制sql執(zhí)行性能,靈活度高,非常適合關系數(shù)據(jù)模型要求不高
的軟件開發(fā),因為這類軟件需求變化頻繁,一但需求變化要求迅速輸出成功。
3.Hibernate對象/關系映射能力強,數(shù)據(jù)庫無關性好,對于關系模型要求高的軟件,如果用hibernate
開發(fā)可以節(jié)省很多代碼,提高效率。
四、#{}和${}的區(qū)別是什么?
Mybatis在處理#{}時會將sql中的#{}替換為?號,調用PreparedStatement的set方法來賦值。
Mybatis在處理${}時,就是把¥{}替換成變量的值。
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性。
五、當實體類中的屬性名和表中的字段名不一樣,怎么辦?
1.定義字段名的別名,讓字段名的別名和實體類的屬性名一致。
2.通過來映射字段名和屬性名一一對應
六、模糊查詢like語句該怎么寫?
1.在Java代碼中添加sql通配符。
2.在sql語句中拼接通配符,會引起sql注入
七、通常一個XML映射文件,都會寫一個Dao接口與之對應,請問這個Dao接口
的工作原理是什么?Dao接口里的方法,參數(shù)不同時,方法能重載嗎?
1.Dao接口也即是Mapper接口,接口的全限名,就是映射文件中namespace的值;接口的方法名,就
是映射文件中Mapper的Statement的id值;接口方法內的參數(shù),就是傳遞給sql的參數(shù)。
2.Mapper接口是沒有實現(xiàn)類的,當調用接口方法時,接口全限名+方法名拼接字符串作為key值,可唯
一定位一個MapperStatement。
八、Mybatis的XML映射文件中,不同的XML映射文件,id是否可以重復?
不同的XML映射文件,如果配置了namespace,那么id可以重復,如果沒有配置namespace,那么id
不能重復。
原因是namespace+id是作為map的key使用的,如果沒有namespace,就剩下id,那么,id重復會導
致數(shù)據(jù)互相覆蓋。有了namespace,自然id就可以重復,namespace不同,namespace+id自然也就
不同。
九、為什么說Mybatis是半自動ORM映射工具?它與全自動的區(qū)別在哪里?
Hibernate屬于全自動ORM映射工具,使用Hibernate查詢關聯(lián)對象或者關聯(lián)集合對象時,可以根據(jù)對
象關系模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯(lián)對象或關聯(lián)集合對象時,需要手動編
寫sql來完成,所以,稱之為半自動ORM映射工具。
十、MyBatis實現(xiàn)一對一有幾種方式?具體怎么操作的?
有聯(lián)合查詢和嵌套查詢,聯(lián)合查詢是幾個表聯(lián)合查詢,只查詢一次,通過resultMap里面配置
association節(jié)點配置一對一的類就可以完成。
嵌套查詢是先查一個表,根據(jù)這個表里面的結果的外鍵id,再去另一個表里查詢數(shù)據(jù),也是通過
association配置,但另外一個表的查詢通過select屬性配置。
十二、使用MyBatis的mapper接口調用時有哪些要求?
1.Mapper接口方法名和mapper.xml中定義的每個sql的id相同。
2.Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個sql的parameterType的類型相同。
3.Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個sql的resultType的類型相同。
4.Mapper.xml文件中namespace即是mapper接口的類路徑。
十三、mybatis的延遲加載
延遲加載:在真正使用數(shù)據(jù)時才發(fā)起查詢,不用的時候不查詢,按需加載
立即加載:不管用不用,只要一調用方法,馬上發(fā)起查詢
十四、Mybatis的一級緩存和二級緩存?
1)一級緩存 Mybatis的一級緩存是指SQLSession,一級緩存的作用域是SQlSession, Mybits默認開啟一級緩存。 在同一個SqlSession中,執(zhí)行相同的SQL查詢時;第一次會去查詢數(shù)據(jù)庫,并寫在緩存中,第二次會直接從緩存中取。 當執(zhí)行SQL時候兩次查詢中間發(fā)生了增刪改的操作,則SQLSession的緩存會被清空。 每次查詢會先去緩存中找,如果找不到,再去數(shù)據(jù)庫查詢,然后把結果寫到緩存中。 Mybatis的內部緩存使用一個HashMap,key為hashcode+statementId+sql語句。Value為查詢出來的結果集映射成的java對象。 SqlSession執(zhí)行insert、update、delete等操作commit后會清空該SQLSession緩存。
2)二級緩存是mapper級別的,Mybatis默認是沒有開啟二級緩存的。 第一次調用mapper下的SQL去查詢用戶的信息,查詢到的信息會存放代該mapper對應的二級緩存區(qū)域。 第二次調用namespace下的mapper映射文件中,相同的sql去查詢用戶信息,會去對應的二級緩存內取結果。 如果調用相同namespace下的mapepr映射文件中增刪改sql,并執(zhí)行了commit操作
一級緩存:也稱為本地緩存,用于保存用戶在一次會話過程中查詢的結果,用戶一次會話中只能使用一個sqlSession,一級緩存是自動開啟的,不允許關閉。
二級緩存:也稱為全局緩存,是mapper級別的緩存,是針對一個表的查結果的存儲,可以共享給所有針對這張表的查詢的用戶。也就是說對于mapper級別的緩存不同的sqlsession是可以共享的。
JDBC編程有哪些不足之處,Mybatis是如何解決這些問題的?
1) 數(shù)據(jù)庫連接的創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費從而影響了性能,如果使用數(shù)據(jù)庫連接池就可以解決這個問題。當然JDBC同樣能夠使用數(shù)據(jù)源。
解決:在SQLMapConfig.xml中配置數(shù)據(jù)連接池,使用數(shù)據(jù)庫連接池管理數(shù)據(jù)庫連接。
2) SQL語句在寫代碼中不容易維護,事件需求中SQL變化的可能性很大,SQL變動需要改變JAVA代碼。解決:將SQL語句配置在mapper.xml文件中與java代碼分離。
3) 向SQL語句傳遞參數(shù)麻煩,因為SQL語句的where條件不一定,可能多,也可能少,占位符需要和參數(shù)一一對應。解決:Mybatis自動將java對象映射到sql語句。
4) 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數(shù)據(jù)庫記錄封裝成pojo對象解析比較方便。解決:Mbatis自動將SQL執(zhí)行結果映射到java對象。
Mybatis編程步驟 ?
Step1:創(chuàng)建SQLSessionFactory Step2:通過SQLSessionFactory創(chuàng)建SQLSession Step3:通過SQLSession執(zhí)行數(shù)據(jù)庫操作 Step4:調用session.commit()提交事物 Step5:調用session.close()關閉會話
MyBatis與hibernate有哪些不同 ?
1)Mybatis MyBatis 是支持定制化 SQL、存儲過程以及高級映射的一種持久層框架。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數(shù)以及獲取結果集。Mybatis它不完全是一個ORM(對象關系映射)框架;它需要程序員自己編寫部分SQL語句。 mybatis可以通過xml或者注解的方式靈活的配置要運行的SQL語句,并將java對象和SQL語句映射生成最終的執(zhí)行的SQL,最后將SQL執(zhí)行的結果在映射生成java對象。 Mybatis程序員可以直接的編寫原生態(tài)的SQL語句,可以控制SQL執(zhí)行性能,靈活度高,適合軟件需求變換頻繁的企業(yè)。 缺點:Mybatis無法做到數(shù)據(jù)庫無關性,如果需要實現(xiàn)支持多種數(shù)據(jù)庫的軟件,則需要自定義多套SQL映射文件,工作量大。 2) Hibernate Hibernate是支持定制化 SQL、存儲過程以及高級映射的一種持久層框架。 Hibernate對象-關系映射能力強,數(shù)據(jù)庫的無關性好,Hirberate可以自動生成SQL語句,對于關系模型要求高的軟件,如果用HIrbernate開發(fā)可以節(jié)省很多時間。
SQLMapConfig.xml中配置有哪些內容?
1 2 3 4 5 6 7 8 9 10 11 | properties(屬性) settings(配置) typeAliases(類型別名) typeHandlers(類型處理器) objectFactory(對象工廠) plugins(插件) environments(環(huán)境集合屬性對象) environment(環(huán)境子屬性對象) transactionManager(事務管理) dataSource(數(shù)據(jù)源) mappers(映射器) |
Mybatis動態(tài)SQL?
傳統(tǒng)的JDBC的方法,在組合SQL語句的時候需要去拼接,稍微不注意就會少少了一個空格,標點符號,都會導致系統(tǒng)錯誤。Mybatis的動態(tài)SQL就是為了解決這種問題而產生的;Mybatis的動態(tài)SQL語句值基于OGNL表達式的,方便在SQL語句中實現(xiàn)某些邏輯;可以使用標簽組合成靈活的sql語句,提供開發(fā)的效率。
ORM:
對象關系映射(Object Relational Mapping,簡稱ORM),提供了概念性的、易于理解的模型化數(shù)據(jù)的方法,目的是想像操作對象一樣操作數(shù)據(jù)庫.因為數(shù)據(jù)庫不是面向對象的,所以需要編程進行映射.
Mabatis三劍客分別是:mybatis-generator、mybatis-plugin、mybatis-pagehelper
4、配置文件總結
web.xml**
1.配置一個全局的參數(shù):指定spring容器的配置文件applicationContext.xml路徑。
2.編碼過濾器。
3.配置***,創(chuàng)建spring容器對象。
4.前端控制器,指定配置文件spring-mvc.xml路徑
spring-mvc.xml
1.掃描包,創(chuàng)建類對象。
2.視圖解析器。
3.注解驅動。
4.自定義類型轉換器。
5.文件上傳。
6.攔截器。
7.靜態(tài)資源放行。
applicationContext.xml
持久層配置
1.引入數(shù)據(jù)庫外部屬性文件。
2.創(chuàng)建數(shù)據(jù)源對象。
3.創(chuàng)建sqlSessionFactory對象:以前在測試類中使用構建者模式創(chuàng)建SessionFactory對象,引入
SqlMapConfig.xml文件。
4.掃描dao層接口的包,創(chuàng)建動態(tài)代理對象,存入spring容器中。
業(yè)務層配置
5.掃描包,創(chuàng)建業(yè)務層所有類對象。
6.聲明式事務
1)事務管理類對象
2)事務增強對象
3)aop配置:切面配置
在使用springmvc框架的時候,在處理json的時候需要用到spring框架特有的注解@ResponseBody或
者@RestController注解,這兩個注解都會處理返回的數(shù)據(jù)格式,使用了該類型注解后返回的不再是視
圖,不會進行轉跳,而是返回json或xml數(shù)據(jù)格式,輸出在頁面上。
那么,這兩個注解在使用上有什么區(qū)別呢?
@ResponseBody,一般是使用在單獨的方法上的,需要哪個方法返回json數(shù)據(jù)格式,就在哪個方法
上使用,具有針對性。
@RestController,一般是使用在類上的,它表示的意思其實就是結合了@Controller和
@ResponseBody兩個注解,
如果哪個類下的所有方法需要返回json數(shù)據(jù)格式的,就在哪個類上使用該注解,具有統(tǒng)一性;需要注意
的是,使用了@RestController注解之后,其本質相當于在該類的所有方法上都統(tǒng)一使用了
@ResponseBody注解,所以該類下的所有方法都會返回json數(shù)據(jù)格式,輸出在頁面上,而不會再返回
視圖。
? SpringCloud將現(xiàn)在非常流行的一些技術整合到一起,實現(xiàn)了諸如:配置管理,服務發(fā)現(xiàn),智能路由,負載均衡,熔斷器,控制總線,集群狀態(tài)等等功能。
Eureka就好比是滴滴,負責管理、記錄服務提供者的信息。服務調用者無需自己尋找服務,而是把自己的需求告訴Eureka,然后Eureka會把符合你需求的服務告訴你。
同時,服務提供方與Eureka之間通過“心跳”
機制進行監(jiān)控,當某個服務提供方出現(xiàn)問題,Eureka自然會把它從服務列表中剔除。這就實現(xiàn)了服務的自動注冊、發(fā)現(xiàn)、狀態(tài)監(jiān)控。
基本架構:
Eureka架構中的三個核心角色:
服務注冊中心
Eureka的服務端應用,提供服務注冊和發(fā)現(xiàn)功能,就是剛剛我們建立的eureka-demo
服務提供者
提供服務的應用,可以是SpringBoot應用,也可以是其它任意技術實現(xiàn),只要對外提供的是Rest風格服務即可。本例中就是我們實現(xiàn)的user-service-demo
服務消費者
消費應用從注冊中心獲取服務列表,從而得知每個服務方的信息,知道去哪里調用服務方。本例中就是我們實現(xiàn)的consumer-demo
? 服務網關是微服務架構中一個不可或缺的部分。通過服務網關統(tǒng)一向外系統(tǒng)提供REST API的過程中,除了具備服務路由、均衡負載功能之外,它還具備了權限控制
等功能。Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務架構提供了前門保護的作用,同時將權限控制這些較重的非業(yè)務邏輯內容遷移到服務路由層面,使得服務集群主體能夠具備更高的可復用性和可測試性。在微服務架構中,Zuul就是守門的大Boss!一夫當關,萬夫莫開!
? 不管是來自于客戶端(PC或移動端)的請求,還是服務內部調用。一切對服務的請求都會經過Zuul這個網關,然后再由網關來實現(xiàn) 鑒權、動態(tài)路由等等操作。Zuul就是我們服務的統(tǒng)一入口。
Zuul中默認就已經集成了Ribbon負載均衡和Hystix熔斷機制。但是所有的超時策略都是走的默認值,比如熔斷超時時間只有1S,很容易就觸發(fā)了
負載均衡是我們處理高并發(fā)、緩解網絡壓力和進行服務器擴容的重要手段之一。但是,一般情況下我們
所說的負載均衡通常都是指服務器端負載均衡,服務器端負載均衡又分為兩種:一種是硬件負載均衡,
還有一種是軟件負載均衡
Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣。你不用再自己拼接url,拼接參數(shù)等等操作,一切都交給Feign去做。
Feign中本身已經集成了Ribbon依賴和自動配置、Feign默認也有對Hystix的集成、Spring Cloud Feign 支持對請求和響應進行GZIP壓縮,以減少通信過程中的性能損耗。
雪崩效應:
在微服務架構中通常會有多個服務層調用,基礎服務的故障可能會導致級聯(lián)故障,進而造成整個系統(tǒng)不
可用的情況,這種現(xiàn)象被稱為雪崩效應。雪崩效應是一種因服務提供者的不可用導致服務消費者 的不可
用,并將不可用逐漸放大的過程。
A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者,A不可用引起了B的不可用,并將不可
用像滾雪球一樣放大到C和D時,雪崩效應就形成了。
Hystix是Netflix開源的一個延遲和容錯庫,用于隔離訪問遠程服務、第三方庫,防止出現(xiàn)級聯(lián)失敗。當有服務出現(xiàn)異常時,直接進行失敗回滾,服務降級處理:
當服務繁忙時,如果服務出現(xiàn)異常,不是粗暴的直接報錯,而是返回一個友好的提示,雖然拒絕了用戶的訪問,但是會返回一個結果。
這就好比去買魚,平常超市買魚會額外贈送殺魚的服務。等到逢年過節(jié),超時繁忙時,可能就不提供殺魚服務了,這就是服務的降級。
系統(tǒng)特別繁忙時,一些次要服務暫時中斷,優(yōu)先保證主要服務的暢通,一切資源優(yōu)先讓給主要服務來使用,在雙十一、618時,京東天貓都會采用這樣的策略。
使用步驟:導入依賴--->Feign的客戶端--->開啟feign的功能--->啟動測試
單點登錄又叫做sso,是在互相信任的多個系統(tǒng)中,只需要輸入一次用戶名密碼,就可以直接登錄其它
互相信任的系統(tǒng)。
使用場景:
傳統(tǒng)企業(yè)項目:作系統(tǒng)權限集成
互聯(lián)網項目:soa分布式架構下,是多個項目,如果跨項目跳轉訪問能夠自動認證。
單點登錄服務器,項目中配置cas的客戶端工具包,就可以不用寫代碼實現(xiàn)單點登錄。
cas和springSecurity整合到品優(yōu)購項目中:整合前:
springSecurity的作用:
認證:判斷用戶名和密碼是否正確
賦權:用戶登錄后,應該具有什么樣的訪問權限
整合后:
springSecurity:
賦權,用戶登錄后,應該具有什么樣的訪問權限,用戶的認證工作交給cas,因為cas更擅長。
cas:判斷用戶名密碼是否正確,cas更擅長認證工作,因為它能完成在多個互相信任的系統(tǒng)中,只要在
一個系統(tǒng)中登錄后,在其它系統(tǒng)中就不需要再次輸入用戶名密碼就能夠自動認證。
集群就是多臺機器,是一種線上的部署方案,很多機器加起來,性能就比一臺機器強,一般用這種部署
方案來解決高并發(fā),高可用,容災,集群也有不同的叫法,負載均衡集群,高可用集群,擴容集群等。
什么是分布式
分布式也叫做SOA,是一種設計方案,以前使用所有模塊在一個項目中的寫法,叫做垂直架構,后來由
于互聯(lián)網的興起,為了模塊間的解耦和擴展性以及部署的靈活性,會將一個項目按照模塊進行拆分,一
個模塊就是一個項目這種設計方案叫做分布式架構,也叫做SOA架構。
什么是負載均衡器以及作用?
負載均衡器就是為了解決高并發(fā)而生的一種解決方案,它的作用就是接收所有請求,并將請求分發(fā)給
tomcat集群,這樣均勻分布請求到很多tomcat中,可以解決高并發(fā)。
負載均衡器的分類:
硬負載:硬負載就是硬件,很貴,需要花錢購買,常用的硬負載機器有f5,netsclaer。優(yōu)點就是性能好
軟負載:軟件,***,需要部署在linux操作系統(tǒng)上,常用的有nginx,lvs優(yōu)點就是***,缺點
就是性能沒有硬負載好,nginx一般單機可以抗住每秒5萬的請求量。
nginx反向代理配置:
一個nginx充當代理人的角色,而后面的tomcat不是集群就是單臺tomcat部署的我們一個項目,這種部
署方案nginx就相當于我們項目的代理人,叫做反向代理配置。
nginx負載均衡配置:
一個nginx,對應tomcat集群,也就是多個tomcat,這多個tomcat中部署的是同一個項目,nginx就可
以將請求均勻的分發(fā)給tomcat集群來處理請求,這種配置叫做負載均衡配置。
docker是一種容器化技術,也可以說是一種虛擬化技術。通俗的理解就是一個高性能,Linux服務器上
才能用的虛擬機軟件。docker跟vmware虛擬機區(qū)別:
docker:
Linux服務器上才可以用,高性能,docker虛擬出來的虛擬機只能是linux系統(tǒng)
vmware:
window版虛擬機軟件,低性能,vmware可以虛擬出windows,linux,centos,unix等系統(tǒng)。
我們在企業(yè)用docker做什么用?
使用docker進行部署,降低企業(yè)運營部署成本,基本實現(xiàn)零成本部署。
docker解決了部署的時候,同一臺機器軟件版本差異化造成的沖突問題。
docker對于硬件資源的管理,非常擅長,能更好的發(fā)揮每一臺機器的性能。
spring cloud和rpc框架的區(qū)別
Dubbo RPC:基于TCP或HTTP的遠程過程調用(就像在本地調用一樣),RPC強調的是遠程調用。
spring cloud:基于springboot,而springboot是基于HTTP協(xié)議REST風格的RPC。
對比:
1、協(xié)議:服務間通信協(xié)議不同,Dubbo是基于TCP協(xié)議的rpc,spring cloud基于http協(xié)議。
2、RPC避免了上面提到的原生RPC帶來的問題。REST相比RPC更為靈活,SpringCloud不存在代碼級別的強依賴
3、效率:由于協(xié)議的不同,調用的效率相比之下Dubbo比SpringCLoud效率高。
4、技術開放性:SpringCLoud基于http協(xié)議,由于http的協(xié)議更方便于多語言情況下的整合,提供服務方可以用任意語言開發(fā)服務。
5、spring cloud是微服務生態(tài),包括完整的微服務相關的組件工具集,而RPC是遠程調用的技術,僅僅是微服務的一部分,而dubbo框架正是RPC的實現(xiàn)框架。
6、Spring Cloud還提供了包括Netflix Eureka、hystrix、feign、Spring Boot Admin 、Sleuth、config、stream、security、sleuth等分布式服務解決方案,而Dubbo為了擁抱融入Spring Cloud生態(tài),Dubbo也在積極規(guī)劃和演進適配SpringCloud生態(tài)的新版本。
一、熱部署
熱部署是指當我們修改代碼后,服務能自動加載新修改的內容,這樣大大提高了 我們開發(fā)的效率,否則
每次都要手動重啟,這樣就比較耗時。
二、使用lombok
在之前編寫的代碼中,我們寫了很多bean,這里面加了很多set、get方法,這些方法冗余,但卻也不可
缺少??梢允褂胠ombok包,通過該工具,就不用在bean源碼中手動添加set、get方法了,除此之外
equals、hashcode、toString方法也無需手動在源碼中添加了。
三、什么是SpringBoot?
SpringBoot是Spring開源組織下的子項目,是Spring組件一站式解決方案,主要是簡化了使用Spring的
難度,簡省了繁重的配置,提供了各種啟動器,開發(fā)者能快速上手。
四、SpringBoot有哪些有哪些優(yōu)點?
1.減少開發(fā),測試時間和努力
2.使用JavaConfig有助于避免使用XML
3.避免大量的Maven導入和各種版本沖突。
五、SpringBoot的核心配置文件有哪幾個?它們的區(qū)別是什么?
SpringBoot的核心配置文件是application和bootstrap配置文件
application:主要用于Spring Boot項目的自動化配置。
@Controller
@ResponseBody
@RestController
六、SpringBoot的配置文件有哪幾種格式?它們有什么區(qū)別?
.properties和.yml,它們的區(qū)別主要是書寫格式不同。
七、Spring Boot的核心注解是哪個?它主要由哪幾個注解組成的?
@SpringBootApplication是SpringBoot的核心注解,主要組合包含了以下3個注解:
1.@SpringBootConfiguration:組合了@Configuration注解,實現(xiàn)配置文件的功能。
2.@EnableAutoConfiguration:打開自動配置的功能,也可以關閉某個自動配置的選項,如關閉數(shù)據(jù)
源自動配置功能:@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.直接執(zhí)行main方法。
十一、SpringBoot自動配置原理是什么?
注解@EnableAutoConfiguration,@Configuration,@ConditionalOnClass就是自動配置的核心,首先
它得是一個配置文件,其次根據(jù)類路徑下是否有這個類去自動配置。
十二、SpringBoot實現(xiàn)分頁和排序?
使用Spring Data-JPA可以實現(xiàn)將可分頁的org.springframework.data.domain.Pageable傳遞給存儲庫
方法。
十三、如何實現(xiàn)Spring Boot應用程序的安全性?
使用spring-boot-starter-security依賴項,并且必須添加安全配置。
十四、如何集成Spring Boot和ActiveMQ?
使用spring-boot-start-activemq依賴關系。它只需要很少的配置,并且不需要樣板代碼。
十五、SpringBoot中的監(jiān)視器是什么?
Spring boot actuator是spring啟動框架中的重要功能之一。spring boot監(jiān)視器可幫助您訪問生產環(huán)境
中正在運行 的應用程序的當前狀態(tài)。
十六、什么是Swagger?你用Spring Boot實現(xiàn)了它嗎?
Swagger是用于生成Restful Web服務的可視化表示的工具,規(guī)范和完整框架實現(xiàn)。它使文檔能夠以與
服務器相同的速度更新。
十七、如何使用Spring Boot實現(xiàn)異常處理?
Spring提供了一種使用ControllerAdvice處理異常的非常有用的方法。我們通過實現(xiàn)一個
ControlerAdvice類,來處理控制器類拋出的所有異常。
十八、RequestMapping和GetMapping的不同之處在哪里?
RequestMapping具有類屬性的,可以進行GET\POST\PUT或者其它的注釋中具有的請求方法
GetMapping是GET請求方法中的一個特例。它只是RequestMapping的一個延伸,目的是為了提高清
晰度。
十九、Spring Boot可以兼容老Spring項目嗎?如何做?
可以兼容,使用@ImportResource注解導入老Spring項目配置文件。
二十、包含Spring boot應用有哪些方法?
在生產中使用Https使用Snyk檢查你的依賴關系
升級到最新版本
啟用CSRF保護
使用內容安全策略防止XSS攻擊。
1.關于緩存
緩存和CDN:CDN是內容分發(fā)網絡,其實,可以把它看做是一個內容緩存服務器,不同的運營商,自己使用的CDN(緩存策略)是不一樣的。我們將訪問的資源存放在離我們最近的CDN服務器上,通過HTTP協(xié)議中的cache-contol:max-age來設置緩存時間。當我們下次訪問同一資源的時候,通過判斷緩存數(shù)據(jù)是否過期來判斷是否重新向源站發(fā)出請求。
3.斷點續(xù)傳以及多線程下載
請求時設置了一個請求頭range的范圍,服務器響應Accept-Range字段表示是否接受斷點續(xù)傳,content-Range返回接受的范圍即文件大小,進行判斷后,返回請求的范圍數(shù)據(jù),及響應碼。
計算機網絡七層模型
應用層(數(shù)據(jù))、表示層(數(shù)據(jù))、會話層(數(shù)據(jù))、傳輸層(數(shù)據(jù)報文)、網絡層 (數(shù)據(jù)分組)、數(shù)據(jù)鏈路層 (幀)、物理層 (比特)
TCP/IP四層模型
應用層 :應用進程 ->文件傳輸協(xié)議(FTP)、域名服務(DNS)、超文本傳輸協(xié)議(HTTP)
傳輸層:TCP /UDP
網絡層:ICMP/IGMP/ARP/RARP/IP 網絡協(xié)議 IP
網絡接口層:網絡接口
1.Http和Https的區(qū)別
Http協(xié)議運行在TCP之上,明文傳輸,客戶端和服務器都無法驗證對方的身份;Https運行于SSL之上,SSL運行于TCP之上,是添加了加密和認證機制的Http。
端口不同:http和https使用不同的連接方式,用的端口也不一樣,前者是80端口,后者是443端口;
資源消耗不同:和http通信相比,https通信會由于加減密處理消耗更多的CPU和內存資源;
開銷:https通信需要證書,而證書一般需要向認證機構購買。
https的加密機制是一種共享密鑰加密和公開加密并用的混合加密機制。
2.對稱加密與非對稱加密
對稱加密是指加密和解密使用同一個密鑰的方式,這種方式存在的最大的問題就是密鑰發(fā)送問題,即如
何安全的將密鑰發(fā)給對方;而非對稱加密是指使用一對非對稱密鑰,即公鑰和私鑰,公鑰可以隨意發(fā)
布,但私鑰只有自己知道。發(fā)送密文的一方使用對方的公鑰進行加密處理,對方接收到加密信息,使用
自己的私鑰進行解密。
3.三次握手和四次揮手
tcp的幾個狀態(tài):
1 2 3 4 5 | SYN表示建立連接, FIN表示關閉連接, ACK表示響應, PSH表示有數(shù)據(jù)傳輸, RST表示連接重置! |
(1)三次握手(我要和你建立連接,你真的要和我建立連接么,我真的要和你建立連接,成功):
1.第一次握手:Client將標志位SYN置為1,隨機產生一個值seq=J,并將該數(shù)據(jù)包發(fā)送給Server,Client
進入syn_sent狀態(tài),等待Server確認。
2.第二次握手:Server收到數(shù)據(jù)包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和
ACK都置為1,ack=J+1,隨機產生一個值seq=K,并將該數(shù)據(jù)包發(fā)送給Client以確認連接請求,Server進
入syn_rcvd狀態(tài)。
3.第三次握手:Client收到確認后,檢查ack=J+1,ACK是否為1,如果正確則將標志位ACK為1,
ack=K+1,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建
立成功,Client和Server進入established狀態(tài),完成三次握手,隨后Client和Server之間可以開始傳輸
數(shù)據(jù)了。
(2)四次揮手(我要和你斷開連接;好的,斷吧。我也要和你斷開連接;好的,斷吧)
第一次揮手:Client發(fā)送一個FIN,用來關閉Client到Server的數(shù)據(jù)傳送,Client進入fin_wait_1狀態(tài)。
第二次揮手:Server收到FIN后,發(fā)送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個
FIN占用一個序號),Server進入Close_wait狀態(tài)。此時TCP連接處于半關閉狀態(tài),即客戶端已經沒有要
發(fā)送的數(shù)據(jù)了,但服務端若發(fā)送數(shù)據(jù),則客戶端仍要接收。
第三次揮手:Server發(fā)送一個FIN,用來關閉Server到Client的數(shù)據(jù)傳送,Server進入Last_ack狀態(tài)。
第四次揮手:Client收到FIN后,Client進入Time_wait狀態(tài),接著發(fā)送一個ACK給Server,確認序號為
收到序號+1,Server進入Closed狀態(tài),完成四次揮手。
4.域名系統(tǒng)(服務)協(xié)議(DNS)是一種分布式網絡目錄服務,主要用于域名與 IP 地址的相互轉換,以及控制因特網的電子郵件的發(fā)送。
5.子網掩碼:是一種用來指明一個IP地址的哪些位標識的是主機所在的子網,以及哪些位標識的是主機的位掩碼,子網掩碼只有一個作用,就是將某個IP地址劃分成網絡地址和主機地址兩部分
6.網關:網關又稱網間連接器、協(xié)議轉換器。網關在網絡層以上實現(xiàn)網絡互連,是復雜的網絡互連設備,僅用于兩個高層協(xié)議不同的網絡互連。網關既可以用于廣域網互連,也可以用于局域網互連。 網關是一種充當轉換重任的計算機系統(tǒng)或設備。
7、TCP與UDP區(qū)別總結:
1、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接
2、TCP提供可靠的服務。通過TCP連接傳送的數(shù)據(jù),無差錯,不丟失,不重復,且按序到達;UDP盡最大努力交付,即不保證可靠交付
3、UDP具有較好的實時性,工作效率比TCP高,適用于對高速傳輸和實時性有較高的通信或廣播通信。
4、每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信
5、TCP對系統(tǒng)資源要求較多,UDP對系統(tǒng)資源要求較少。
● int和Integer有什么區(qū)別?
為了編程的方便還是引入了基本數(shù)據(jù)類型,但是為了能夠將這些基本數(shù)據(jù)類型當成對象操作,Java為每一個基本數(shù)據(jù)類型都引入了對應的包裝類型(wrapper class),int的包裝類就是Integer,從Java 5開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換。
Java 提供兩種不同的類型:引用類型和原始類型(或內置類型)。Int是java的原始數(shù)據(jù)類型,Integer是java為int提供的封裝類。
- 原始類型: boolean,char,byte,short,int,long,float,double
- 包裝類型:Boolean,Character,Byte,Short,Integer,Long,F(xiàn)loat,Double
請你談談大O符號(big-O notation)并給出不同數(shù)據(jù)結構的例子
? 大O符號描述了當數(shù)據(jù)結構里面的元素增加的時候,算法的規(guī)?;蛘呤切阅茉谧顗牡膱鼍跋掠卸嗝春?。
大O符號也可用來描述其他的行為,比如:內存消耗。因為集合類實際上是數(shù)據(jù)結構,我們一般使用大O符號基于時間,內存和性能來選擇最好的實現(xiàn)。大O符號表示一個程序運行時所需要的漸進時間復雜度上界。
● 請你解釋什么是值傳遞和引用傳遞?
值傳遞是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量.
引用傳遞一般是對于對象型變量而言的,傳遞的是該對象地址的一個副本, 并不是原對象本身 。 所以對引用對象進行操作會同時改變原對象.一般認為java內的傳遞都是值傳遞.
請你說說Lamda表達式的優(yōu)缺點。
優(yōu)點:1. 簡潔。2. 非常容易并行計算。3. 可能代表未來的編程趨勢。
缺點:1. 若不用并行計算,很多時候計算速度沒有比傳統(tǒng)的 for 循環(huán)快。(并行計算有時需要預熱才顯示出效率優(yōu)勢)2. 不容易調試。3. 若其他程序員沒有學過 lambda 表達式,代碼不容易讓其他語言的程序員看懂。
● 你知道java8的新特性嗎,請簡單介紹一下
Lambda 表達式 ? Lambda允許把函數(shù)作為一個方法的參數(shù)
方法引用? 方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。與lambda聯(lián)合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗余代碼。
默認方法? 默認方法就是一個在接口里面有了一個實現(xiàn)的方法。
新工具? 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。
==與equlas有什么區(qū)別?
==
equals
final關鍵字
當用final修飾一個類時,表明這個類不能被繼承。“使用final方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。
對于一個final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。
● 接口和抽象類的區(qū)別是什么?
Java提供和支持創(chuàng)建抽象類和接口。它們的實現(xiàn)有共同點,不同點在于:
接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
類可以實現(xiàn)很多個接口,但是只能繼承一個抽象類
類可以不實現(xiàn)抽象類和接口聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。
抽象類可以在不提供接口方法實現(xiàn)的情況下實現(xiàn)接口。
Java接口中聲明的變量默認都是final的。抽象類可以包含非final的變量。
Java接口中的成員函數(shù)默認是public的。抽象類的成員函數(shù)可以是private,protected或者是public。
接口是絕對抽象的,不可以被實例化。抽象類也不可以被實例化,如果它包含main方法的話是可以被調用的。
● 請你說說Iterator和ListIterator的區(qū)別?
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。
Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向。
ListIterator實現(xiàn)了Iterator接口,并包含其他的功能:增加元素,替換元素,獲取前一個和后一個元素的索引
● 請問什么是java序列化?以及如何實現(xiàn)java序列化?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化??梢詫α骰蟮膶ο筮M行讀寫操作,也可將流化后的對象傳輸于網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發(fā)的問題。
java內存模型(Java Memory Model)是java虛擬機規(guī)范定義的,用來屏蔽掉java程序在各種不同的硬件和操作系統(tǒng)對內存的訪問的差異,這樣就可以實現(xiàn)java程序在各種不同的平臺上都能達到內存訪問的一致性??梢员苊庀馽++等直接使用物理硬件和操作系統(tǒng)的內存模型在不同操作系統(tǒng)和硬件平臺下表現(xiàn)不同,比如有些c/c++程序可能在windows平臺運行正常,而在linux平臺卻運行有問題。
● 請談一談JSP有哪些內置對象?以及這些對象的作用分別是什么?
JSP有9個內置對象:
● 請簡要說明一下JSP和Servlet有哪些相同點和不同點?另外他們之間的聯(lián)系又是什么呢?
JSP 是Servlet技術的擴展,本質上是Servlet的簡易方式,更強調應用的外表表達。JSP編譯后是”類servlet”。Servlet和JSP最主要的不同點在于,Servlet的應用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP的情況是Java和HTML可以組合成一個擴展名為.jsp的文件。JSP側重于視圖,Servlet主要用于控制邏輯
Netty和Tomcat
最大的區(qū)別就在于通信協(xié)議,Tomcat是基于Http協(xié)議的,他的實質是一個基于http協(xié)議的web容器,但是Netty不一樣,他能通過編程自定義各種協(xié)議,因為netty能夠通過codec自己來編碼/解碼字節(jié)流,完成類似redis訪問的功能,這就是netty和tomcat最大的不同。
● 請談談你對Javaweb開發(fā)中的***的理解?
***模型涉及以下三個對象,
(1)事件:用戶對組件的一個操作,稱之為一個事件
(2)事件源:發(fā)生事件的組件就是事件源
(3)事件***(處理器):監(jiān)聽并負責處理事件的方法
執(zhí)行順序:
1、給事件源注冊***
2、組件接受外部作用,也就是事件被觸發(fā)
3、組件產生一個相應的事件對象,并把此對象傳遞給與之關聯(lián)的事件處理器
4、事件處理器啟動,并執(zhí)行相關的代碼來處理該事件。
● 請問過濾器有哪些作用?以及過濾器的用法又是什么呢?
過濾器(filter)是從Servlet 2.3規(guī)范開始增加的功能,對Web應用來說,過濾器是一個駐留在服務器端的Web組件,它可以截取客戶端和服務器之間的請求與響應信息,并對這些信息進行過濾。當Web容器接受到一個對資源的請求時,它將判斷是否有過濾器與這個資源相關聯(lián)。如果有,那么容器將把請求交給過濾器進行處理。在過濾器中,你可以改變請求的內容,或者重新設置請求的報頭信息,然后再將請求發(fā)送給目標資源。
● 請回答一下servlet的生命周期是什么。servlet是否為單例以及原因是什么?
Servlet 通過調用 init () 方法進行初始化。
Servlet 調用 service() 方法來處理客戶端的請求。
Servlet 通過調用 destroy() 方法終止(結束)。
最后,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。
Servlet單實例,減少了產生servlet的開銷;
● 請你說說,cookie 和 session 的區(qū)別?
1、cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務器上。
2、cookie不是很安全,別人可以分析存放在本地的COOKIE并進行COOKIE欺騙,考慮到安全應當使用session。
3、session會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能,考慮到減輕服務器性能方面,應當使用COOKIE。
4、單個cookie保存的數(shù)據(jù)不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。
● 說說你對get和post請求,并且說說它們之間的區(qū)別?
①get請求用來從服務器上獲得資源,而post是用來向服務器提交數(shù)據(jù);
②get將表單中數(shù)據(jù)按照name=value的形式,添加到action 所指向的URL 后面,并且兩者使用"?"連接,而各個變量之間使用"&"連接;post是將表單中的數(shù)據(jù)放在HTTP協(xié)議的請求頭或消息體中,傳遞到action所指向URL;
③get傳輸?shù)臄?shù)據(jù)要受到URL長度限制(1024字節(jié));post可以傳輸大量的數(shù)據(jù),上傳文件通常要使用post方式;
④使用get時參數(shù)會顯示在地址欄上,如果這些數(shù)據(jù)不是敏感數(shù)據(jù)可以使用get;對于敏感數(shù)據(jù)還是應用使用post;
● 請談談,轉發(fā)和重定向之間的區(qū)別?
forward是容器中控制權的轉向,是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL 的響應內容讀取過來,然后把這些內容再發(fā)給瀏覽器,瀏覽器根本不知道服務器發(fā)送的內容是從哪兒來的,所以它的地址欄中還是原來的地址。
redirect就是服務器端根據(jù)邏輯,發(fā)送一個狀態(tài)碼,告訴瀏覽器重新去請求那個地址,因此從瀏覽器的地址欄中可以看到跳轉后的鏈接地址,很明顯redirect無法訪問到服務器保護起來資源,但是可以從一個網站redirect到其他網站。forward更加高效,在有些情況下,比如需要訪問一個其它服務器上的資源,則必須使用重定向
解決session共享問題
方法一、使用Nginx讓它綁定ip,配置Nginx。
方法二、使用spring session+redis的方法解決session共享問題
當一個資源去訪問另一個不同域名或者同域名不同端口的資源時,就會發(fā)出跨域請求。如果此時另一個資源不允許其進行跨域資源訪問,那么訪問的那個資源就會遇到跨域問題。
因為跨域問題是瀏覽器對于ajax請求的一種安全限制:一個頁面發(fā)起的ajax請求,只能是于當前頁同域名的路徑,這能有效的阻止跨站攻擊。
異步查詢數(shù)據(jù),自然是通過ajax查詢,大家首先想起的肯定是jQuery。但jQuery與MVVM的思想不吻合
Jsonp:最早的解決方案,利用script標簽可以跨域的原理實現(xiàn)。缺點:需要服務的支持、只能發(fā)起GET請求
nginx反向代理:利用nginx反向代理把跨域為不跨域,支持各種請求方式。缺點:需要在nginx進行額外配置
CORS(跨域資源共享):規(guī)范化的跨域請求解決方案,安全可靠。
優(yōu)勢:在服務端進行控制是否允許跨域,可自定義規(guī)則、支持各種請求方式
缺點:會產生額外的請求
同源策略
是瀏覽器的安全策略。是一種約定,是瀏覽器最核心最基本的安全功能。如果沒有同源策略,瀏覽器很容易收到XSS,CSRF攻擊。保證用戶信息安全,防止惡意網站竊取數(shù)據(jù)
同源指“協(xié)議+域名(主機)+端口”三者相同。任一不同,都屬于非同源。即使不同域名對應同一IP地址也非同源。
? 當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現(xiàn),此時需增加一個調度中心基于訪問壓力實時管理集群容量,提高集群利用率。此時,用于提高機器利用率的資源調度和治理中心(SOA)是關鍵
服務治理要做什么?
無論是微服務還是SOA,都面臨著服務間的遠程調用。常見的遠程調用方式有以下幾種:
RPC:Remote Produce Call遠程過程調用,類似的還有RMI。自定義數(shù)據(jù)格式,基于原生TCP通信,速度快,效率高。早期的webservice,現(xiàn)在熱門的dubbo,都是RPC的典型
Http:http其實是一種網絡傳輸協(xié)議,基于TCP,規(guī)定了數(shù)據(jù)傳輸?shù)母袷健,F(xiàn)在客戶端瀏覽器與服務端通信基本都是采用Http協(xié)議。也可以用來進行遠程服務調用。缺點是消息封裝臃腫。
現(xiàn)在熱門的Rest風格,就可以通過http協(xié)議來實現(xiàn)。
微服務,更加強調的是獨立、自治、靈活。而RPC方式的限制較多,因此微服務框架中,一般都會采用基于Http的Rest風格服務。
nginx可以作為web服務器,但更多的時候,我們把它作為網關,因為它具備網關必備的功能:
反向代理、負載均衡、動態(tài)路由、請求過濾。
Web服務器分2類:
區(qū)分:web服務器不能解析jsp等頁面,只能處理js、css、html等靜態(tài)資源。
并發(fā):web服務器的并發(fā)能力遠高于web應用服務器。
nginx作為反向代理
什么是反向代理?
nginx可以當做反向代理服務器來使用:
HashMap的底層實現(xiàn)
HashMap底層是數(shù)組和鏈表的結合。HashMap通過key的HashCode經過擾動函數(shù)處理過后得到Hash
值,然后通過位運算判斷當前元素存放的位置,如果當前位置存在元素的話,就判斷該元素與要存入的元素的hash值以及key是否相同,如果相同的話,直接覆蓋,不相同就通過拉鏈法解決沖突。當Map中的元素總數(shù)超過Entry數(shù)組的0.75時,觸發(fā)擴容操作,為了減少鏈表長度,元素分配更均勻。
HashMap基于哈希思想,實現(xiàn)對數(shù)據(jù)的讀寫。當我們將鍵值對傳遞給put()方法時,它調用 鍵對象的hashCode()方法來計算hashcode,然后后找到bucket位置來儲存值對象。當獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然后返回值對象。HashMap使用鏈表 來解決碰撞問題,當發(fā)生碰撞了,對象將會儲存在鏈表的下一個節(jié)點中。HashMap在每個 鏈表節(jié)點中儲存鍵值對對象。當兩個不同的鍵對象的hashcode相同時,它們會儲存在同一個 bucket位置的鏈表中,可通過鍵對象的equals()方法用來找到鍵值對。如果鏈表大小超過閾 值( 8),鏈表就會被改造為樹形結構。
————————————————rehash解決多次擴容后數(shù)據(jù)分配問題
JDK1.8 以后在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為 8)時,將鏈表轉化為紅黑樹,以減少搜索時間。 (一個是鏈表的長度達到8個,一個是數(shù)組的長度達到64個)
那為什么選擇8才會選擇使用紅黑樹呢
為了配合使用分布良好的hashCode,樹節(jié)點很少使用。并且在理想狀態(tài)下,受隨機分布的hashCode影響,鏈表中的節(jié)點遵循泊松分布,而且根據(jù)統(tǒng)計,鏈表中節(jié)點數(shù)是8的概率已經接近千分之一,而且此時鏈表的性能已經很差了。所以在這種比較罕見和極端的情況下,才會把鏈表轉變?yōu)?a target="_blank" >紅黑樹。因為鏈表轉換為紅黑樹也是需要消耗性能的,特殊情況特殊處理,為了挽回性能,權衡之下,才使用紅黑樹,提高性能。也就是大部分情況下,hashmap還是使用的鏈表,如果是理想的均勻分布,節(jié)點數(shù)不到8,hashmap就自動擴容
哈希沖突:如果兩個不同對象的hashCode相同,這種現(xiàn)象稱為hash沖突。
有以下的方式可以解決哈希沖突:
● 請你說明HashMap和Hashtable的區(qū)別?
HashMap和Hashtable都實現(xiàn)了Map接口,因此很多特性非常相似。但是,他們有以下不同點:
HashMap允許鍵和值是null,而Hashtable不允許鍵或者值是null。
Hashtable是同步的,而HashMap不是。HashMap更適合于單線程環(huán)境,而Hashtable適合于多線程環(huán)境。
HashMap提供了可供應用迭代的鍵的集合,因此,HashMap是快速失敗的。
HashMap和TreeMap的區(qū)別
HashMap:數(shù)組方式存儲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實現(xiàn),線程非安全,不允許null,key不可以重復,value允許重
復,存入TreeMap的元素應當實現(xiàn)Comparable接口或者實現(xiàn)Comparator接口,會按照排序后的順序
迭代元素,兩個相比較key不得拋出classCastException。主要用于存入元素的時候對元素進行自動排
序,迭代輸出的時候就按照排序順序輸出。
● 請你說明一下TreeMap的底層實現(xiàn)?
TreeMap 的實現(xiàn)就是紅黑樹數(shù)據(jù)結構,一棵自平衡的排序二叉樹,這樣就可以保證當需要快速檢索指定節(jié)點。
紅黑樹的插入、刪除、遍歷時間復雜度都為O(lgN),所以性能上低于哈希表。但是哈希表無法提供鍵值對的有序輸出,紅黑樹因為是排序插入的,可以按照鍵的值的大小有序輸出。紅黑樹性質:
紅黑樹的性質:
1.節(jié)點是紅色或黑色。
2.根節(jié)點是黑色。
3.每個葉子節(jié)點都是黑色的空節(jié)點(NIL節(jié)點)。
4 每個紅色節(jié)點的兩個子節(jié)點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續(xù)的紅色節(jié)點)
5.從任一節(jié)點到其每個葉子的所有路徑都包含相同數(shù)目的黑色節(jié)點。
平衡二叉樹的性質:
它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹。這個方案很好的解決了二叉查找樹退化成鏈表的問題,把插入,查找,刪除的時間復雜度最好情況和最壞情況都維持在O(logN)。但是頻繁旋轉會使插入和刪除犧牲掉O(logN)左右的時間,不過相對二叉查找樹來說,時間上穩(wěn)定了很多。
區(qū)別:
1、紅黑樹放棄了追求完全平衡,追求大致平衡,在與平衡二叉樹的時間復雜度相差不大的情況下,保證每次插入最多只需要三次旋轉就能達到平衡,實現(xiàn)起來也更為簡單。
2、平衡二叉樹追求絕對平衡,條件苛刻,實現(xiàn)起來比較麻煩,每次插入新節(jié)點之后需要旋轉的次數(shù)不能預知。
● 請說明ArrayList和LinkedList的區(qū)別?
ArrayList和LinkedList都實現(xiàn)了List接口,他們有以下的不同點:
ArrayList是基于索引的數(shù)據(jù)接口,它的底層是數(shù)組。它可以以O(1)時間復雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式存儲它的數(shù)據(jù),每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復雜度是O(n)。
相對于ArrayList,LinkedList的插入,添加,刪除操作速度更快,因為當元素被添加到集合任意位置的時候,不需要像數(shù)組那樣重新計算大小或者是更新索引。
LinkedList比ArrayList更占內存,因為LinkedList為每一個節(jié)點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。
● 請你講講數(shù)組(Array)和列表(ArrayList)的區(qū)別?什么時候應該使用Array而不是ArrayList?
Array可以包含基本類型和對象類型,ArrayList只能包含對象類型。
Array大小是固定的,ArrayList的大小是動態(tài)變化的。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
對于基本類型數(shù)據(jù),集合使用自動裝箱來減少編碼工作量。但是,當處理固定大小的基本數(shù)據(jù)類型的時候,這種方式相對比較慢。
分布式鎖的幾種常用實現(xiàn)方式
分布式的CAP理論告訴我們“任何一個分布式系統(tǒng)都無法同時滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯性(Partition tolerance),最多只能同時滿足兩項。”所以,很多系統(tǒng)在設計之初就要對這三者做出取舍。在互聯(lián)網領域的絕大多數(shù)的場景中,都需要犧牲強一致性來換取系統(tǒng)的高可用性
針對分布式鎖的實現(xiàn),目前比較常用的有以下幾種方案:
基于數(shù)據(jù)庫實現(xiàn)分布式鎖:核心思想是在數(shù)據(jù)庫中創(chuàng)建一個表,表中包含方法名等字段,并在方法名字段上創(chuàng)建唯一索引,想要執(zhí)行某個方法,就使用這個方法名向表中插入數(shù)據(jù),成功插入則獲取鎖,執(zhí)行完成后刪除對應的行數(shù)據(jù)釋放鎖。
基于緩存實現(xiàn)分布式鎖:實現(xiàn)思想:
(1)獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。
(2)獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
(3)釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執(zhí)行delete進行鎖釋放。
基于Zookeeper實現(xiàn)分布式鎖
ZooKeeper是一個為分布式應用提供一致***的開源組件,它內部是一個分層的文件系統(tǒng)目錄樹結構,規(guī)定同一個目錄下只能有一個唯一文件名。(1)創(chuàng)建一個目錄mylock;
(2)線程A想獲取鎖就在mylock目錄下創(chuàng)建臨時順序節(jié)點;
(3)獲取mylock目錄下所有的子節(jié)點,然后獲取比自己小的兄弟節(jié)點,如果不存在,則說明當前線程順序號最小,獲得鎖;
(4)線程B獲取所有節(jié)點,判斷自己不是最小節(jié)點,設置監(jiān)聽比自己次小的節(jié)點;
(5)線程A處理完,刪除自己的節(jié)點,線程B監(jiān)聽到變更事件,判斷自己是不是最小的節(jié)點,如果是則獲得鎖。
什么是分布式文件系統(tǒng):
1、傳統(tǒng)文件系統(tǒng)管理的文件就存儲在本機。
2、分布式文件系統(tǒng)管理的文件存儲在很多機器,這些機器通過網絡連接,要被統(tǒng)一管理。無論是上傳
或是訪問文件,都需要通過管理中心來訪問。
功能豐富:
文件存儲、文件同步、文件訪問、存取負載均衡、在線擴容
適合有大容量存儲需求的應用或系統(tǒng)。
FastDFS兩個主要的角色:Tracker Server和Storage Server
Tracker Server:跟蹤服務器,主要負責調度storage節(jié)點與client通信,在訪問上起負載均衡的作用,
和記錄storage節(jié)點的允許狀態(tài),是連接client和storage節(jié)點的樞紐。
Storage Server:存儲服務器,保存文件和文件的meta data(元數(shù)據(jù)),每個storage server會啟動一
個單獨的線程主動向Tracker cluster中每個tracker server報告其狀態(tài)信息,包括磁盤使用情況,文件同
步情況及文件上傳下載次數(shù)統(tǒng)計等信息。
Group:文件組,多臺Strage Server的集群。上傳一個文件到同組內的一臺機器上后,F(xiàn)astDFS會將該
文件即時同步到同組內的其它所有機器上,起到備份的作用。不同組的服務器,保存的數(shù)據(jù)不同,而且
相互獨立,不進行通信。
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的使用場景中,包含了服務發(fā)現(xiàn)、負載、容錯、網絡傳輸、序列化等組件,而RPC的主要目標是更容易地構建分布式應用。為實現(xiàn)該目標,RPC框架需提供一種透明調用機制,讓使用者不必顯式的區(qū)分本地調用和遠程調用。
1 、服務尋址2 、序列化和反序列化3 、網絡傳輸
部署項目用到的linux命令:
1.進入tomcat的bin目錄 cd /data/apache-tomcat-6.0.39/bin
2.查看tomcat的進程 ps -ef | grep tomcat
3.殺死進程 kill -9 + 進程數(shù)
查看進程 2.1、ps -ef | grep xx 2.2、ps -aux | grep xxx(-aux顯示所有狀態(tài))
查看端口:1、netstat -anp | grep 端口號(狀態(tài)為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 root@192.168.1.1:/data/apache-tomcat-6.0.39/webapps
scp -r 目錄名 遠程計算機用戶名@遠程計算機的ip:遠程計算機存放該目錄的路徑
進程與線程的區(qū)別:
1、進程是資源分配的最小單位,線程是程序執(zhí)行的最小單位(資源調度的最小單位)
2、進程有自己的獨立地址空間,每啟動一個進程,系統(tǒng)就會為它分配地址空間, 而線程是共享進程中的數(shù)據(jù)、地址空間
3、線程之間的通信更方便,同一進程下的線程共享全局變量、靜態(tài)變量等數(shù)據(jù),而進程之間的通信需要以通信的方式(IPC)進行。
4、多進程程序更健壯,多線程程序只要有一個線程死掉,整個進程也死掉了,而一個進程死掉并不會對另外一個進程造成影響,因為進程有自己獨立的地址空間。
● 如何保證線程安全?
通過合理的時間調度,避開共享資源的存取沖突。另外,在并行任務設計上可以通過適當?shù)牟呗?,保證任務與任務之間不存在共享資源
● 線程同步和線程調度的相關方法。
- wait():使一個線程處于等待狀態(tài),并且釋放所持有的對象的鎖;
- sleep():使一個正在運行的線程處于睡眠狀態(tài),是一個靜態(tài)方法,調用此方法要處理異常;
- notify():喚醒一個處于等待狀態(tài)的線程,當然在調用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且與優(yōu)先級無關;
- notityAll():喚醒所有處于等待狀態(tài)的線程,該方法并不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態(tài);
*● Java中有幾種方法可以實現(xiàn)一個線程?用什么關鍵字修飾同步方法? *
有四種實現(xiàn)方法,分別是繼承Thread類與實現(xiàn)Runnable接口,使用Callable和Future創(chuàng)建線程、使用線程池例如用Executor框架。
● 啟動一個線程是用run()還是start()?
啟動一個線程是調用start()方法,使線程所代表的虛擬處理機處于可運行狀態(tài),這意味著它可以由JVM調度并執(zhí)行。這并不意味著線程就會立即運行。run()方法可以產生必須退出的標志來停止一個線程。
● 請說明一下sleep() 和 wait() 有什么區(qū)別?
sleep是線程類(Thread)的方法,導致此線程暫停執(zhí)行指定時間,把執(zhí)行機會給其他線程,但是監(jiān)控狀態(tài)依然保持,到時后會自動恢復。調用sleep不會釋放對象鎖。
wait是Object類的方法,對此對象調用wait方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線程才進入對象鎖定池準備獲得對象鎖進入運行狀態(tài)。
● 請分析一下同步方法和同步代碼塊的區(qū)別是什么?
區(qū)別:同步方法默認用this或者當前類class對象作為鎖;
同步代碼塊可以選擇以什么來加鎖,比同步方法要更細顆粒度,可以選擇只同步會發(fā)生同步問題的部分代碼而不是整個方法。
● 請詳細描述一下線程從創(chuàng)建到死亡的幾種狀態(tài)都有哪些?
新建( new ):新創(chuàng)建了一個線程對象。
可運行( runnable ):線程對象創(chuàng)建后,其他線程(比如 main 線程)調用了該對象 的 start ()方法。該狀態(tài)的線程位于可運行線程池中,等待被線程調度選中,獲取 cpu 的使用權 。
運行( running ):可運行狀態(tài)( runnable )的線程獲得了 cpu 時間片( timeslice ) ,執(zhí)行程序代碼。
阻塞( block ):阻塞狀態(tài)是指線程因為某種原因放棄了 cpu 使用權,阻塞的情況分三種: 等待阻塞、同步阻塞、其他阻塞:
死亡( dead ):線程 run ()、 main () 方法執(zhí)行結束,或者因異常退出了 run ()方法,則該線程結束生命周期。死亡的線程不可再次復生。
● 請問什么是死鎖(deadlock)?
兩個線程或兩個以上線程都在等待對方執(zhí)行完畢才能繼續(xù)往下執(zhí)行的時候就發(fā)生了死鎖。結果就是這些線程都陷入了無限的等待中。如何避免線程死鎖?
只要破壞產生死鎖的四個條件中的其中一個就可以了。
破壞互斥條件:這個條件我們沒有辦法破壞,因為我們用鎖本來就是想讓他們互斥的(臨界資源需要互斥訪問)。
破壞請求與保持條件:一次性申請所有的資源。
破壞不剝奪條件:占用部分資源的線程進一步申請其他資源時,如果申請不到,可以主動釋放它占有的資源。
破壞循環(huán)等待條件:靠按序申請資源來預防。按某一順序申請資源,釋放資源則反序釋放
● JAVA中如何確保N個線程可以訪問N個資源,但同時又不導致死鎖?
使用多線程的時候,一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,并強制線程按照指定的順序獲取鎖。因此,如果所有的線程都是以同樣的順序加鎖和釋放鎖,就不會出現(xiàn)死鎖了。
常用線程池,線程池有哪幾個參數(shù)
Java通過Executors提供四種線程池,分別為:
1)newCachedThreadPool創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
2)newFixedThreadPool 創(chuàng)建一個定長線程池,可控制線程最大并發(fā)數(shù),超出的線程會在隊列中等待。
3)newScheduledThreadPool 創(chuàng)建一個定長線程池,支持定時及周期性任務執(zhí)行。
4)newSingleThreadExecutor 創(chuàng)建一個單線程化的線程池,它只會用唯一的工作線程來執(zhí)行任務,保證所有任務按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行。
參數(shù)
corePoolSize :核心線程數(shù)量
maximumPoolSize :線程最大線程數(shù)
workQueue :阻塞隊列,存儲等待執(zhí)行的任務 很重要 會對線程池運行產生重大影響
keepAliveTime :線程沒有任務時最多保持多久時間終止
unit :keepAliveTime的時間單位
threadFactory :線程工廠,用來創(chuàng)建線程
rejectHandler :當拒絕處理任務時的策略
線程池怎么用
1 2 | ExecutorService cachePool = Executors.newCachedThreadPool(); cachePool.execute(getThread(i)); |
● Synchronized和lock
synchronized當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執(zhí)行該段代碼。Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現(xiàn);synchronized在發(fā)生異常時,會自動釋放線程占有的鎖,因此不會導致死鎖現(xiàn)象發(fā)生;而Lock在發(fā)生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成F死鎖現(xiàn)象,因此使用Lock時需要在finally塊中釋放鎖;Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
● Syncronized鎖,如果用這個關鍵字修飾一個靜態(tài)方法,鎖住了什么?如果修飾成員方法,鎖住了什么?
synchronized修飾靜態(tài)方法以及同步代碼塊的synchronized (類.class)用法鎖的是類,線程想要執(zhí)行對應同步代碼,需要獲得類鎖。
synchronized修飾成員方法,線程獲取的是當前調用該方法的對象實例的對象鎖。
synchronized 和 CAS 的區(qū)別
synchronized
采用的是 CPU 悲觀鎖機制,即線程獲得的是獨占鎖, 其他線程只能依靠阻塞來等待線程釋放鎖。而在 CPU 轉換線程阻塞時會引起線程上下文切換,當有很多線程競爭鎖的時候,會引起 CPU 頻繁的上下文切換導致效率很低。盡管 Java1.6 為 synchronized
做了優(yōu)化,增加了從偏向鎖到輕量級鎖再到重量級鎖的過度,但是在最終轉變?yōu)橹亓考夋i之后,性能仍然較低。
CAS 是比較并替換。它當中使用了3個基本操作數(shù):內存地址 V,舊的預期值 A,要修改的新值 B。采用的是一種樂觀鎖的機制,它不會阻塞任何線程,所以在效率上,它會比 synchronized
要高。所謂樂觀鎖就是:每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。
所以,在并發(fā)量非常高的情況下,我們盡量的用同步鎖,而在其他情況下,我們可以靈活的采用 CAS 機制。
synchronized關鍵字和volatile關鍵字比較:
線程池運行原理分析
1、創(chuàng)建一個線程池,在還沒有任務提交的時候,默認線程池里面是沒有線程的。也可以調用prestartCoreThread方法,來預先創(chuàng)建一個核心線程。
2、線程池里還沒有線程或者線程池里存活的線程數(shù)小于核心線程數(shù)corePoolSize時,這時對于一個新提交的任務,線程池會創(chuàng)建一個線程去處理提交的任務。此時線程池里面的線程會一直存活著,就算空閑時間超過了keepAliveTime,線程也不會被銷毀,而是一直阻塞在那里一直等待任務隊列的任務來執(zhí)行。
3、當線程池里面存活的線程數(shù)已經等于corePoolSize了,對于一個新提交的任務,會被放進任務隊列workQueue排隊等待執(zhí)行。而之前創(chuàng)建的線程并不會被銷毀,而是不斷的去拿阻塞隊列里面的任務,當任務隊列為空時,線程會阻塞,直到有任務被放進任務隊列,線程拿到任務后繼續(xù)執(zhí)行,執(zhí)行完了過后會繼續(xù)去拿任務。這也是為什么線程池隊列要是用阻塞隊列。
4、當線程池里面存活的線程數(shù)已經等于corePoolSize了,并且任務隊列也滿了,這里假設maximumPoolSize>corePoolSize(如果等于的話,就直接拒絕了),這時如果再來新的任務,線程池就會繼續(xù)創(chuàng)建新的線程來處理新的任務,知道線程數(shù)達到maximumPoolSize,就不會再創(chuàng)建了。這些新創(chuàng)建的線程執(zhí)行完了當前任務過后,在任務隊列里面還有任務的時候也不會銷毀,而是去任務隊列拿任務出來執(zhí)行。在當前線程數(shù)大于corePoolSize過后,線程執(zhí)行完當前任務,會有一個判斷當前線程是否需要銷毀的邏輯:如果能從任務隊列中拿到任務,那么繼續(xù)執(zhí)行,如果拿任務時阻塞(說明隊列中沒有任務),那超過keepAliveTime時間就直接返回null并且銷毀當前線程,直到線程池里面的線程數(shù)等于corePoolSize之后才不會進行線程銷毀。
5、如果當前的線程數(shù)達到了maximumPoolSize,并且任務隊列也滿了,這種情況下還有新的任務過來,那就直接采用拒絕的處理器進行處理。默認的處理器邏輯是拋出一個RejectedExecutionException異常。
● 請說明一下線程池有什么優(yōu)勢?
第一:降低資源消耗。第二:提高響應速度。第三:提高線程的可管理性
線程池的運行流程
首先判斷核心線程池里的線程是否都在執(zhí)行任務,如果不是則直接從核心線程池中創(chuàng)建一個線程來執(zhí)行,如果都在忙則判斷任務隊列是否也滿了,沒滿的話將任務放進去等待執(zhí)行,滿了就判斷線程池的全部線程是否都在忙,如果都在忙就交給飽和策略來處理,否則就創(chuàng)建一個線程來幫助核心線程處理任務。
線程阻塞
AQS原理
抽象的隊列式同步器,是除了java自帶的synchronized關鍵字之外的鎖機制,AQS的核心思想是,如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程,并將共享資源設置為鎖定狀態(tài),如果被請求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒時鎖分配的機制,這個機制AQS是用CLH隊列鎖實現(xiàn)的,即將暫時獲取不到鎖的線程加入到隊列中。
CLH隊列是一個虛擬的雙向隊列,虛擬的雙向隊列即不存在隊列實例,僅存在節(jié)點之間的關聯(lián)關系。
AQS是將每一條請求共享資源的線程封裝成一個CLH鎖隊列的一個結點(Node),來實現(xiàn)鎖的分配
主內存:多個線程共享的內存,方法區(qū)和堆屬于主內存區(qū)域。線程工作內存:每個線程獨享的內存。虛擬機棧、本地方法棧、程序計數(shù)器屬于線程獨享的工作內存
Java創(chuàng)建對象的過程:
● JVM加載class文件的原理是什么?
JVM中類的裝載是由ClassLoader和它的子類來實現(xiàn)的,Java ClassLoader 是一個Java運行時系統(tǒng)組件。它負責在運行時查找和裝入類文件的類。
Java中的所有類都需要由類加載器裝載到JVM中才能運行。類加載器的工作就是把class文件從硬盤讀取到內存中。
雙親委派機制:
如果一個類加載器收到了類加載請求,他并不會自己先去加載,而是把這個請求委托給父類的加載器去執(zhí)行;
如果父類加載器還存在其父類加載器,則進一步向上委托,依次遞歸,請求最終達到頂層的啟動類加載器
如果父類加載器可以完成類加載任務就成功返回,如果父類加載器不能完成加載任務,子加載器互嘗試自己去加載
堆內存的分配策略:
1對象優(yōu)先在eden區(qū)分配,Eden區(qū)沒有足夠的空間,將觸發(fā)一次Minor GC。
2大對象直接進入老年代(為了避免為大對象分配內存時由于分配擔保機制帶來的復制而降低效率 ),
3長期存活的對象進入老年代
4動態(tài)對象年齡判斷:如果Survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入到老年代,無需等到MaxTenuringThreshold中要求的年齡
5空間分配擔保:-XX: HandlePromotionFailure
Minor GC與Full GC分別在什么時候發(fā)生?
觸發(fā)MinorGC(Young GC)
虛擬機在進行minorGC之前會判斷老年代最大的可用連續(xù)空間是否大于新生代的所有對象總空間
1、如果大于的話,直接執(zhí)行minorGC
2、如果小于,判斷是否開啟HandlerPromotionFailure,沒有開啟直接FullGC
3、如果開啟了HanlerPromotionFailure, JVM會判斷老年代的最大連續(xù)內存空間是否大于歷次晉升的大小,如果小于直接執(zhí)行FullGC
觸發(fā)FullGC
老年代空間不足
如果創(chuàng)建一個大對象,Eden區(qū)域當中放不下這個大對象,會直接保存在老年代當中,如果老年代空間也不足,就會觸發(fā)Full GC。為了避免這種情況,最好就是不要創(chuàng)建太大的對象。
持久代空間不足
如果有持久代空間的話,系統(tǒng)當中需要加載的類,調用的方法很多,同時持久代當中沒有足夠的空間,就出觸發(fā)一次Full GC
YGC出現(xiàn)promotion failure
Minor GC 和 Full GC 有什么不同呢?
新生代 GC(Minor GC):指發(fā)生新生代的的垃圾收集動作,Minor GC 非常頻繁,回收速度一般也比較快。
老年代 GC(Major GC/Full GC):指發(fā)生在老年代的 GC,出現(xiàn)了 Major GC 經常會伴隨至少一次的 Minor
GC(并非絕對),Major GC 的速度一般會比 Minor GC 的慢 10 倍以上
分代收集器:
老生代和新生代兩個區(qū)域,而新生代又會分為:Eden 區(qū)和兩個 Survivor區(qū)(From Survivor、To Survivor)
為什么 Survivor 分區(qū)不能是 0 個?
如果 Survivor 是 0 的話,也就是說新生代只有一個 Eden 分區(qū),每次垃圾回收之后,存活的對象都會進入老生代,這樣老生代的內存空間很快就被占滿了,從而觸發(fā)最耗時的 Full GC ,顯然這樣的收集器的效率是我們完全不能接受的。
為什么 Survivor 分區(qū)不能是 1 個?
如果 Survivor 分區(qū)是 1 個的話,假設我們把兩個區(qū)域分為 1:1,那么任何時候都有一半的內存空間是閑置的,顯然空間利用率太低不是最佳的方案。但如果設置內存空間的比例是 8:2 ,只是看起來似乎“很好”,假設新生代的內存為 100 MB( Survivor 大小為 20 MB ),現(xiàn)在有 70 MB 對象進行垃圾回收之后,剩余活躍的對象為 15 MB 進入 Survivor 區(qū),這個時候新生代可用的內存空間只剩了 5 MB,這樣很快又要進行垃圾回收操作,顯然這種垃圾回收器最大的問題就在于,需要頻繁進行垃圾回收。
為什么 Survivor 分區(qū)是 2 個?
如果 Survivor 分區(qū)有 2 個分區(qū),我們就可以把 Eden、From Survivor、To Survivor 分區(qū)內存比例設置為 8:1:1 ,那么任何時候新生代內存的利用率都 90% ,這樣空間利用率基本是符合預期的。再者就是虛擬機的大部分對象都符合“朝生夕死”的特性,所以每次新對象的產生都在空間占比比較大的 Eden 區(qū),垃圾回收之后再把存活的對象方法存入 Survivor 區(qū),如果是 Survivor 區(qū)存活的對象,那么“年齡”就 +1 ,當年齡增長到 15 (可通過設定)對象就升級到老生代。
● 請說明一下垃圾回收的優(yōu)點以及原理
使得Java程序員在編寫程序的時候不再需要考慮內存管理。由于有個垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用才有"作用域"。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個單獨的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。不再會被使用的對象的內存不能被回收,就是內存泄露
判斷對象是否可回收的方法
引用計數(shù)法:給對象中添加一個引用計數(shù)器,每當有一個地方引用它,計數(shù)器就加 1;當引用失效,計數(shù)器就減 1;任何時候計數(shù)器為 0 的對象就是不可能再被使用的
可達性分析法:通過一系列的稱為 “GC Roots” 的對象作為起點,從這些節(jié)點開始向下搜索,節(jié)點所走過
的路徑稱為引用鏈,當一個對象到 GC Roots 沒有任何引用鏈相連的話,則證明此對象是不可用的
強引用、軟引用、弱引用、虛引用(虛引用與軟引用和弱引用的區(qū)別、軟引用能帶來的好處)
1.強引用
以前我們使用的大部分引用實際上都是強引用,這是使用最普遍的引用。如果一個對象具有強引用,那就類似于必
不可少的生活用品,垃圾回收器絕不會回收它。當內存空 間不足,Java 虛擬機寧愿拋出 OutOfMemoryError 錯
誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題
2.軟引用
如果一個對象只具有軟引用,那就類似于可有可無的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如
果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可
用來實現(xiàn)內存敏感的高速緩存。
軟引用可以和一個引用隊列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對象被垃圾回收,JAVA 虛擬機就會把這個軟引用加入到與之關聯(lián)的引用隊列中
3.弱引用
如果一個對象只具有弱引用,那就類似于可有可無的生活用品。弱引用與軟引用的區(qū)別在:只具有弱引用的對象
擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優(yōu)先級很低的線程, 因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。
弱引用可以和一個引用隊列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對象被垃圾回收,Java 虛擬機就
會把這個弱引用加入到與之關聯(lián)的引用隊列中。
4.虛引用
虛引用主要用來跟蹤對象被垃圾回收的活動 ,在程序設計中一般很少使用弱引用與虛引用,使用軟引用的情況較多,因為軟引用可以加速 JVM對垃圾內存的回收速度,可以維護系統(tǒng)的運行安全,防止內存溢出等問題的產生**
如何判斷一個常量是廢棄常量
運行時常量池主要回收的是廢棄的常量。
假如在常量池中存在字符串 "abc",如果當前沒有任何 String 對象引用該字符串常量的話,就說明常量 "abc" 就是
廢棄常量,如果這時發(fā)生內存回收的話而且有必要的話,"abc" 就會被系統(tǒng)清理出常量池。
如何判斷一個類是無用的類
方法區(qū)主要回收的是無用的類,類需要同時滿足下面 3 個條件才能算是 “無用的類” :
1、該類所有的實例都已經被回收,也就是 Java 堆中不存在該類的任何實例。
2、加載該類的 ClassLoader 已經被回收。
3、該類對應的 java.lang.Class 對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。
垃圾回收算法:
1、標記-清除算法
算法分為“標記”和“清除”階段:首先標記出所有需要回收的對象,在標記完成后統(tǒng)一回收所有被標記的對象。它是
最基礎的收集算法,效率也很高,但是會帶來兩個明顯的問題:\1. 效率問題\2. 空間問題
2、復制算法
為了解決效率問題,“復制”收集算法出現(xiàn)了。它可以將內存分為大小相同的兩塊,每次使用其中的一塊。當這一塊
的內存使用完后,就將還存活的對象復制到另一塊去,然后再把使用的空間一次清理掉。這樣就使每次的內存回收
都是對內存區(qū)間的一半進行回收。
3、標記-整理算法
根據(jù)老年代的特點特出的一種標記算法,標記過程仍然與“標記-清除”算法一樣,但后續(xù)步驟不是直接對可回收對象回收,而是讓所有存活的對象向一端移動,然后直接清理掉端邊界以外的內存。
4、分代收集算法
當前虛擬機的垃圾收集都采用分代收集算法,根據(jù)對象存活周期的不同將內存分為幾塊。一般將 java 堆分為新生代和老年代,這樣我們就可以根據(jù)各個年代的特點選擇合適的垃圾收集算法。
比如在新生代中,每次收集都會有大量對象死去,所以可以選擇復制算法,只需要付出少量對象的復制成本就可以
完成每次垃圾收集。而老年代的對象存活幾率是比較高的,而且沒有額外的空間對它進行分配擔保,所以我們必須
選擇“標記-清除”或“標記-整理”算法進行垃圾收集。
垃圾收集器
1、 Serial 收集器 它的 “單線程” 的意義不僅僅意味著它只會使用一條垃圾收集線程去完成垃圾收集工作,更重要的是它在進行垃圾收集工作的時候必須暫停其他所有的工作線程,直到它收集結束。 新生代采用復制算法,老年代采用標記-整理算法
2、ParNew 收集器其實就是 Serial 收集器的多線程版本,除了使用多線程進行垃圾收集外,其余行為(控制參數(shù)、收集算法、回收策略等等)和 Serial 收集器完全一樣
3 、Parallel Scavenge 收集器它關注點是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的關注點更多的是用戶線程的停頓時間(提高用戶體驗)。 新生代采用復制算法,老年代采用標記-整理算法。
4、Serial Old 收集器,它是一個單線程收集器。它主要有兩大用途:一種用途是在 JDK1.5 以及以前的
版本中與 Parallel Scavenge 收集器搭配使用,另一種用途是作為 CMS 收集器的后備方案。
5 、Parallel Old 收集器
6 、CMS 收集器,是一種以獲取最短回收停頓時間為目標的收集器。它而非常符合在注重用戶體驗的應用上使用。CMS(Concurrent Mark Sweep)收集器是 HotSpot 虛擬機第一款真正意義上的并發(fā)收集器,它第一次實現(xiàn)了讓垃圾收集線程與用戶線程(基本上)同時工作
7、G1 收集器是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內存的機器. 以極高概率滿
足 GC 停頓時間要求的同時,還具備高吞吐量性能特征.
volatile的作用
保證共享變量的可見性:使用volatile修飾的變量,任何線程對其進行操作都是在主內存中進行的,不會產生副本,從而保證共享變量的可見性。防止局部指令重排序:happens-before規(guī)則中的volatile變量規(guī)則規(guī)定了一個線程先去寫一個volatile變量,然后一個線程去讀這個變量,那么這個寫操作的結果一定對讀的這個線程可見。volatile如何防止指令重排序
volatile是通過內存屏障來防止指令重排序的。volatile防止指令重排序具體步驟:
在每個volatile寫操作的前面插入一個StoreStore屏障。在每個volatile寫操作的后面插入一個StoreLoad屏障。在每個volatile讀操作的后面插入一個LoadLoad屏障。在每個volatile讀操作的后面插入一個LoadStore屏障。
認證授權是如何實現(xiàn)的? Spring security + Oauth2完成用戶認證及用戶授權。認證授權流程如下:
1、用戶請求認證服務完成身份認證。
2、認證服務下發(fā)用戶身份令牌和JWT令牌,擁有身份令牌表示身份合法,Jwt令牌用于完成授權。
3、用戶攜帶jwt令牌請求資源服務。
4、網關校驗用戶身份令牌的合法,不合法表示用戶沒有登錄,如果合法則放行繼續(xù)訪問。
5、資源服務獲取jwt令牌,根據(jù)jwt令牌完成授權
認證與授權實現(xiàn)思路
如果系統(tǒng)的模塊多,每個模塊都需要就行授權與認證,所以選擇基于token的形式進行授權與認證,用戶根據(jù)用戶名密碼認證成功,然后獲取當前用戶角色的一系列權限值,并以用戶名為key,權限列表為value的形式存入redis緩存中,根據(jù)用戶名相關信息生成token返回,瀏覽器將token記錄到cookie中,每次調用api接口都默認將token攜帶到header請求頭中,Spring-security解析header頭獲取token信息,解析token獲取當前用戶名,根據(jù)用戶名就可以從redis中獲取權限列表,這樣Spring-security就能夠判斷當前請求是否有權限訪問
使用rabbitMQ
1、平臺包括多個站點,頁面歸屬不同的站點,需求是發(fā)布一個頁面應將該頁面發(fā)布到所屬站點的服務器上。
2、每個站點服務部署CMS Client程序,并與交換機綁定,綁定時指定站點Id為routingKey。
指定站點id為routingKey就可以實現(xiàn)cms client只能接收到所屬站點的頁面發(fā)布消息。
3、頁面發(fā)布程序向MQ發(fā)布消息時指定頁面所屬站點Id為routingKey,根據(jù)routingKey將消息發(fā)給指定的
CMS Client。
分布式事務:
1、在微服務中使用Spring 聲明式事務控制方式進行控制,在Service方法上添加@Transctional注解即可實現(xiàn)事務
控制,它控制的是MySQL的本地事務。
2、項目中存在分布式事務控制,比如下單支付、課程發(fā)布等地址都用到了分布式事務。
本項目實現(xiàn)分布式事務控制實現(xiàn)最終數(shù)據(jù)一致性,做法是:
a、將分布式事務拆分為多個本地事務。
b、提交事務前每個參與者要通過數(shù)據(jù)校驗,和資源預留。
c、由消息隊列去通知多個事務參與者完成本地事務的提交。
d、提交失敗的本地事務會重試。
項目中課程搜索采用ElasticSearch來完成。實現(xiàn)方法是:
1、使用 Logstash(logstash是ES下的一款開源軟件,它能夠同時 從多個來源采集數(shù)據(jù)、轉換數(shù)據(jù))將MySQL中
的課程信息讀取到ES中創(chuàng)建索引,使用IK分詞器進行分詞。
2、使用 Java High Level REST Client完成搜索。
3、生產環(huán)境使用ES部署為集群。
系統(tǒng)對異常的處理使用統(tǒng)一的異常處理流程。
1、自定義異常類型。
2、自定義錯誤代碼及錯誤信息。
3、對于可預知的異常由程序員在代碼中主動拋出自定義異常類型的異常,拋出異常時需要指定錯誤代碼。
4、對于不可預知的異常(運行時異常)由SpringMVC統(tǒng)一捕獲Exception類型的異常,由統(tǒng)一的異常捕獲類來解析處理,并轉換為與自定義異常類型一致的信息格式(錯誤代碼+錯誤信息)。
5、可預知的異常及不可預知的運行時異常最終會采用統(tǒng)一的信息格式(錯誤代碼+錯誤信息)來表示,最終也會隨請求響應給客戶端。
http協(xié)議處理視頻流
http采用DASH傳輸視頻流,原理是DASH服務器將視頻進行了切片,MPD是一個XML,為接收端播放器提供表示不同分片的URL、時序、比特率、清晰度等信息。客戶端通過接受、解析MPD文件作為自適應流的依據(jù),客戶端基于MPD信息為分片發(fā)送HTTP請求,然后客戶端的媒體播放器為收到的分片進行解碼和播放。
你在開發(fā)中遇到什么問題?是怎么解決的?
例子:
在處理訂單時要用到定時任務,當時采用的是Spring Task來完成,由于一個訂單服務會部署多個,多個訂單服務
同時去處理任務會造成任務被重復處理的情況,如何解決任務的重復處理。
解決:
采用樂觀鎖解決,在任務表中設置一個version字段記錄版本號,取出任務記錄同時拿到任務的版本號,執(zhí)行前對
任務進行鎖定,具體的做法是執(zhí)行update根據(jù)當前版本號將版本號加1,update成功表示鎖定任務成功,即可開始執(zhí)行任務。
例子:
Redis服務器 can not get resource from pool. 1000個線程并發(fā)還能跑,5000個線程的時候出現(xiàn)這種問題,查后臺debug日志,發(fā)現(xiàn)redis 線程池不夠。剛開始設置的是:
解決:順便也改了一下jdbc 的連接池參數(shù),最大空閑和最大連接數(shù)都改成1000.在測一下??梢?/p>
例子:
注冊中心和服務提供者集群注冊失敗,啟動報錯
解決:修改yml文件,修改啟動類上的注解,yml文件縮進出了問題,服務端啟動類上應該添加注解@EnableEurekaServer,客戶端@EnableDiscoveryClient
例子:
xml文件配置錯誤,頁面訪問一直無數(shù)據(jù)
解決:根據(jù)瀏覽器的開發(fā)工具,定位錯誤,檢查xml文件的SQL,namespace,parameterType等是否正確,是否假如應有的注解
例子:
git合并沖突,甲乙都是根據(jù)point.java文件進行開發(fā),甲開發(fā)出來版本2,并且提交了代碼,乙開發(fā)出來版本3,也需要提交代碼,此時將會報錯存在沖突。因為甲提交版本之后,此時遠端的代碼已經是版本2了,而乙是在版本1的基礎上進行開發(fā)出了版本3,所以乙想要提交代碼,勢必要將自己的代碼更新為版本2的代碼,然后在進行提交
解決:拉去遠端代碼,存在沖突,會報錯。此時我們需要將本地代碼暫存起來stash;更新本地代碼,將本地代碼版本更新和遠端的代碼一致,將暫存的代碼合并到更新后的代碼后,有沖突的要手動解決沖突,然后提交解決沖突后的代碼。Git<resolve conflict
例子:
支付接口采用微信的掃碼支付拿到需求后,首先去閱讀微信的接口文檔,重點閱讀統(tǒng)一下單、支付結果通知、支付結果查詢三個接口。下載官方提供的sdk編寫單元測試用例測試每個接口。測試時沒有使用微信的沙箱測試,直接使用正式接口,將金額改的小一些進行測試。單元測試通過后開發(fā)整個支付功能,最終集成測試通過。
解決:訂單支付接口參數(shù)的簽名問題,當時是因為自己沒有仔細看接口文檔導致少寫一個必填參數(shù)一直報簽名失敗,隨后將所有必填參數(shù)填寫完成,最終解決問題。
例子:
一個接口出現(xiàn)Bug你是怎么調試的?
1、接口的開發(fā)需要前端和服務端共同調試,要仔細閱讀測試人員反映的bug信息,判斷這個bug是服務端的bug還
是前端的bug。通常服務接口開發(fā)完成會使用postman工具進行測試,測試沒有問題再提交到Git或SVN。
2、找到bug的出錯點就可以根據(jù)bug信息進行修改。修改完成需要前后端再次連調測試,按照測試人員提交的測試流程重新進行測試,測試通過將此bug置為已解決。
聯(lián)系客服