4W字的後端面試知識點總結(持續更新)
點贊再看,養成習慣,微信搜尋【三太子敖丙】關注這個網際網路苟且偷生的工具人。
本文 GitHub https://github.com/JavaFamily 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
前言
前段時間敖丙不是在複習嘛,很多小夥伴也想要我的複習路線,以及我自己筆記裡面的一些知識點,好了,丙丙花了一個月的時間,整整一個月啊,給大家整理出來了。
一上來我就放個大招好吧,我的複習腦圖,可以說是全得不行,為了防止被盜圖,我加了水印哈。
這期看下去你會發現很硬核,而且我會持續更新,啥也不說了,看在我熬夜一個月滿臉痘痘的份上,你可以點讚了哈哈。
注:如果圖被壓縮了,可以去公眾號【三太子敖丙】回覆【複習】獲取原圖
Spring
Spring框架的七大模組
Spring Core:框架的最基礎部分,提供 IoC 容器,對 bean 進行管理。
Spring Context:繼承BeanFactory,提供上下文資訊,擴展出JNDI、EJB、電子郵件、國際化等功能。
Spring DAO:提供了JDBC的抽象層,還提供了宣告性事務管理方法。
Spring ORM:提供了JPA、JDO、Hibernate、MyBatis 等ORM對映層.
Spring AOP:集成了所有AOP功能
Spring Web:提供了基礎的 Web 開發的上下文資訊,現有的Web框架,如JSF、Tapestry、Structs等,提供了整合
Spring Web MVC:提供了 Web 應用的 Model-View-Controller 全功能實現。
Bean定義5種作用域
singleton(單例) prototype(原型) request session global session
spring ioc初始化流程?
resource定位 即尋找使用者定義的bean資源,由 ResourceLoader通過統一的介面Resource介面來完成 beanDefinition載入 BeanDefinitionReader讀取、解析Resource定位的資源 成BeanDefinition 載入到ioc中(通過HashMap進行維護BD) BeanDefinition註冊 即向IOC容器註冊這些BeanDefinition, 通過BeanDefinitionRegistery實現
BeanDefinition載入流程?
定義BeanDefinitionReader解析xml的document BeanDefinitionDocumentReader解析document成beanDefinition
DI依賴注入流程? (例項化,處理Bean之間的依賴關係)
過程在Ioc初始化後,依賴注入的過程是使用者第一次向IoC容器索要Bean時觸發
如果設定lazy-init=true,會在第一次getBean的時候才初始化bean, lazy-init=false,會容器啟動的時候直接初始化(singleton bean);
呼叫BeanFactory.getBean()生成bean的;
生成bean過程運用裝飾器模式產生的bean都是beanWrapper(bean的增強);
依賴注入怎麼處理bean之間的依賴關係?
其實就是通過在beanDefinition載入時,如果bean有依賴關係,通過佔位符來代替,在呼叫getbean時候,如果遇到佔位符,從ioc裡獲取bean注入到本例項來
Bean的生命週期?
例項化Bean: Ioc容器通過獲取BeanDefinition物件中的資訊進行例項化,例項化物件被包裝在BeanWrapper物件中 設定物件屬性(DI):通過BeanWrapper提供的設定屬性的介面完成屬性依賴注入; 注入Aware介面(BeanFactoryAware, 可以用這個方式來獲取其它 Bean,ApplicationContextAware):Spring會檢測該物件是否實現了xxxAware介面,並將相關的xxxAware例項注入給bean BeanPostProcessor:自定義的處理(分前置處理和後置處理) InitializingBean和init-method:執行我們自己定義的初始化方法 使用 destroy:bean的銷燬
IOC:控制反轉:將物件的建立權,由Spring管理. DI(依賴注入):在Spring建立物件的過程中,把物件依賴的屬性注入到類中。
Spring的IOC注入方式
構造器注入 setter方法注入 註解注入 介面注入
怎麼檢測是否存在迴圈依賴?
Bean在建立的時候可以給該Bean打標,如果遞迴呼叫回來發現正在建立中的話,即說明了迴圈依賴了。
Spring如解決Bean迴圈依賴問題?
Spring中迴圈依賴場景有:
構造器的迴圈依賴 屬性的迴圈依賴 singletonObjects:第一級快取,裡面放置的是例項化好的單例物件; earlySingletonObjects:第二級快取,裡面存放的是提前曝光的單例物件; singletonFactories:第三級快取,裡面存放的是要被例項化的物件的物件工廠 建立bean的時候Spring首先從一級快取singletonObjects中獲取。如果獲取不到,並且物件正在建立中,就再從二級快取earlySingletonObjects中獲取,如果還是獲取不到就從三級快取singletonFactories中取(Bean呼叫建構函式進行例項化後,即使屬性還未填充,就可以通過三級快取向外提前暴露依賴的引用值(提前曝光),根據物件引用能定位到堆中的物件,其原理是基於Java的引用傳遞),取到後從三級快取移動到了二級快取完全初始化之後將自己放入到一級快取中供其他使用, 因為加入singletonFactories三級快取的前提是執行了構造器,所以構造器的迴圈依賴沒法解決。 構造器迴圈依賴解決辦法:在建構函式中使用@Lazy註解延遲載入。在注入依賴時,先注入代理物件,當首次使用時再建立物件說明:一種互斥的關係而非層次遞進的關係,故稱為三個Map而非三級快取的緣由 完成注入;
Spring 中使用了哪些設計模式?
工廠模式: spring中的BeanFactory就是簡單工廠模式的體現,根據傳入唯一的標識來獲得bean物件; 單例模式: 提供了全域性的訪問點BeanFactory; 代理模式: AOP功能的原理就使用代理模式(1、JDK動態代理。2、CGLib位元組碼生成技術代理。) 裝飾器模式: 依賴注入就需要使用BeanWrapper; 觀察者模式: spring中Observer模式常用的地方是listener的實現。如ApplicationListener。 策略模式: Bean的例項化的時候決定採用何種方式初始化bean例項(反射或者CGLIB動態位元組碼生成)
AOP 核心概念
1、切面(aspect):類是對物體特徵的抽象,切面就是對橫切關注點的抽象
2、橫切關注點:對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點。
3、連線點(joinpoint):被攔截到的點,因為 Spring 只支援方法型別的連線點,所以在Spring 中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器。
4、切入點(pointcut):對連線點進行攔截的定義
5、通知(advice):所謂通知指的就是指攔截到連線點之後要執行的程式碼,通知分為前置、後置、異常、最終、環繞通知五類。
6、目標物件:代理的目標物件
7、織入(weave):將切面應用到目標物件並導致代理物件建立的過程
8、引入(introduction):在不修改程式碼的前提下,引入可以在執行期為類動態地新增方法或欄位。
解釋一下AOP
傳統oop開發程式碼邏輯自上而下的,這個過程中會產生一些橫切性問題,這些問題與我們主業務邏輯關係不大,會散落在程式碼的各個地方,造成難以維護,aop思想就是把業務邏輯與橫切的問題進行分離,達到解耦的目的,提高程式碼重用性和開發效率;
AOP 主要應用場景有:
記錄日誌 監控效能 許可權控制 事務管理
AOP原始碼分析
@EnableAspectJAutoProxy給容器(beanFactory)中註冊一個AnnotationAwareAspectJAutoProxyCreator物件;
AnnotationAwareAspectJAutoProxyCreator對目標物件進行代理物件的建立,物件內部,是封裝JDK和CGlib兩個技術,實現動態代理物件建立的(建立代理物件過程中,會先建立一個代理工廠,獲取到所有的增強器(通知方法),將這些增強器和目標類注入代理工廠,再用代理工廠建立物件);
代理物件執行目標方法,得到目標方法的攔截器鏈,利用攔截器的鏈式機制,依次進入每一個攔截器進行執行
AOP應用場景
日誌記錄 事務管理 執行緒池關閉等
AOP使用哪種動態代理?
當bean的是實現中存在介面或者是Proxy的子類,---jdk動態代理;不存在介面,spring會採用CGLIB來生成代理物件; JDK 動態代理主要涉及到 java.lang.reflect 包中的兩個類:Proxy 和 InvocationHandler。 Proxy 利用 InvocationHandler(定義橫切邏輯) 介面動態建立 目標類的代理物件。
jdk動態代理
通過bind方法建立代理與真實物件關係,通過Proxy.newProxyInstance(target)生成代理物件 代理物件通過反射invoke方法實現呼叫真實物件的方法
動態代理與靜態代理區別
靜態代理,程式執行前代理類的.class檔案就存在了; 動態代理:在程式執行時利用反射動態建立代理物件<複用性,易用性,更加集中都呼叫invoke>
CGLIB與JDK動態代理區別
Jdk必須提供接口才能使用; C不需要,只要一個非抽象類就能實現動態代理
SpringMVC
springMVC流程:
(1):使用者請求傳送給DispatcherServlet,DispatcherServlet呼叫HandlerMapping處理器對映器;
(2):HandlerMapping根據xml或註解找到對應的處理器,生成處理器物件返回給DispatcherServlet;
(3):DispatcherServlet會呼叫相應的HandlerAdapter;
(4):HandlerAdapter經過適配呼叫具體的處理器去處理請求,生成ModelAndView返回給DispatcherServlet
(5):DispatcherServlet將ModelAndView傳給ViewReslover解析生成View返回給DispatcherServlet;
(6):DispatcherServlet根據View進行渲染檢視;
->DispatcherServlet->HandlerMapping->Handler ->DispatcherServlet->HandlerAdapter處理handler->ModelAndView ->DispatcherServlet->ModelAndView->ViewReslover->View ->DispatcherServlet->返回給客戶
Mybatis
Mybatis原理
sqlsessionFactoryBuilder生成sqlsessionFactory(單例) 工廠模式生成sqlsession執行sql以及控制事務 Mybatis通過動態代理使Mapper(sql對映器)介面能執行起來即為介面生成代理物件將sql查詢到結果對映成pojo
sqlSessionFactory構建過程
解析並讀取配置中的xml建立Configuration物件 (單例) 使用Configruation類去建立sqlSessionFactory(builder模式)
Mybatis一級快取與二級快取
預設情況下一級快取是開啟的,而且是不能關閉的。
一級快取是指 SqlSession 級別的快取 原理:使用的資料結構是一個 map,如果兩次中間出現 commit 操作 (修改、新增、刪除),本 sqlsession 中的一級快取區域全部清空 二級快取是指可以跨 SqlSession 的快取。是 mapper 級別的快取; 原理: 是通過 CacheExecutor 實現的。CacheExecutor其實是 Executor 的代理物件
Zookeeper+eureka+springcloud
SpringBoot啟動流程
new springApplication物件,利用spi機制載入applicationContextInitializer, applicationLister介面例項(META-INF/spring.factories);
調run方法準備Environment,載入應用上下文(applicationContext),釋出事件 很多通過lister實現
建立spring容器, refreshContext() ,實現starter自動化配置,spring.factories檔案載入, bean例項化
SpringBoot自動配置的原理
@EnableAutoConfiguration找到META-INF/spring.factories(需要建立的bean在裡面)配置檔案 讀取每個starter中的spring.factories檔案
Spring Boot 的核心註解
核心註解是@SpringBootApplication 由以下三種組成
@SpringBootConfiguration:組合了 @Configuration 註解,實現配置檔案的功能。 @EnableAutoConfiguration:開啟自動配置的功能。 @ComponentScan:Spring元件掃描。
SpringBoot常用starter都有哪些
spring-boot-starter-web - Web 和 RESTful 應用程式; spring-boot-starter-test - 單元測試和整合測試; spring-boot-starter-jdbc - 傳統的 JDBC; spring-boot-starter-security - 使用 SpringSecurity 進行身份驗證和授權; spring-boot-starter-data-jpa - 帶有 Hibernate 的 Spring Data JPA; spring-boot-starter-data-rest - 使用 Spring Data REST 公佈簡單的 REST 服務
Spring Boot 的核心配置檔案
(1):Application.yml 一般用來定義單個應用級別的,如果搭配 spring-cloud-config 使用
(2).Bootstrap.yml(先載入) 系統級別的一些引數配置,這些引數一般是不變的
Zuul與Gateway區別
(1):zuul則是netflix公司的專案整合在spring-cloud中使用而已, Gateway是spring-cloud的 一個子專案;
(2):zuul不提供非同步支援流控等均由hystrix支援, gateway提供了非同步支援,提供了抽象負載均衡,提供了抽象流控; 理論上gateway則更適合於提高系統吞吐量(但不一定能有更好的效能),最終效能還需要通過嚴密的壓測來決定
(3):兩者底層實現都是servlet,但是gateway多嵌套了一層webflux框架
(4): zuul可用至其他微服務框架中,內部沒有實現限流、負載均衡;gateway只能用在springcloud中;
Zuul原理分析
(1):請求給zuulservlet處理(HttpServlet子類) zuulservlet中有一個zuulRunner物件,該物件中初始化了RequestContext(儲存請求的資料),RequestContext被所有的zuulfilter共享;
(2): zuulRunner中有 FilterProcessor(zuulfilter的管理器),其從filterloader 中獲取zuulfilter;
(3):有了這些filter之後, zuulservelet執行的Pre-> route-> post 型別的過濾器,如果在執行這些過濾器有錯誤的時候則會執行error型別的過濾器,執行完後把結果返回給客戶端.
Gateway原理分析
(1):請求到達DispatcherHandler, DispatchHandler在IOC容器初始化時會在容器中例項化HandlerMapping介面
(2):用handlerMapping根據請求URL匹配到對應的Route,然後有對應的filter做對應的請求轉發最終response返回去
Zookeeper 工作原理(待查)
Zookeeper 的核心是原子廣播,這個機制保證了各個 server 之間的同步。實現這個機制的協議叫做 Zab 協議。Zab 協議有兩種模式,它們分別是恢復模式和廣播模式。
zoo與eur區別
zookeeper保證cp(一致性) eureka保證ap(可用性) zoo在選舉期間註冊服務癱瘓,期間不可用 eur各個節點平等關係,只要有一臺就可保證服務可用,而查詢到的資料可能不是最新的,可以很好應對網路故障導致部分節點失聯情況 zoo有leader和follower角色,eur各個節點平等 zoo採用半數存活原則(避免腦裂),eur採用自我保護機制來解決分割槽問題 eur本質是個工程,zoo只是一個程序 ZooKeeper基於CP,不保證高可用,如果zookeeper正在選主,或者Zookeeper叢集中半數以上機器不可用,那麼將無法獲得資料。 Eureka基於AP,能保證高可用,即使所有機器都掛了,也能拿到本地快取的資料。作為註冊中心,其實配置是不經常變動的,只有發版(釋出新的版本)和機器出故障時會變。對於不經常變動的配置來說,CP是不合適的,而AP在遇到問題時可以用犧牲一致性來保證可用性,既返回舊資料,快取資料。 所以理論上Eureka是更適合做註冊中心。而現實環境中大部分專案可能會使用ZooKeeper,那是因為叢集不夠大,並且基本不會遇到用做註冊中心的機器一半以上都掛了的情況。所以實際上也沒什麼大問題。
Hystrix原理(待查)
通過維護一個自己的執行緒池,當執行緒池達到閾值的時候,就啟動服務降級,返回fallback預設值
為什麼需要hystrix熔斷
防止雪崩,及時釋放資源,防止系統發生更多的額級聯故障,需要對故障和延遲進行隔離,防止單個依賴關係的失敗影響整個應用程式;
微服務優缺點
每個服務高內聚,鬆耦合,面向介面程式設計; 服務間通訊成本,資料一致性,多服務運維難度增加,http傳輸效率不如rpc
eureka自我保護機制
eur不移除長時間沒收到心跳而應該過期的服務 仍然接受新服務註冊和查詢請求,但是不會同步到其它節點(高可用) 當網路穩定後,當前例項新註冊資訊會同步到其它節點(最終一致性)
MQ對比
ActiveMQ:Apache出品,最早使用的訊息佇列產品,時間比較長了,最近版本更新比較緩慢。 RabbitMQ:erlang語言開發,支援很多的協議,非常重量級,更適合於企業級的開發。效能較好,但是不利於做二次開發和維護。 RocketMQ:阿里開源的訊息中介軟體,純Java開發,具有高吞吐量、高可用性、適合大規模分散式系統應用的特點,分散式事務。 ZeroMQ:號稱最快的訊息佇列系統,尤其針對大吞吐量的需求場景,採用 C 語言實現。 訊息佇列的選型需要根據具體應用需求而定,ZeroMQ 小而美,RabbitMQ 大而穩,Kakfa 和 RocketMQ 快而強勁
JAVA基礎
AVL樹與紅黑樹(R-B樹)的區別與聯絡
AVL是嚴格的平衡樹,因此在增加或者刪除節點的時候,根據不同情況,旋轉的次數比紅黑樹要多; 紅黑樹是用非嚴格的平衡來換取增刪節點時候旋轉次數的降低開銷; 所以簡單說,查詢多選擇AVL樹,查詢更新次數差不多選紅黑樹 AVL樹順序插入和刪除時有20%左右的效能優勢,紅黑樹隨機操作15%左右優勢,現實應用當然一般都是隨機情況,所以紅黑樹得到了更廣泛的應用 索引為B+樹 Hashmap為紅黑樹
為啥redis zset使用跳躍連結串列而不用紅黑樹實現
skiplist的複雜度和紅黑樹一樣,而且實現起來更簡單。 在併發環境下紅黑樹在插入和刪除時需要rebalance,效能不如跳錶。
JAVA基本資料型別
(1個位元組是8個bit) 整數型:byte(1位元組)、short(2位元組)、int(4位元組)、long(8位元組) 浮點型:float(4位元組)、double(8位元組) 布林型:boolean(1位元組) 字元型:char(2位元組)
IO與NIO
包括 類File,outputStream,inputStream,writer,readerseralizable(5類1介面)
NIO三大核心內容 selector(選擇器,用於監聽channel),channel(通道),buffer(緩衝區)
NIO與IO區別,IO面向流,NIO面向緩衝區;io阻塞,nio非阻塞
異常類
throwable為父類,子為error跟exception,exception分runtime(空指標,越界等)跟checkexception(sql,io,找不到類等異常)
LVS(4層與7層)原理
由前端虛擬負載均衡器和後端真實伺服器群組成; 請求傳送給虛擬伺服器後其根據包轉發策略以及負載均衡排程演算法轉發給真實伺服器 所謂四層(lvs,f5)就是基於IP+埠的負載均衡;七層(nginx)就是基於URL等應用層資訊的負載均衡
StringBuilder與StringBuffer
StringBuilder 更快; StringBuffer是執行緒安全的
interrupt/isInterrupted/interrupt區別
interrupt() 呼叫該方法的執行緒的狀態為將被置為"中斷"狀態(set操作) isinterrupted() 是作用於呼叫該方法的執行緒物件所對應的執行緒的中斷訊號是true還是false(get操作)。例如我們可以在A執行緒中去呼叫B執行緒物件的isInterrupted方法,檢視的是A interrupted()是靜態方法:內部實現是呼叫的當前執行緒的isInterrupted(),並且會重置當前執行緒的中斷狀態(getandset)
sleep與wait區別
sleep屬於執行緒類,wait屬於object類;sleep不釋放鎖
CountDownLatch和CyclicBarrier區別
con用於主執行緒等待其他子執行緒任務都執行完畢後再執行,cyc用於一組執行緒相互等待大家都達到某個狀態後,再同時執行; CountDownLatch是不可重用的,CyclicBarrier可重用
終止執行緒方法
使用退出標誌,說執行緒正常退出; 通過判斷this.interrupted() throw new InterruptedException()來停止 使用String常量池作為鎖物件會導致兩個執行緒持有相同的鎖,另一個執行緒不執行,改用其他如new Object()
ThreadLocal的原理和應用
原理:
執行緒中建立副本,訪問自己內部的副本變數,內部實現是其內部類名叫ThreadLocalMap的成員變數threadLocals,key為本身,value為實際存值的變數副本
應用:
用來解決資料庫連線,存放connection物件,不同執行緒存放各自session; 解決simpleDateFormat執行緒安全問題; 會出現記憶體洩漏,顯式remove..不要與執行緒池配合,因為worker往往是不會退出的;
threadLocal 記憶體洩漏問題
如果是強引用,設定tl=null,但是key的引用依然指向ThreadLocal物件,所以會有記憶體洩漏,而使用弱引用則不會; 但是還是會有記憶體洩漏存在,ThreadLocal被回收,key的值變成null,導致整個value再也無法被訪問到; 解決辦法:在使用結束時,呼叫ThreadLocal.remove來釋放其value的引用;
如果我們要獲取父執行緒的ThreadLocal值呢
ThreadLocal是不具備繼承性的,所以是無法獲取到的,但是我們可以用InteritableThreadLocal來實現這個功能。InteritableThreadLocal繼承來ThreadLocal,重寫了createdMap方法,已經對應的get和set方法,不是在利用了threadLocals,而是interitableThreadLocals變數。
這個變數會線上程初始化的時候(呼叫init方法),會判斷父執行緒的interitableThreadLocals變數是否為空,如果不為空,則把放入子執行緒中,但是其實這玩意沒啥鳥用,當父執行緒建立完子執行緒後,如果改變父執行緒內容是同步不到子執行緒的。。。同樣,如果在子執行緒建立完後,再去賦值,也是沒啥鳥用的
執行緒狀態
執行緒池有5種狀態:running,showdown,stop,Tidying,TERMINATED。
running:執行緒池處於執行狀態,可以接受任務,執行任務,建立執行緒預設就是這個狀態了
showdown:呼叫showdown()函式,不會接受新任務,但是會慢慢處理完堆積的任務。
stop:呼叫showdownnow()函式,不會接受新任務,不處理已有的任務,會中斷現有的任務。
Tidying:當執行緒池狀態為showdown或者stop,任務數量為0,就會變為tidying。這個時候會呼叫鉤子函式terminated()。
TERMINATED:terminated()執行完成。
線上程池中,用了一個原子類來記錄執行緒池的資訊,用了int的高3位表示狀態,後面的29位表示執行緒池中執行緒的個數。
Java中的執行緒池是如何實現的?
執行緒中執行緒被抽象為靜態內部類Worker,是基於AQS實現的存放在HashSet中; 要被執行的執行緒存放在BlockingQueue中; 基本思想就是從workQueue中取出要執行的任務,放在worker中處理;