6七、分佈式理論懂多少,說一下(CAP,Base,paxos)
CAP理論:一個分佈式系統不可能同時知足一致性(C:Consistency)、可用性(A:Availability)和分區容錯性(P:Partition tolerance)這三個基本需求,最多隻能同時知足其中的兩項。
Base理論:BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的簡寫。
BASE是對CAP中一致性和可用性權衡的結果,其來源於對大規模互聯網系統分佈式實踐的總結,是基於CAP定理逐步演化而來的,其核心思想是即便沒法作到強一致性(Strong consistency),但每一個應用均可以根據自身的業務特色,採用適當的方式來使系統達到最終一致性(Eventual consistency)。
Paxos(分佈式一致性算法)做爲分佈式系統的基石。
6八、分佈式事務有了解嗎
6九、RabbitMQ消息隊列丟失消息,重複消費問題
70,Redis和memcached
7一、看你項目用到Spring boot,那有用過Spring cloud嗎
7二、RPC說一下
7三、說一下你對微服務的理解,與SOA的區別
7四、跟我介紹一下區塊鏈~
7五、怎麼看待國內區塊鏈的發展
數據庫數據同步
tomcat 分庫jar包管理
讀寫鎖
一、明確項目是作什麼的
二、明確項目的價值。(爲何作這個項目,它解決了用戶什麼痛點,它帶來什麼價值?)
三、明確項目的功能。(這個項目涉及哪些功能?)
四、明確項目的技術。(這個項目用到哪些技術?)
五、明確我的在項目中的位置和做用。(你在這個項目的承擔角色?)
六、明確項目的總體架構。
七、明確項目的優缺點,若是從新設計你會如何設計。
八、明確項目的亮點。(這個項目有什麼亮點?)
九、明確技術成長。(你經過這個項目有哪些技術成長?)
Java基礎
一、List 和 Set 的區別
1.List和Set都是接口繼承於Collection接口。
2.最大的不一樣就是List是能夠重複的。而Set是不能重複的。(注意:元素雖然無放入順序,可是元素在set中的位置是有該元素的HashCode決定的,其位置實際上是固定的)
3.List接口有三個實現類:LinkedList,ArrayList,Vector ,Set接口有兩個實現類:HashSet(底層由HashMap實現),LinkedHashSet
4.List適合常常追加數據,插入,刪除數據。但隨機取數效率比較低。
5.Set適合常常地隨機儲存,插入,刪除。可是在遍歷時效率比較低。
二、HashSet 是如何保證不重複的 ?
在向hashSet中add()元素時,判斷元素是否存在的依據,不只僅是hash碼值就可以肯定的,同時還要結合equles方法。
三、HashMap 是線程安全的嗎,爲何不是線程安全的(最好畫圖說明多線程環境下不安全)?
不是線程安全的。
不安全的緣由. resize死循環
四、HashMap 的擴容過程
使用一個容量更大的數組來代替已有的容量小的數組,transfer()方法將原有Entry數組的元素拷貝到新的Entry數組裏。
五、HashMap 1.7 與 1.8 的 區別,說明 1.8 作了哪些優化,如何優化的?
JDK1.7用的鏈表散列結構,JDK1.8用的紅黑樹
在擴充HashMap的時候,JDK1.7的從新計算hash,
JDK1.7只須要看看原來的hash值新增的那個bit是1仍是0就行了,是0的話索引沒變,是1的話索引變成「原索引+oldCap;
DK1.7中rehash的時候,舊鏈表遷移新鏈表的時候,若是在新表的數組索引位置相同,則鏈表元素會倒置,可是從上圖能夠看出,
JDK1.8不會倒置
六、final finally finalize
final修飾符(關鍵字)。被final修飾的類,就意味着不能再派生出新的子類,不能做爲父類而被子類繼承。
finally是在異常處理時提供finally塊來執行任何清除操做。無論有沒有異常被拋出、捕獲,finally塊都會被執行。
finalize是方法名。java技術容許使用finalize()方法在垃圾收集器將對象從內存中清除出去以前作必要的清理工做。
七、強引用 、軟引用、 弱引用、虛引用
new一個對象,強引用不會被GC回收。
若是一個對象只具備軟引用,那就相似於可有可物的生活用品。
若是一個對象只具備弱引用,那就相似於可有可物的生活用品。弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。
在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。
當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中
八、Java反射
反射就是把java類中的各類成分映射成一個個的Java對象
九、Arrays.sort 實現原理和 Collection 實現原理
在jdk7之前的版本中sort()的實現原理是:基本類型使用優化後的快速排序,其餘類型使用優化後的歸併排序,jdk7之後若是jdk7之後修改了排序策略:若是JVM啓動參數配置了-Djava.util.Arrays.useLegacyMergeSort%3Dtrue+那麼就會執行上面所說的排序策略(優化的歸併排序),不然將會執行TimSort排序。&oq=在jdk7之前的版本中sort()的實現原理是:基本類型使用優化後的快速排序,其餘類型使用優化後的歸併排序,jdk7之後若是jdk7之後修改了排序策略:若是JVM啓動參數配置了-Djava.util.Arrays.useLegacyMergeSort%3Dtrue++那麼就會執行上面所說的排序策略(優化的歸併排序),不然將會執行TimSort排序。
事實上Collections.sort方法底層就是調用的array.sort方法
十、LinkedHashMap的應用
LinkedHashMap是Map接口的哈希表和連接列表實現,具備可預知的迭代順序。LinkedHashMap實現與HashMap的不一樣之處在於,LinkedHashMap維護着一個運行於全部條目的雙重連接列表。此連接列表定義了迭代順序,該迭代順序能夠是插入順序(insert-order)或者是訪問順序,其中默認的迭代訪問順序就是插入順序,便可以按插入的順序遍歷元素,這點和HashMap有很大的不一樣。
十一、cloneable接口實現原理
其實,Cloneable接口在這裏起到了一種標識的做用,代表實現它的類具有了實例拷貝功能
由於若是不繼承自Cloneable接口,當調用clone()時會拋出CloneNotSupportedException異常
十二、異常分類以及處理機制
拋出異常有三種形式,一是throw,一個throws,還有一種系統自動拋異常。
針對性處理方式:捕獲異常
1三、wait和sleep的區別
sleep() 方法是線程類(Thread)的靜態方法,讓調用線程進入睡眠狀態,讓出執行機會給其餘線程,等到休眠時間結束後,線程進入就緒狀態和其餘線程一塊兒競爭cpu的執行時間。
wait()是Object類的方法,當一個線程執行到wait方法時,它就進入到一個和該對象相關的等待池,同時釋放對象的機鎖,使得其餘線程可以訪問,能夠經過notify,notifyAll方法來喚醒等待的線程
1四、數組在內存中如何分配
一、簡單的值類型的數組,每一個數組成員是一個引用(指針),引用到棧上的空間(由於值類型變量的內存分配在棧上)
二、引用類型,類類型的數組,每一個數組成員還是一個引用(指針),引用到堆上的空間(由於類的實例的內存分配在堆上)
Java 併發
一、synchronized 的實現原理以及鎖優化?
原理:synchronized底層是經過一個monitor的對象阻塞和獲取。
對代碼同步:指令執行時,monitor的進入數減1,若是減1後進入數爲0,那線程退出monitor,再也不是這個monitor的全部者。其餘被這個monitor阻塞的線程能夠嘗試去獲取這個 monitor 的全部權。
對方法同步:常量池中多了ACC_SYNCHRONIZED標示符。JVM就是根據該標示符來實現方法的同步的:當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標誌是否被設置,若是設置了,執行線程將先獲取monitor,獲取成功以後才能執行方法體,方法執行完後再釋放monitor。在方法執行期間,其餘任何線程都沒法再得到同一個monitor對象。
重量級鎖:Mutex Lock 監視器鎖monitor本質就是依賴於底層的操做系統的Mutex Lock來實現的。
二、volatile 的實現原理?
JVM就會向處理器發送一條Lock前綴的指令,將這個變量所在緩存行的數據寫回到系統內存。可是就算寫回到內存,若是其餘處理器緩存的值仍是舊的,再執行計算操做就會有問題,因此在多處理器下,爲了保證各個處理器的緩存是一致的,就會實現緩存一致性協議,每一個處理器經過嗅探在總線上傳播的數據來檢查本身緩存的值是否是過時了,當處理器發現本身緩存行對應的內存地址被修改,就會將當前處理器的緩存行設置成無效狀態,當處理器要對這個數據進行修改操做的時候,會強制從新從系統內存裏把數據讀處處理器緩存裏。
三、Java 的信號燈?
Semaphore能夠維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore能夠控制同時訪問資源的線程個數,例如,實現一個文件容許的併發訪問數。
Semaphore實現的功能就相似廁全部5個坑,假若有十我的要上廁所,那麼同時能有多少我的去上廁所呢?同時只能有5我的可以佔用,當5我的中的任何一我的讓開後,其中在等待的另外5我的中又有一個能夠佔用了。
另外等待的5我的中能夠是隨機得到優先機會,也能夠是按照先來後到的順序得到機會,這取決於構造Semaphore對象時傳入的參數選項。
單個信號量的Semaphore對象能夠實現互斥鎖的功能,而且能夠是由一個線程得到了「鎖」,再由另外一個線程釋放「鎖」,這可應用於死鎖恢復的一些場合。
四、synchronized 在靜態方法和普通方法的區別?
synchronized修飾不加static的方法,鎖是加在單個對象上,不一樣的對象沒有競爭關係;修飾加了static的方法,鎖是加載類上,這個類全部的對象競爭一把鎖。
五、怎麼實現全部線程在等待某個事件的發生纔會去執行?
柵欄CyclicBarrier
設置柵欄的初始值爲1,當事件發生時,調用barrier.wait()衝破設置的柵欄,將調用指定的Runable線程執行,在該線程中啓動N個新的子線程執行。這個方法並非讓執行中的線程所有等待在某個點,待某一事件發生後繼續執行。
CountDownLatch
CountDownLatch是一個計數器閉鎖,主要的功能就是經過await()方法來阻塞住當前線程,而後等待計數器減小到0了,再喚起這些線程繼續執行。 這個類裏主要有兩個方法,一個是向下減計數器的方法:countdown(),其實現的核心代碼以下:
public boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } }
很簡單,若是取得當前的狀態爲0,說明這個鎖已經結束,直接返回false;若是沒有結束,而後去設置計數器減1,若是compareAndSetState不成功,則繼續循環執行。 而其中的一直等待計數器歸零的方法是await()。
經過CountDownLatch能夠作幾件事情:
1. 主線程控制同時啓動一組線程
2. 主線程等待各子線程所有執行完畢後再往下執行:
Semaphore
Semaphore與CountDownLatch類似,不一樣的地方在於Semaphore的值被獲取到後是能夠釋放的,並不像CountDownLatch那樣一直減到底。它也被更多地用來限制流量,相似閥門的 功能。若是限定某些資源最多有N個線程能夠訪問,那麼超過N個主不容許再有線程來訪問,同時當現有線程結束後,就會釋放,而後容許新的線程進來。有點相似於鎖的lock與 unlock過程。相對來講他也有兩個主要的方法:
- 用於獲取權限的acquire(),其底層實現與CountDownLatch.countdown()相似;
- 用於釋放權限的release(),其底層實現與acquire()是一個互逆的過程。
CyclicBarrier
CyclicBarrier是用來一個關卡來阻擋住全部線程,等全部線程所有執行到關卡處時,再統一執行下一步操做,它裏面最重要的方法是await()方法,其實現以下:
即每一個線程執行完後調用await(),而後在await()裏,線程先將計數器減1,若是計數器爲0,則執行定義好的操做,而後再繼續執行原線程的內容。
這個類比以前兩個類的一個好處是有點相似於切面編程,可讓咱們在同類線程的某個切面切入一塊邏輯,而且能夠同步全部的線程的執行速度。
六、CAS?CAS 有什麼缺陷,如何解決?
CAS解決高併發時數據一致性問題,只須要在進行set操做時,compare一下初始值,若是初始值變換,不容許set成功。
++i是cas操做,利用CPU的CAS指令,同時藉助JNI來完成Java的非阻塞算法。其它原子操做都是利用相似的特性完成的。
CAS的缺點:
1.CPU開銷較大
在併發量比較高的狀況下,若是許多線程反覆嘗試更新某一個變量,卻又一直更新不成功,循環往復,會給CPU帶來很大的壓力。
2.不能保證代碼塊的原子性
CAS機制所保證的只是一個變量的原子性操做,而不能保證整個代碼塊的原子性。好比須要保證3個變量共同進行原子性的更新,就不得不使用Synchronized了。
3.ABA問題
這是CAS機制最大的問題所在。
引用原書的話:若是在算法中的節點能夠被循環使用,那麼在使用「比較並交換」指令就可能出現這種問題,在CAS操做中將判斷「V的值是否仍然爲A?」,而且若是是的話就繼續執行更新操做,在某些算法中,若是V的值首先由A變爲B,再由B變爲A,那麼CAS將會操做成功。
在變量前面追加上版本號
Java 1.5中提供了AtomicStampedReference和AtomicMarkableReference來解決ABA問題。
七、synchronized 和 lock 有什麼區別?
synchronized是java中的一個關鍵字,也就是說是Java語言內置的特性。
Lock是一個接口 Lock接口中每一個方法的使用,lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用來獲取鎖的。
八、Hashtable 是怎麼加鎖的 ?
HashTable是線程安全的,內部的方法基本都是synchronized。
九、HashMap 的併發問題?
resize死循環
十、ConcurrenHashMap 介紹?1.8 中爲何要用紅黑樹?
java8不是用紅黑樹來管理hashmap,而是在hash值相同的狀況下(且重複數量大於8),用紅黑樹來管理數據。 紅黑樹至關於排序數據。能夠自動的使用二分法進行定位。性能較高。
在ConcurrentHashMap中,就是把Map分紅了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪一個Segment中:
ConcurrentHashMap中默認是把segments初始化爲長度爲16的數組。
根據ConcurrentHashMap.segmentFor的算法,三、4對應的Segment都是segments[1],7對應的Segment是segments[12]。
(1)Thread1和Thread2前後進入Segment.put方法時,Thread1會首先獲取到鎖,能夠進入,而Thread2則會阻塞在鎖上:
(2)切換到Thread3,也走到Segment.put方法,由於7所存儲的Segment和三、4不一樣,所以,不會阻塞在lock():
人很聰明,真的很聰明。既然不能全鎖(HashTable)又不能不鎖(HashMap),因此就搞個部分鎖,只鎖部分,用到哪部分就鎖哪部分。一個大倉庫,裏面有若干個隔間,每一個隔間都有鎖,同時只容許一我的進隔間存取東西。可是,在存取東西以前,須要有一個全局索引,告訴你要操做的資源在哪一個隔間裏,而後當你看到隔間空閒時,就能夠進去存取,若是隔間正在佔用,那你就得等着。聰明!!
十一、AQS
抽象的隊列式的同步器,AQS定義了一套多線程訪問共享資源的同步器框架,許多同步類實現都依賴於它,如經常使用的ReentrantLock/Semaphore/CountDownLatch...。
AQS提供了一種原子式管理同步狀態、阻塞和喚醒線程功能以及隊列模型的簡單框架。
十二、如何檢測死鎖?怎麼預防死鎖?
有兩個容器,一個用於保存線程正在請求的鎖,一個用於保存線程已經持有的鎖。每次加鎖以前都會作以下檢測:
1)檢測當前正在請求的鎖是否已經被其它線程持有,若是有,則把那些線程找出來
2)遍歷第一步中返回的線程,檢查本身持有的鎖是否正被其中任何一個線程請求
若是第二步返回真,表示出現了死鎖
三種用於避免死鎖的技術:
一、加鎖順序(線程按照必定的順序加鎖)
二、加鎖時限(線程嘗試獲取鎖的時候加上必定的時限,超過期限則放棄對該鎖的請求,並釋放本身佔有的鎖)
三、死鎖檢測
1三、Java 內存模型?
1四、如何保證多線程下 i++ 結果正確?
- volatile解決了線程間共享變量的可見性問題
- 使用volatile會增長性能開銷
- volatile並不能解決線程同步問題
- 解決i++或者++i這樣的線程同步問題須要使用synchronized或者AtomicXX系列的包裝類,同時也會增長性能開銷
1五、線程池的種類,區別和使用場景?
一個線程從被提交(submit)到執行共經歷如下流程:
- 線程池判斷核心線程池裏是的線程是否都在執行任務,若是不是,則建立一個新的工做線程來執行任務。若是核心線程池裏的線程都在執行任務,則進入下一個流程
- 線程池判斷工做隊列是否已滿。若是工做隊列沒有滿,則將新提交的任務儲存在這個工做隊列裏。若是工做隊列滿了,則進入下一個流程。
- 線程池判斷其內部線程是否都處於工做狀態。若是沒有,則建立一個新的工做線程來執行任務。若是已滿了,則交給飽和策略來處理這個任務。
任務拒接策略?
有4種內置的實現策略和一個用戶自定義拒絕策略。
AbortPolicy 爲java線程池默認的阻塞策略,不執行此任務,並且直接拋出一個運行時異常,切記ThreadPoolExecutor.execute須要try catch,不然程序會直接退出。
DiscardPolicy 直接拋棄,任務不執行,空方法 。
DiscardOldestPolicy 從隊 列裏面拋棄head的一個任務,並再次execute 此task。
CallerRunsPolicy 在調用execute的線程裏面執行此command,會阻塞入口 。
用戶自定義拒絕策略 實現RejectedExecutionHandler,並本身定義策略模式。
再次須要注意的是,ThreadPoolExecutor.submit() 函數,此方法內部調用的execute方法,並把execute執行完後的結果給返回,但若是任務並無執行的話(被拒絕了),則submit返回的future.get()會一直等到。
future 內部其實仍是一個runnable,並把command給封裝了下,當command執行完後,future會返回一個值。
newCachedThreadPool:
- 底層:返回ThreadPoolExecutor實例,corePoolSize爲0;maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲60L;unit爲TimeUnit.SECONDS;workQueue爲SynchronousQueue(同步隊列)
- 通俗:當有新任務到來,則插入到SynchronousQueue中,因爲SynchronousQueue是同步隊列,所以會在池中尋找可用線程來執行,如有能夠線程則執行,若沒有可用線程則建立一個線程來執行該任務;若池中線程空閒時間超過指定大小,則該線程會被銷燬。
- 適用:執行不少短時間異步的小程序或者負載較輕的服務器
newFixedThreadPool:
- 底層:返回ThreadPoolExecutor實例,接收參數爲所設定線程數量nThread,corePoolSize爲nThread,maximumPoolSize爲nThread;keepAliveTime爲0L(不限時);unit爲:TimeUnit.MILLISECONDS;WorkQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列
- 通俗:建立可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;若是池中的全部線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列)
- 適用:執行長期的任務,性能好不少
newSingleThreadExecutor:
- 底層:FinalizableDelegatedExecutorService包裝的ThreadPoolExecutor實例,corePoolSize爲1;maximumPoolSize爲1;keepAliveTime爲0L;unit爲:TimeUnit.MILLISECONDS;workQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列
- 通俗:建立只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)
- 適用:一個任務一個任務執行的場景
NewScheduledThreadPool:
- 底層:建立ScheduledThreadPoolExecutor實例,corePoolSize爲傳遞來的參數,maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲0;unit爲:TimeUnit.NANOSECONDS;workQueue爲:new DelayedWorkQueue() 一個按超時時間升序排序的隊列
- 通俗:建立一個固定大小的線程池,線程池內線程存活時間無限制,線程池能夠支持定時及週期性任務執行,若是全部線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構
- 適用:週期性執行任務的場景
線程池任務執行流程:
- 當線程池小於corePoolSize時,新提交任務將建立一個新線程執行任務,即便此時線程池中存在空閒線程。
- 當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
- 當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會建立新線程執行任務
- 當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
- 當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程
- 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉
1六、分析線程池的實現原理和線程的調度過程?
ThreadPoolExecutor
調度線程執行器ScheduledThreadPoolExecutor是線程執行器ThreadPoolExecutor的擴展,在ThreadPoolExecutor基礎之上添加了在必定時間間隔以後調度任務的核心功能,也包括以後的按既定時間間隔去調度任務的功能。
1七、線程池如何調優,最大數目如何確認?
線程等待時間所佔比例越高,須要越多線程。線程CPU時間所佔比例越高,須要越少線程。
1八、ThreadLocal原理,用的時候須要注意什麼?
ThreadLocal,不少地方叫作線程本地變量,也有些地方叫作線程本地存儲,ThreadLocal爲變量在每一個線程中都建立了一個副本,那麼每一個線程能夠訪問本身內部的副本變量。
1九、CountDownLatch 和 CyclicBarrier 的用法,以及相互之間的差異?
20、LockSupport工具
2一、Condition接口及其實現原理
2二、Fork/Join框架的理解
2三、分段鎖的原理,鎖力度減少的思考
2四、八種阻塞隊列以及各個阻塞隊列的特性
可重入性:
從名字上理解,ReenTrantLock的字面意思就是再進入的鎖,其實synchronized關鍵字所使用的鎖也是可重入的,二者關於這個的區別不大。二者都是同一個線程沒進入一次,鎖的計數器都自增1,因此要等到鎖的計數器降低爲0時才能釋放鎖。
鎖的實現:
Synchronized是依賴於JVM實現的,而ReenTrantLock是JDK實現的,有什麼區別,說白了就相似於操做系統來控制實現和用戶本身敲代碼實現的區別。前者的實現是比較難見到的,後者有直接的源碼可供閱讀。
性能的區別:
在Synchronized優化之前,synchronized的性能是比ReenTrantLock差不少的,可是自從Synchronized引入了偏向鎖,輕量級鎖(自旋鎖)後,二者的性能就差很少了,在兩種方法均可用的狀況下,官方甚至建議使用synchronized,其實synchronized的優化我感受就借鑑了ReenTrantLock中的CAS技術。都是試圖在用戶態就把加鎖問題解決,避免進入內核態的線程阻塞。
功能區別:
便利性:很明顯Synchronized的使用比較方便簡潔,而且由編譯器去保證鎖的加鎖和釋放,而ReenTrantLock須要手工聲明來加鎖和釋放鎖,爲了不忘記手工釋放鎖形成死鎖,因此最好在finally中聲明釋放鎖。
鎖的細粒度和靈活度:很明顯ReenTrantLock優於Synchronized
ReenTrantLock獨有的能力:
1. ReenTrantLock能夠指定是公平鎖仍是非公平鎖。而synchronized只能是非公平鎖。所謂的公平鎖就是先等待的線程先得到鎖。
2. ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒須要喚醒的線程們,而不是像synchronized要麼隨機喚醒一個線程要麼喚醒所有線程。
3. ReenTrantLock提供了一種可以中斷等待鎖的線程的機制,經過lock.lockInterruptibly()來實現這個機制。
ReenTrantLock實現的原理:
在網上看到相關的源碼分析,原本這塊應該是本文的核心,可是感受比較複雜就不一一詳解了,簡單來講,ReenTrantLock的實現是一種自旋鎖,經過循環調用CAS操做來實現加鎖。它的性能比較好也是由於避免了使線程進入內核態的阻塞狀態。想盡辦法避免線程進入內核的阻塞狀態是咱們去分析和理解鎖設計的關鍵鑰匙。
什麼狀況下使用ReenTrantLock:
答案是,若是你須要實現ReenTrantLock的三個獨有功能時。
Spring
一、BeanFactory 和 FactoryBean?
區別:BeanFactory是個Factory,也就是IOC容器或對象工廠,FactoryBean是個Bean。在Spring中,全部的Bean都是由BeanFactory(也就是IOC容器)來進行管理的。但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能生產或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器模式相似
二、Spring IOC 的理解,其初始化過程?
在建立ApplicationContext實例對象過程當中會建立一個spring容器,該容器會讀取配置文件"cjj/models/beans.xml",並統一管理由該文件中定義好的全部bean實例對象,若是要獲取某個bean實例,使用getBean方法就好了。例如咱們只須要將Person提早配置在beans.xml文件中(能夠理解爲注入),以後咱們能夠不需使用new Person()的方式建立實例,而是經過容器來獲取Person實例,這就至關於將Person的控制權交由spring容器了,差很少這就是控制反轉的概念。
三、BeanFactory 和 ApplicationContext?
BeanFacotry是spring中比較原始的Factory。如XMLBeanFactory就是一種典型的BeanFactory。原始的BeanFactory沒法支持spring的許多插件,如AOP功能、Web應用等。
ApplicationContext接口,它由BeanFactory接口派生而來,於是提供BeanFactory全部的功能。ApplicationContext以一種更向面向框架的方式工做以及對上下文進行分層和實現繼承,ApplicationContext包還提供瞭如下的功能:
• MessageSource, 提供國際化的消息訪問
• 資源訪問,如URL和文件
• 事件傳播
• 載入多個(有繼承關係)上下文 ,使得每個上下文都專一於一個特定的層次,好比應用的web層
四、Spring Bean 的生命週期,如何被管理的?
1. 實例化一個Bean,也就是咱們一般說的new
2. 按照Spring上下文對實例化的Bean進行配置,也就是IOC注入
3. 若是這個Bean實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的是Spring配置文件中Bean的ID
4. 若是這個Bean實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(),傳遞的是Spring工廠自己(能夠用這個方法獲取到其餘Bean)
5. 若是這個Bean實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文,該方式一樣能夠實現步驟4,但比4更好,覺得ApplicationContext是BeanFactory的子接口,有更多的實現方法
6. 若是這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor常常被用做是Bean內容的更改,而且因爲這個是在Bean初始化結束時調用After方法,也可用於內存或緩存技術
7. 若是這個Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法
8. 若是這個Bean關聯了BeanPostProcessor接口,將會調用postAfterInitialization(Object obj, String s)方法
注意:以上工做完成之後就能夠用這個Bean了,那這個Bean是一個single的,因此通常狀況下咱們調用同一個ID的Bean會是在內容地址相同的實例
9. 當Bean再也不須要時,會通過清理階段,若是Bean實現了DisposableBean接口,會調用其實現的destroy方法
10. 最後,若是這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法
五、Spring Bean 的加載過程是怎樣的?
一個是populateBean,一個是initializeBean,這兩個方法完成了bean的賦值與初始化。
這裏有一個BeanDefinitionValueResolver,這個類用來解析property裏的value,若是是依賴其餘bean則會到容器中找是否存在若是有則返回,沒有則建立一個。spring又爲每一個對象的屬性定義了一個數據結構:PropertyValue,這樣作加大了容器對bean屬性的修改的靈活性,上面的方法就是對每一個屬性進行處理而後經過beanWapper的setPropertyValues進行賦值。
這裏注意一下,bean有singleton和prototype兩種 ,對於prototype,spring採用了原型模式,使用對象的deepcopy。
至此,spring完成了對實例的賦值,而後就是調用initializeBean:
六、若是要你實現Spring AOP,請問怎麼實現?
實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法建立「方面」,從而使得編譯器能夠在編譯期間織入有關「方面」的代碼。
七、若是要你實現Spring IOC,你會注意哪些問題?
八、Spring 是如何管理事務的,事務管理機制?
Spring 支持兩種方式事務管理
一:編程式的事務管理
經過TransactionTemplate手動管理事務
在實際應用中不多使用,緣由是要修改原來的代碼,加入事務管理代碼 (侵入性 )
二:聲明式事務管理(XML配置文件方式或註解方式)
Spring的聲明式事務是經過AOP實現的(環繞通知)
開發中常用(代碼侵入性最小)--推薦使用!
注:後面會演示聲明式事務管理的兩種方式:xml配置文件方式和註解方式,不演示編程式方式
Spring的事務機制包括聲明式事務和編程式事務。
編程式事務管理:Spring推薦使用TransactionTemplate,實際開發中使用聲明式事務較多。
聲明式事務管理:將咱們從複雜的事務處理中解脫出來,獲取鏈接,關閉鏈接、事務提交、回滾、異常處理等這些操做都不用咱們處理了,Spring都會幫咱們處理。
聲明式事務管理使用了AOP面向切面編程實現的,本質就是在目標方法執行先後進行攔截。在目標方法執行前加入或建立一個事務,在執行方法執行後,根據實際狀況選擇提交或是回滾事務。
九、Spring 的不一樣事務傳播行爲有哪些,幹什麼用的?
十、Spring 中用到了那些設計模式?
十一、Spring MVC 的工做原理?
十二、Spring 循環注入的原理?
1三、Spring AOP的理解,各個術語,他們是怎麼相互工做的?
1四、Spring 如何保證 Controller 併發的安全?
Netty
一、BIO、NIO和AIO
BIO(Blocking I/O)同步阻塞I/O
這是最基本與簡單的I/O操做方式,其根本特性是作完一件事再去作另外一件事,一件事必定要等前一件事作完,這很符合程序員傳統的順序來開發思想,所以BIO模型程序開發起來較爲簡單,易於把握。
NIO (New I/O) 同步非阻塞I/O
關於NIO,國內有不少技術博客將英文翻譯成No-Blocking I/O,非阻塞I/O模型 ,固然這樣就與BIO造成了鮮明的特性對比。NIO自己是基於事件驅動的思想來實現的,其目的就是解決BIO的大併發問題,在BIO模型中,若是須要併發處理多個I/O請求,那就須要多線程來支持,NIO使用了多路複用器機制
AIO (Asynchronous I/O) 異步非阻塞I/O
Java AIO就是Java做爲對異步IO提供支持的NIO.2
AIO相對於NIO的區別在於,NIO須要使用者線程不停的輪詢IO對象,來肯定是否有數據準備好能夠讀了,而AIO則是在數據準備好以後,纔會通知數據使用者,這樣使用者就不須要不停地輪詢了。
二、Netty 的各大組件
1 Bootstrap
一個應用一般有一個Bootstrap 開始,他主要是配置整個Netty 程序,串聯各個組件,Bootstrap 有兩種類型,ServerBootstrap 和 Bootstrap 分別用於Serber 端和 Client 端
2 Channel 渠道 (ChannelFuture)
表明一個Socker連接 或者其餘的IO相關組件
3 EventLoop (NioEventLoopGroup
)
爲Channel 處理I/O操做 一個EventLoop 能夠爲多個Channel 服務,理解爲一個線程。
4 EventLoopGroup
一個EventLoopGroup 包含多個EventLoop 能夠理解爲一個線程池
5 Handler
三、Netty的線程模型
四、TCP 粘包/拆包的緣由及解決方法
若是客戶端接二連三的向服務端發送數據包時,服務端接收的數據會出現兩個數據包粘在一塊兒的狀況,這就是TCP協議中常常會遇到的粘包以及拆包的問題。
可是TCP把這些數據塊僅僅當作一連串無結構的字節流,沒有邊界;另外從TCP的幀結構也能夠看出,在TCP的首部沒有表示數據長度的字段,基於上面兩點,在使用TCP傳輸數據時,纔有粘包或者拆包現象發生的可能。
發生TCP粘包或拆包有不少緣由,現列出常見的幾點,可能不全面,歡迎補充,
一、要發送的數據大於TCP發送緩衝區剩餘空間大小,將會發生拆包。
二、待發送數據大於MSS(最大報文長度),TCP在傳輸前將進行拆包。
三、要發送的數據小於TCP發送緩衝區的大小,TCP將屢次寫入緩衝區的數據一次發送出去,將會發生粘包。
四、接收數據端的應用層沒有及時讀取接收緩衝區中的數據,將發生粘包。
經過以上分析,咱們清楚了粘包或拆包發生的緣由,那麼如何解決這個問題呢?解決問題的關鍵在於如何給每一個數據包添加邊界信息,經常使用的方法有以下幾個:
一、發送端給每一個數據包添加包首部,首部中應該至少包含數據包的長度,這樣接收端在接收到數據後,經過讀取包首部的長度字段,便知道每個數據包的實際長度了。
二、發送端將每一個數據包封裝爲固定長度(不夠的能夠經過補0填充),這樣接收端每次從接收緩衝區中讀取固定長度的數據就天然而然的把每一個數據包拆分開來。
三、能夠在數據包之間設置邊界,如添加特殊符號,這樣,接收端經過這個邊界就能夠將不一樣的數據包拆分開。
五、瞭解哪幾種序列化協議?包括使用場景和如何去選擇
Serializable
JSON
Fastjson是一個Java語言編寫的高性能功能完善的JSON庫。
Thrift並不只僅是序列化協議,而是一個RPC框架。
六、Netty的零拷貝實現
Zero-copy, 就是在操做數據時, 不須要將數據 buffer 從一個內存區域拷貝到另外一個內存區域. 由於少了一次內存的拷貝, 所以 CPU 的效率就獲得的提高.
七、Netty的高性能表如今哪些方面
從大的方面看,netty性能高效主要體如今:
1.io線程模型
使用reactor模式,同步非阻塞。這決定了能夠用最少的資源作更多的事。
2.內存零拷貝
使用直接緩存
3.內存池設計
申請的內存能夠重用,主要指直接內存。
內部實現是用一顆二叉查找樹管理內存分配狀況。
4.串形化處理socket讀寫,避免鎖,即一個指定socket的消息是串形化處理的。這樣性能比多個線程同時 處理一個socket對應消息要好,由於多線程處理會有鎖。
5.提供對protobuf等高性能序列化協議支持
分佈式相關
一、Dubbo的底層實現原理和機制
–高性能和透明化的RPC遠程服務調用方案
–SOA服務治理方案
Dubbo缺省協議採用單一長鏈接和NIO異步通信,
適合於小數據量大併發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的狀況
二、描述一個服務從發佈到被消費的詳細過程
務。首先先獲取zk的配置信息,而後獲取須要暴露的url,而後調用registry.register方法將url註冊到zookeeper上去。
三、分佈式系統怎麼作服務治理
針對互聯網業務的特色,eg 突發的流量高峯、網絡延時、機房故障等,重點針對大規模跨機房的海量服務進行運行態治理,保障線上服務的高SLA,知足用戶的體驗,經常使用的策略包括限流降級、服務嵌入遷出、服務動態路由和灰度發佈等
四、接口的冪等性的概念
冪等的意思是同一個操做,重複執行屢次,跟執行一次結果一致。消息冪等,即消息發送操做對於消息消費來講是冪等。也就是相同的消息發送屢次,跟發送一次是同樣的,這個消息只會被消費一次。
五、消息中間件如何解決消息丟失問題
爲了解決消息丟失問題,咱們引入了一些重發機制,但也帶來的另一個問題:消息重複,咱們來看下都有哪些狀況會致使消息重複:
消息發送超時,處於不肯定狀態,致使重試發送消息,有可能以前的消息已經發送成功,會出現消息重複的狀況。解決的思路是,每一個消息生成一個消息id,若是發送的消息Broker已經存在了,則丟棄。這種解決辦法須要維護一個已經接收的消息的message id list。
消息在Broker中只有一份,可是consumer重啓前,未及時更新offset,致使consumer重啓以後重複消費消息。
上游業務給每一個message 分配一個message ID,下游業務在接收到message以後,執行業務而且保存message ID,並且要講兩部分放到同一個事務中,保證業務執行成功,message ID確定保存,業務執行失敗,message ID確定不會保存下來,利用db中存儲的message id來作冪等。咱們能夠從新封裝producer client和consumer client,將這部分message ID分配和判重的邏輯封裝到client lib裏面。
六、Dubbo的服務請求失敗怎麼處理
dubbo啓動時默認有重試機制和超時機制。
超時機制的規則是若是在必定的時間內,provider沒有返回,則認爲本次調用失敗,
重試機制在出現調用失敗時,會再次調用。若是在配置的調用次數內都失敗,則認爲這次請求異常,拋出異常。
七、重連機制會不會形成錯誤
dubbo在調用服務不成功時,默認會重試2次。
Dubbo的路由機制,會把超時的請求路由到其餘機器上,而不是本機嘗試,因此 dubbo的重試機器也能必定程度的保證服務的質量。
可是若是不合理的配置重試次數,當失敗時會進行重試屢次,這樣在某個時間點出現性能問題,調用方再連續重複調用,
系統請求變爲正常值的retries倍,系統壓力會大增,容易引發服務雪崩,須要根據業務狀況規劃好如何進行異常處理,什麼時候進行重試。
八、對分佈式事務的理解
本質上來講,分佈式事務就是爲了保證不一樣數據庫的數據一致性。
事務的ACID特性 原子性 一致性 隔離性 持久性
消息事務+最終一致性
CC提供了一個編程框架,將整個業務邏輯分爲三塊:Try、Confirm和Cancel三個操做。以在線下單爲例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,若是更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是經過代碼人爲實現了兩階段提交,不一樣的業務場景所寫的代碼都不同,複雜度也不同,所以,這種模式並不能很好地被複用。
九、如何實現負載均衡,有哪些算法能夠實現?
常常會用到如下四種算法:隨機(random)、輪訓(round-robin)、一致哈希(consistent-hash)和主備(master-slave)。
十、Zookeeper的用途,選舉的原理是什麼?
十一、數據的垂直拆分水平拆分。
十二、zookeeper原理和適用場景
1三、zookeeper watch機制
Znode發生變化(Znode自己的增長,刪除,修改,以及子Znode的變化)能夠經過Watch機制通知到客戶端。那麼要實現Watch,就必須實現org.apache.zookeeper.Watcher接口,而且將實現類的對象傳入到能夠Watch的方法中。Zookeeper中全部讀操做(getData(),getChildren(),exists())均可以設置Watch選項。
1四、redis/zk節點宕機如何處理
1五、分佈式集羣下如何作到惟一序列號
Redis生成ID 這主要依賴於Redis是單線程的,因此也能夠用生成全局惟一的ID。能夠用Redis的原子操做 INCR和INCRBY來實現。
1六、如何作一個分佈式鎖
1七、用過哪些MQ,怎麼用的,和其餘mq比較有什麼優缺點,MQ的鏈接是線程安全的嗎
RabbitMQ 支持 AMQP(二進制),STOMP(文本),MQTT(二進制),HTTP(裏面包裝其餘協議)等協議。Kafka 使用本身的協議。
Kafka 自身服務和消費者都須要依賴 Zookeeper。
RabbitMQ 在有大量消息堆積的狀況下性能會降低,Kafka不會。畢竟AMQP設計的初衷不是用來持久化海量消息的,而Kafka一開始是用來處理海量日誌的。
總的來講,RabbitMQ 和 Kafka 都是十分優秀的分佈式的消息代理服務,只要合理部署,不做,基本上能夠知足生產條件下的任何需求。
1八、MQ系統的數據如何保證不丟失
在數據生產時避免數據丟失的方法:
只要能避免上述兩種狀況,那麼就能夠保證消息不會被丟失。
1)就是說在同步模式的時候,確認機制設置爲-1,也就是讓消息寫入leader和全部的副本。
2)還有,在異步模式下,若是消息發出去了,但尚未收到確認的時候,緩衝池滿了,在配置文件中設置成不限制阻塞超時的時間,也就說讓生產端一直阻塞,這樣也能保證數據不會丟失。
在數據消費時,避免數據丟失的方法:若是使用了storm,要開啓storm的ackfail機制;若是沒有使用storm,確認數據被完成處理以後,再更新offset值。低級API中須要手動控制offset值。
數據重複消費的狀況,若是處理
(1)去重:將消息的惟一標識保存到外部介質中,每次消費處理時判斷是否處理過;
(2)無論:大數據場景中,報表系統或者日誌信息丟失幾條都無所謂,不會影響最終的統計分析結
1九、列舉出你能想到的數據庫分庫分表策略;分庫分表後,如何解決全表查詢的問題
:業務拆分、主從複製,數據庫分庫與分表
使用用戶ID是最經常使用的分庫的路由策略。用戶的ID能夠做爲貫穿整個系統用的重要字段。所以,使用用戶的ID咱們不只能夠方便咱們的查詢
垂直分表
水平分表
20、zookeeper的選舉策略
在zookeeper集羣中也是同樣,每一個節點都會投票,若是某個節點得到超過半數以上的節點的投票,則該節點就是leader節點了。
zookeeper中有三種選舉算法,分別是LeaderElection,FastLeaderElection,AuthLeaderElection,
FastLeaderElection此算法和LeaderElection不一樣的是它不會像後者那樣在每輪投票中要蒐集到全部結果後才統計投票結果,而是不斷的統計結果,一旦沒有新的影響leader結果的notification出現就返回投票結果。這樣的效率更高。
2一、全局ID
Snowflake
redis
數據庫
一、mysql分頁有什麼優化
通常分頁查詢
通常的分頁查詢使用簡單的 limit 子句就能夠實現。limit 子句聲明以下:
使用子查詢優化
這種方式先定位偏移位置的 id,而後日後查詢,這種方式適用於 id 遞增的狀況。
使用 id 限定優化
這種方式假設數據表的id是連續遞增的,則咱們根據查詢的頁數和查詢的記錄數能夠算出查詢的id的範圍,能夠使用 id between and 來查詢:
二、悲觀鎖、樂觀鎖
三、組合索引,最左原則
最左前綴:顧名思義,就是最左優先,上例中咱們建立了lname_fname_age多列索引,至關於建立了(lname)單列索引,(lname,fname)組合索引以及(lname,fname,age)組合索引。
注:在建立多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。
四、mysql 的表鎖、行鎖
開銷、加鎖速度、死鎖、粒度、併發性能
- 表鎖:開銷小,加鎖快;不會出現死鎖;鎖定力度大,發生鎖衝突機率高,併發度最低
- 行鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖衝突的機率低,併發度高
五、mysql 性能優化
六、mysql的索引分類:B+,hash;什麼狀況用什麼索引
很簡單 用plsql developer 按F5 執行計劃分析
你只要看出來的對話框中間節點的表述,是full 表示你走的是全表遍歷
若是是hash或其餘的 則表示走的是索引
看看cost也能知道時間消耗狀況
,也就是b tree或者 b+ tree,重要的事情說三遍:「平衡樹,平衡樹,平衡樹」。固然, 有的數據庫也使用哈希桶做用索引的數據結構 , 然而, 主流的RDBMS都是把平衡樹當作數據表默認的索引數據結構的。
咱們平時建表的時候都會爲表加上主鍵, 在某些關係數據庫中, 若是建表時不指定主鍵,數據庫會拒絕建表的語句執行。 事實上, 一個加了主鍵的表,並不能被稱之爲「表」。一個沒加主鍵的表,它的數據無序的放置在磁盤存儲器上,一行一行的排列的很整齊, 跟我認知中的「表」很接近。若是給表上了主鍵,那麼表在磁盤上的存儲結構就由整齊排列的結構轉變成了樹狀結構,也就是上面說的「平衡樹」結構,換句話說,就是整個表就變成了一個索引。
B+Tree索引
B+Tree是mysql使用最頻繁的一個索引數據結構,是Inodb和Myisam存儲引擎模式的索引類型。相對Hash索引,B+Tree在查找單條記錄的速度比不上Hash索引,可是由於更適合排序等操做,因此它更受歡迎。畢竟不可能只對數據庫進行單條記錄的操做。
帶順序訪問指針的B+Tree
B+Tree全部索引數據都在葉子節點上,而且增長了順序訪問指針,每一個葉子節點都有指向相鄰葉子節點的指針。
這樣作是爲了提升區間效率,例如查詢key爲從18到49的全部數據記錄,當找到18後,只要順着節點和指針順序遍歷就能夠以此向訪問到全部數據節點,極大提升了區間查詢效率。
大大減小磁盤I/O讀取
數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點須要一次I/O就能夠徹底載入。
七、事務的特性和隔離級別
原子性(Atomicity )、一致性( Consistency )、隔離性或獨立性( Isolation)和持久性(Durabilily),簡稱就是ACID。
數據庫進行任何寫入操做的時候都是要先寫日誌的,一樣的道理,咱們在執行事務的時候數據庫首先會記錄下這個事務的redo操做日誌,而後纔開始真正操做數據庫,
在操做以前,首先會把日誌文件寫入磁盤,那麼當忽然斷電的時候,即便操做沒有完成,在從新啓動數據庫時候,數據庫會根據當前數據的狀況進行undo回滾或者是redo前滾,
這樣就保證了數據的強一致性。
① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。
② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
③ Read committed (讀已提交):可避免髒讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何狀況都沒法保證。
緩存
一、Redis用過哪些數據數據,以及Redis底層怎麼實現
Redis對象類型簡介
Redis是一種key/value型數據庫,其中,每一個key和value都是使用對象表示的。
二、Redis緩存穿透,緩存雪崩
緩存穿透
什麼是緩存穿透?
通常的緩存系統,都是按照key去緩存查詢,若是不存在對應的value,就應該去後端系統查找(好比DB)。若是key對應的value是必定不存在的,而且對該key併發請求量很大,就會對後端系統形成很大的壓力。這就叫作緩存穿透。
如何避免?
1:對查詢結果爲空的狀況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了以後清理緩存。
2:對必定不存在的key進行過濾。能夠把全部的可能存在的key放到一個大的Bitmap中,查詢時經過該bitmap過濾。【感受應該用的很少吧】
緩存雪崩
什麼是緩存雪崩?
當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給後端系統(好比DB)帶來很大壓力。
如何避免?
1:在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。
2:不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻。
3:作二級緩存,A1爲原始緩存,A2爲拷貝緩存,A1失效時,能夠訪問A2,A1緩存失效時間設置爲短時間,A2設置爲長期(此點爲補充)
三、如何使用Redis來實現分佈式鎖
四、Redis的併發競爭問題如何解決
五、Redis持久化的幾種方式,優缺點是什麼,怎麼實現的
redis兩種持久化的方式
- RDB持久化能夠在指定的時間間隔內生成數據集的時間點快照
- AOF持久化記錄服務器執行的全部寫操做命令,並在服務器啓動時,經過從新執行這些命令來還原數據集,AOF文件中所有以redis協議的格式來保存,新命令會被追加到文件的末尾,redis還能夠在後臺對AOF文件進行重寫,文件的體積不會超出保存數據集狀態所須要的實際大小,
- redis還能夠同時使用AOF持久化和RDB持久化,在這種狀況下,當redis重啓時,它會有限使用AOF文件來還原數據集,由於AOF文件保存的數據集一般比RDB文件所保存的數據集更加完
六、Redis的緩存失效策略
七、Redis集羣,高可用,原理
八、Redis緩存分片
分片(partitioning)就是將你的數據拆分到多個 Redis 實例的過程,這樣每一個實例將只包含全部鍵的子集。本文第一部分將向你介紹分片的概念,第二部分將向你展現 Redis 分片的可選方案。
九、Redis的數據淘汰策略
在一臺 8G 機子上部署了 4 個 redis 服務點,每個服務點分配 1.5G 的內存大小,減小內存緊張的狀況,由此獲取更爲穩健的服務。
redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。
一、Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可用於緩存其餘東西,例如圖片、視頻等等;
二、Redis不只僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲;
三、
虛擬內存--Redis當物理內存用完時,能夠將一些好久沒用到的value 交換到磁盤;
四、過時策略--memcache在set時就指定,例如set key1 0 0 8,即永不過時。Redis能夠經過例如expire 設定,例如expire name 10;
五、分佈式--設定memcache集羣,利用magent作一主多從;redis能夠作一主多從。均可以一主一從;
六、存儲數據安全--memcache掛掉後,數據沒了;redis能夠按期保存到磁盤(持久化);
七、
災難恢復--memcache掛掉後,數據不可恢復; redis數據丟失後能夠經過aof恢復;
八、Redis支持數據的備份,即master-slave模式的數據備份;
十一、Redis的高併發和快速緣由不少,總結一下幾點:
1. Redis是純內存數據庫,通常都是簡單的存取操做,線程佔用的時間不少,時間的花費主要集中在IO上,因此讀取速度快。
2. 再說一下IO,Redis使用的是非阻塞IO,IO多路複用,使用了單線程來輪詢描述符,將數據庫的開、關、讀、寫都轉換成了事件,減小了線程切換時上下文的切換和競爭。
3. Redis採用了單線程的模型,保證了每一個操做的原子性,也減小了線程的上下文切換和競爭。
4. 另外,數據結構也幫了很多忙,Redis全程使用hash結構,讀取速度快,還有一些特殊的數據結構,對數據存儲進行了優化,如壓縮表,對短數據進行壓縮存儲,再如,跳錶,使用有序的數據結構加快讀取的速度。
5. 還有一點,Redis採用本身實現的事件分離器,效率比較高,內部採用非阻塞的執行方式,吞吐能力比較大。
JVM
一、詳細jvm內存模型
二、講講什麼狀況下回出現內存溢出,內存泄漏?
1>當程序在申請內存後,,沒法釋放已經申請的內存空間(例如一個對象或者變量使用完成後沒有釋放,這個對對象一直佔用着內存),一次內存泄漏的危害能夠忽略,可是內存泄露堆積的後果很嚴重,不管多少內存,早晚會被佔光,內存泄露最終會致使內存溢出
2>當程序申請內存時,沒有足夠的內存空間供其使用,出現了out of memory;好比申請了一個int,但給他存放了long才能存下的數,就是內存溢出.
三、說說Java線程棧
四、JVM 年輕代到年老代的晉升過程的判斷條件是什麼呢?
五、JVM 出現 fullGC 很頻繁,怎麼去線上排查問題?
咱們知道Full GC的觸發條件大體狀況有如下幾種狀況:
- 程序執行了System.gc() //建議jvm執行fullgc,並不必定會執行
- 執行了jmap -histo:live pid命令 //這個會當即觸發fullgc
- 在執行minor gc的時候進行的一系列檢查
- 執行Minor GC的時候,JVM會檢查老年代中最大連續可用空間是否大於了當前新生代全部對象的總大小。
- 使用了大對象 //大對象會直接進入老年代
- 在程序中長期持有了對象的引用 //對象年齡達到指定閾值也會進入老年代
六、類加載爲何要使用雙親委派模式,有沒有什麼場景是打破了這個模式?
七、類的實例化順序
父靜-子靜 父初-父構-子初-子構
八、JVM垃圾回收機制,什麼時候觸發MinorGC等操做
堆內存分爲 年輕代 老年代 和持久代
年輕代 又分爲 eden 區和 survivor 區
這兩個區若是滿了 觸發的就是 minor gc
九、JVM 中一次完整的 GC 流程(從 ygc 到 fgc)是怎樣的
1.YGC和FGC是什麼
YGC :對新生代堆進行gc。頻率比較高,由於大部分對象的存活壽命較短,在新生代裏被回收。性能耗費較小。
FGC :全堆範圍的gc。默認堆空間使用到達80%(可調整)的時候會觸發fgc。以咱們生產環境爲例,通常比較少會觸發fgc,有時10天或一週左右會有一次。
2.何時執行YGC和FGC
a.edn空間不足,執行 young gc
b.old空間不足,perm空間不足,調用方法System.gc() ,ygc時的悲觀策略, dump live的內存信息時(jmap –dump:live),都會執行full gc
十、各類回收器,各自優缺點,重點CMS、G1
CMS收集器
CMS收集器是一種以獲取最短回收停頓時間爲目標的收集器。基於「標記-清除」算法實現,它的運做過程以下:
1)初始標記
2)併發標記
3)從新標記
4)併發清除
初始標記、重新標記這兩個步驟仍然須要「stop the world」,初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,熟讀很快,併發標記階段就是進行GC Roots Tracing,而從新標記階段則是爲了修正併發標記期間因用戶程序繼續運做而致使標記產生表動的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長點,但遠比並發標記的時間短。
CMS是一款優秀的收集器,主要優勢:併發收集、低停頓。
缺點:
1)CMS收集器對CPU資源很是敏感。在併發階段,它雖然不會致使用戶線程停頓,可是會由於佔用了一部分線程而致使應用程序變慢,總吞吐量會下降。
2)CMS收集器沒法處理浮動垃圾,可能會出現「Concurrent Mode Failure(併發模式故障)」失敗而致使Full GC產生。
浮動垃圾:因爲CMS併發清理階段用戶線程還在運行着,伴隨着程序運行天然就會有新的垃圾不斷產生,這部分垃圾出現的標記過程以後,CMS沒法在當次收集中處理掉它們,只好留待下一次GC中再清理。這些垃圾就是「浮動垃圾」。
3)CMS是一款「標記--清除」算法實現的收集器,容易出現大量空間碎片。當空間碎片過多,將會給大對象分配帶來很大的麻煩,每每會出現老年代還有很大空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。
二、G1收集器
G1是一款面向服務端應用的垃圾收集器。G1具有以下特色:
一、並行於併發:G1能充分利用CPU、多核環境下的硬件優點,使用多個CPU(CPU或者CPU核心)來縮短stop-The-World停頓時間。部分其餘收集器本來須要停頓Java線程執行的GC動做,G1收集器仍然能夠經過併發的方式讓java程序繼續執行。
二、分代收集:雖然G1能夠不須要其餘收集器配合就能獨立管理整個GC堆,可是仍是保留了分代的概念。它可以採用不一樣的方式去處理新建立的對象和已經存活了一段時間,熬過屢次GC的舊對象以獲取更好的收集效果。
三、空間整合:與CMS的「標記--清理」算法不一樣,G1從總體來看是基於「標記整理」算法實現的收集器;從局部上來看是基於「複製」算法實現的。
四、可預測的停頓:這是G1相對於CMS的另外一個大優點,下降停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能創建可預測的停頓時間模型,能讓使用者明確指定在一個長度爲M毫秒的時間片斷內,
五、G1運做步驟:
一、初始標記;二、併發標記;三、最終標記;四、篩選回收
上面幾個步驟的運做過程和CMS有不少類似之處。初始標記階段僅僅只是標記一下GC Roots能直接關聯到的對象,而且修改TAMS的值,讓下一個階段用戶程序併發運行時,能在正確可用的Region中建立新對象,這一階段須要停頓線程,可是耗時很短,併發標記階段是從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段時耗時較長,但可與用戶程序併發執行。而最終標記階段則是爲了修正在併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分標記記錄,虛擬機將這段時間對象變化記錄在線程Remenbered Set Logs裏面,最終標記階段須要把Remembered Set Logs的數據合併到Remembered Set Logs裏面,最終標記階段須要把Remembered Set Logs的數據合併到Remembered Set中,這一階段須要停頓線程,可是可並行執行。最後在篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所指望的GC停頓時間來制定回收計劃。
十一、各類回收算法
關於垃圾回收的機制,這裏再也不解釋,這篇文章我主要介紹常見的垃圾回收算法,固然還有其餘的。
算法一:引用計數法。
這個方法是最經典點的一種方法。具體是對於對象設置一個引用計數器,每增長一個變量對它的引用,引用計數器就會加1,沒減小一個變量的引用,
引用計數器就會減1,只有當對象的引用計數器變成0時,該對象纔會被回收。可見這個算法很簡單,可是簡單每每會存在不少問題,這裏我列舉最明顯的兩個問題,
一是採用這種方法後,每次在增長變量引用和減小引用時都要進行加法或減法操做,若是頻繁操做對象的話,在必定程度上增長的系統的消耗。
二是這種方法沒法處理循環引用的狀況。再解釋下什麼是循環引用,假設有兩個對象 A和B,A中引用了B對象,而且B中也引用了A對象,
那麼這時兩個對象的引用計數器都不爲0,可是因爲存在相互引用致使沒法垃圾回收A和 B,致使內存泄漏。
算法二:標記清除法。
這個方法是將垃圾回收分紅了兩個階段:標記階段和清除階段。
在標記階段,經過跟對象,標記全部從跟節點開始的可達的對象,那麼未標記的對象就是未被引用的垃圾對象。
在清除階段,清除掉因此的未被標記的對象。
這個方法的缺點是,垃圾回收後可能存在大量的磁盤碎片,準確的說是內存碎片。由於對象所佔用的地址空間是固定的。對於這個算法還有改進的算法,就是我後面要說的算法三。
算法三:標記壓縮清除法(Java中老年代採用)。
在算法二的基礎上作了一個改進,能夠說這個算法分爲三個階段:標記階段,壓縮階段,清除階段。標記階段和清除階段不變,只不過增長了一個壓縮階段,就是在作完標記階段後,
將這些標記過的對象集中放到一塊兒,肯定開始和結束地址,好比所有放到開始處,這樣再去清除,將不會產生磁盤碎片。可是咱們也要注意到幾個問題,壓縮階段佔用了系統的消耗,
而且若是標記對象過多的話,損耗可能會很大,在標記對象相對較少的時候,效率較高。
算法四:複製算法(Java中新生代採用)。
核心思想是將內存空間分紅兩塊,同一時刻只使用其中的一塊,在垃圾回收時將正在使用的內存中的存活的對象複製到未使用的內存中,而後清除正在使用的內存塊中全部的對象,
而後把未使用的內存塊變成正在使用的內存塊,把原來使用的內存塊變成未使用的內存塊。很明顯若是存活對象較多的話,算法效率會比較差,而且這樣會使內存的空間折半,可是這種方法也不會產生內存碎片。
算法五:分代法(Java堆採用)。
主要思想是根據對象的生命週期長短特色將其進行分塊,根據每塊內存區間的特色,使用不一樣的回收算法,從而提升垃圾回收的效率。
好比Java虛擬機中的堆就採用了這種方法分紅了新生代和老年代。而後對於不一樣的代採用不一樣的垃圾回收算法。
新生代使用了複製算法,老年代使用了標記壓縮清除算法。
算法六:分區算法。
這種方法將整個空間劃分紅連續的不一樣的小區間,每一個區間都獨立使用,獨立回收,好處是能夠控制一次回收多少個小區間。
總結:各類回收算法都有各自的優缺點,沒有一種算法能夠徹底替代其餘的算法,在具體的使用中應該結合具體的環境來選擇。
十二、OOM錯誤,stackoverflow錯誤,permgen space錯誤
堆內存溢出
【狀況一】:
java.lang.OutOfMemoryError: Java heap space:這種是java堆內存不夠,一個緣由是真不夠,另外一個緣由是程序中有死循環;
若是是java堆內存不夠的話,能夠經過調整JVM下面的配置來解決:
< jvm-arg>-Xms3062m < / jvm-arg>
< jvm-arg>-Xmx3062m < / jvm-arg>
【狀況二】
java.lang.OutOfMemoryError: GC overhead limit exceeded
【解釋】:JDK6新增錯誤類型,當GC爲釋放很小空間佔用大量時間時拋出;通常是由於堆過小,致使異常的緣由,沒有足夠的內存。
【解決方案】:
一、查看系統是否有使用大內存的代碼或死循環;
二、經過添加JVM配置,來限制使用內存:
< jvm-arg>-XX:-UseGCOverheadLimit< /jvm-arg>
【狀況三】:
java.lang.OutOfMemoryError: PermGen space:這種是P區內存不夠,可經過調整JVM的配置:
< jvm-arg>-XX:MaxPermSize=128m< /jvm-arg>
< jvm-arg>-XXermSize=128m< /jvm-arg>
【注】:
JVM的Perm區主要用於存放Class和Meta信息的,Class在被Loader時就會被放到PermGen space,這個區域成爲年老代,GC在主程序運行期間不會對年老區進行清理,默認是64M大小,當程序須要加載的對象比較多時,超過64M就會報這部份內存溢出了,須要加大內存分配,通常128m足夠。
【狀況四】:
java.lang.OutOfMemoryError: Direct buffer memory
調整-XX:MaxDirectMemorySize= 參數,如添加JVM配置:
< jvm-arg>-XX:MaxDirectMemorySize=128m< /jvm-arg>
【狀況五】:
java.lang.OutOfMemoryError: unable to create new native thread
【緣由】:Stack空間不足以建立額外的線程,要麼是建立的線程過多,要麼是Stack空間確實小了。
【解決】:因爲JVM沒有提供參數設置總的stack空間大小,但能夠設置單個線程棧的大小;而系統的用戶空間一共是3G,除了Text/Data/BSS /MemoryMapping幾個段以外,Heap和Stack空間的總量有限,是此消彼長的。所以遇到這個錯誤,能夠經過兩個途徑解決:
1.經過 -Xss啓動參數減小單個線程棧大小,這樣便能開更多線程(固然不能過小,過小會出現StackOverflowError);
2.經過-Xms -Xmx 兩參數減小Heap大小,將內存讓給Stack(前提是保證Heap空間夠用)。
【狀況六】:
java.lang.StackOverflowError
【緣由】:這也內存溢出錯誤的一種,即線程棧的溢出,要麼是方法調用層次過多(好比存在無限遞歸調用),要麼是線程棧過小。
【解決】:優化程序設計,減小方法調用層次;調整-Xss參數增長線程棧大小。
WebX框架是阿里巴巴集團開發的,它創建在SpringEx的基礎上,具備超強的擴展能力。
1、Webx的層次結構(從裏到外)
(1)SpringExt:基於Spring,提供擴展組件的能力
(2)Webx Framework:基於Servlet API,提供基礎服務
(3)Webx Turbine:基於Webx Framework,實現具體的網頁功能
2、Webx的初始化
位置:/WEB-INF/web.xml文件
結果:自動搜索/WEB-INF目錄下的XML配置文件,並建立級聯的Spring容器。
/WEB-INF/webx.xml->/WEB-INF/web-app1.xml->/WEB-INF/webx-app2.xml
3、初始化日誌系統
添加方式:
4、Webx響應請求
Webx響應請求的流程:
(1)WebxFrameworkFilter接收請求
(2)WebxRootController建立和處理request context,路由到子應用,並提供處理異常、開發模式功能。
(3)WebxController進行apps' pipeline
當一個HTTP請求到達時,WebxFrameworkFilter接收請求的模板配置(/WEB-INF/webx.xml)以下:
爲何使用filter而不是servlet?若是webx發現某個請求不該該由webx來處理,就會把控制「返還」給原來的控制器,而Servlet不具有「返還控制」的機制。
RequestContext對象的標準模板以下:
5、Webx Turbine
它的基本準則是:約定勝於配置,即:工程師只須要根據必定的規則,將模板放在指定的目錄、按照預約的方式命令module(也就是screen、action、control等),就再也不須要額外的配置。
Turbine的基本頁面組成爲:
(1)Screen:表明頁面的主體
(2)Layout:表明頁面的佈局
(3)Control:表明嵌在screen和layout中的頁面片斷
頁面佈局圖以下:
6、Webx Turbine處理頁面的基本流程
Webx Turbine的處理流程被定義在pipeline中,pipeline推薦的配置以下:
流程具體解讀以下:
(1) 分析URL::用戶訪問的主頁target
(2) 進入choose,進行多重分支選擇
(3)performAction執行action
(4) performTemplateScreen查找並執行screen
假設target爲xxx/yyy/zzz,那麼Webx Turbine查找screen模塊的順序爲:
Screen.xxx.yyy.zzz
Screen.xxx.yyy.Default
Screen.xxx.Default
Screen.Default
(5) 渲染模板
首先映射成screen template,以及映射成layout template
假設target爲xxx/yyy/zzz,那麼Webx Turbine會查找下面的screen模板:/templates/screen/xxx/yyy/zzz。Screen模板若是未找到,就會報404 Not Found錯誤。 找到screen模板之後,Webx Turbine還會試着查找下面的layout模板:
/templates/layout/xxx/yyy/zzz
/templates/layout/xxx/yyy/default
/templates/layout/xxx/default
/templates/layout/default
Layout模板若是找不到,就直接渲染screen模板;若是存在,則把渲染screen模板後的結果嵌入到layout模板中。
7、Filter的用途
頁面受權:根據登陸用戶的權限,阻止或許可用戶訪問特定的頁面。
日誌和審計:記錄和檢查用戶訪問WEB應用的狀況。
圖片轉換:改變圖片的格式、精度、尺寸等。
頁面壓縮:壓縮頁面內容,加快下載速度。
本地化:顯示本地語言和風格的頁面。
XSLT轉換:對XML內容進行XSLT轉換,使之適用於多種客戶端。
高速緩存:高速緩存頁面,提升響應速度。
使用方法:
Webx提供了Request Contexts服務以及Pipeline做爲對Filter功能缺陷的補充,做用分別以下:
(1) Request Contexts:負責訪問和修改request和response,但不負責改變應用執行的流程
(2) Pipeline:提供應用執行的流程,但不關心和request和response
8、Spring中依賴注入的限制
小做用域的對象不能被注入到大做用域的對象。你不能把request和response做用域的對象注入到singleton對象中。前者在每次WEB請求時,均會建立新的實例,每一個線程獨享這個request/session做用域的對象;後者是在Spring初始化或第一次使用時被建立,而後被全部的線程共享。假如把某個request/session做用域的對象意外注入到singleton對象中,將可能產生致命的應用錯誤,甚至致使數據庫的錯亂。
在Webx中,這樣作是能夠的!奧祕在於Request Contexts服務對上表所列的這些短時間對象做了特殊的處理,使它們能夠被注入到singleton對象中。事實上,被注入的只是一個「空殼」,真正的對象是在被訪問到的時候纔會從線程中取得的。
9、buffered緩存response中內存的實現原理
Webx支持用layout/screen/control等部件共同構成一個頁面。其中,每一個layout可包含一個screen和多個control,每一個screen可包含多個control,每一個control還能夠在包含其餘的control。
通常頁面好比經過out.println("
hello world
");就直接輸出了,爲了還能分開而後再一塊兒顯示呢。例如,一個screen中包含了一個control,那麼screen能夠得到它所調用的control的完整的渲染內容。
這個玄機就是靠來實現的。改變了response的輸出流,包括output stream和writer,使寫到輸出流中的內容被暫存在內存中。當須要時,能夠取得緩存中的全部內容。
Buffered機制會延遲服務器對用戶的響應,因此某些場景須要關閉該服務。
10、表單驗證的模板
該文件form.xml位於WEB-INF的每一個子目錄中,用於表單的驗證
11、Eclipse中開發Webx應用
(1)Webx工程目錄結構
src\main:存放開發代碼
src\test:存放開發自測代碼,如單元測試代碼
main\java:存放java代碼
main\resources:存放資源定義文件
main\webapp:web應用配置文件
webapp目錄包含(舉例):
1)子應用模板目錄admin、home、store、user,每一個模板目錄又由layout、control、screen三個子目錄組成,包含對應的模板文件(.vm文件)
2)通用模板目錄common
3)WEB-INF目錄
這是java web應用必備的配置目錄,包含了web.xml(java web應用必備的配置文件)、webx.xml(webx配置文件)、日誌配置文件(log4j.xml、logback.xml)、子應用配置文件(webx-admin.xml、webx-home.xml、webx-store.xml、webx-user.xml);另外還有對應每一個子應用的文件夾,用於存放form定義文件(form.xml)和訪問權限定義文件(access.xml);common文件夾中的pipeline.xml和pipeline-exception.xml定義了相關的管道操做流程。
(2)頁面獲取JAVA層的數據PullTool
在velocity模板中使用pulltool方便咱們進行頁面輸出內容的控制,組織頁面的展現,或者是直接取得web層相關的一些對象,直接在vm中調用。由頁面拉動業務邏輯,獲取並控制須要展現的內容,而非應用程序推進push,這符合webx的頁面驅動的模式。
1)是否啓動pull服務:
在webx.xml文件中進行總的控制
2)指定獲取數據的JAVA處理模塊
指定了獲取的數據位於com.xx.web.ui.module.*
3)在/xx/templates/screen下建立testMain.vm(M須要大寫)文件,內容以下:
4)在/src/main/java/com/web/ui/module/screen下建立文件TestMain.java(webx會自動匹配同名的文件),內容以下:
package com.yunos.tv.openbase.web.ui.module.screen;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.citrus.turbine.Context;
public class TestMain {
public void execute(HttpServletRequest request, HttpServletResponse response, Context context) throws Exception{
context.put("name", "Hugh");
}
}
execute方法就是專門用來處理對應請求的,是webx潛規則的地方,它是頁面渲染以前處理的方法。
有些參數爲:public void execute(@Param("systemVersion") String systemVersion,HttpServletRequest request, HttpServletResponse response, Context context, Navigator nav),說明以下:第一個參數爲傳進來的信息,context對象負責頁面渲染時部分數據的修改。
(2)實現form表單功能
實現用戶帳號登錄的功能,若是用戶不輸入則提示用戶輸入相關信息,效果以下:
其具體代碼以下:
login.vm文件:
form.xml文件:
關鍵點說明以下:
1.
這表示提交以後執行的是LoginAction.java,這裏的value值login_action在程序內部會被處理成 LoginAction,所以這裏若是寫成value="LoginAction",結果是同樣的
2.
這裏提交後表示執行的方法是doUserInfoSumbit方法,若是你要執行其餘方法請修改name值name="event_submit_你的方法"
3.關聯form.xml:首先 #set ($group = $form.loginInfoGroup.defaultInstance)[固定寫法,loginInfoGroup對應form.xml中的services:group name="loginInfoGroup"],而後
name對應到form.xml中的規則,group.username.message就是須要顯示的錯誤信息。
4.$csrfToken.hiddenField是必需要添加的,防止跨站請求僞造攻擊。若是不添加的話,數據是不會從顯示層傳送給JAVA層的。
(3)實現form表單往JAVA層傳送數據功能
一、構造與表單對應的類LoginInfo:
package com.yunos.tv.openbase.biz.dataobject;
public class LoginInfo {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
、1q 其中username和password的值須要和form.xml中定義的保持一致,不然二者沒法創建聯繫。
(2) 2.編輯業務功能LoginAction.java:
import com.alibaba.citrus.turbine.dataresolver.FormGroup;
import com.yunos.tv.openbase.biz.dataobject.LoginInfo;
public class LoginAction {
public void doUserInfoSumbit(@FormGroup("loginInfoGroup")LoginInfo userLoginInfo, HttpServletResponse response, Context context, Navigator nav) throws Exception{
System.out.println("hello");
System.out.println(userLoginInfo.getUsername());
3.
3.若是數據模型LoginInfo和LoginAction不在同一個工程中,則LoginAction應該探測不到LoginInfo.class,須要LoginInfo先編譯生成class文件,而後LoginAction才能夠使用LoginInfo類。在LoginInfo所在的工程使用mvn clean install命令從新進行編譯,而後在LoginAction刷新下引入該類。
(
3
};
}
(
二、
WEB-INF文件夾下各個配置文件說明
- logback.xml:日誌配置;
- web.xml:WEB工程初始化配置信息;
- webx.xml:webx通用配置,webx容器初始化的Bean可以讓全部子業務容器依賴。
- webx-app1.xml:webx子業務配置,子業務配置可以建立spring容器,但子業務容器之間是不能互相注入的。
具體內容能夠查看框架說明書《3.1. Webx的初始化》
WEB-INF/common文件夾下各個配置文件說明
- pipeline.xml:攔截器配置文件,至關於SpringMVC(Struts)中的Interceptor。
- pipeline-exception.xml:異常攔截配置文件。
- resources.xml:資源文件加載配置,負責資源的重定向、重命名等。
- uris.xml:外部地址url調用配置文件。
- webx-component-and-root.xml:配置模板渲染引擎、映射規則等。
- webx-component.xml:定義模板頁面可以直接使用的工具類。
從這些配置能夠看出,webx與咱們接觸的SpringMVC、Struts相似,只不過前者控制更加細粒度化,然後者咱們更多的是使用開源的封裝,因此配置量較少。
代碼結構及編寫
對於開發人員來講,最關心的莫過於上手去用這個框架。從工程接收請求到服務器響應並返回信息這整個過程,webx有本身的規則,與咱們所接觸的開源框架有所區別。以下圖:
根據Http請求中所帶參數中是否有action,Webx在代碼層執行的內容也有所區別。
不帶action參數請求
webx執行步驟以下:
步驟1、若控制層screen中存在Login.java代碼,則執行Login.java代碼。
步驟2、執行模板層layout中login.vm(若layout中沒有對應名字的佈局模板,則會調用默認模板default.vm)。
步驟3、執行模板層screen中的login.vm。
帶action參數請求
webx執行步驟以下:
步驟1、執行控制層action中LoginController.java代碼,指定類必須存在,不然會出現404異常。
步驟2、若控制層screen中存在Login.java代碼,則執行Login.java代碼。
步驟3、執行模板層layout中login.vm(若layout中沒有對應名字的佈局模板,則會調用默認模板default.vm)。
步驟4、執行模板層screen中的login.vm。
控制層action、screen層編寫
Webx規定了action、screen層的默認入口函數爲execute,即當類名與路徑可以匹配的時候(路徑與類名能夠以駝峯命名方式,也能夠中間如下劃線「_」來鏈接,只有首字母可以忽略大小寫),webx會執行類名下execute()方法。示例:
工程中經常使用的方法
控制層action:處理用戶操做動做,好比登陸、提交數據等。
控制層screen:處理頁面展現所需內容。
在老版本的webx中(version小於webx3.0.9)screen層一個Java類只能處理一個頁面。而action層能夠處理多個不一樣業務動做。
action層代碼有所變化,具體示例以下:
(1)提交時必須指明訪問的具體方法,且須要有「event_submit_」前綴。
(2)指定具體的action時,須要注意包路徑。
攔截器
Webx中針對攔截器的配置主要集中在pipeline.xml中。在平常業務開發中免不了要進行登陸、權限等驗證,而這部分業務做爲攔截器再適合不過了。詳細配置方式能夠查看
框架說明書《6.3.3. Pipeline的使用》。