1. 程式人生 > >java面試題目

java面試題目

種類型 false redis主從 補充 col 所在 理解 spring 繼續

1.項目中Spring AOP用在什麽地方,為什麽這麽用,切點,織入,通知,用自己的話描述一下,AOP原理,動態代理2種實現。

主要是事務那方面,采用聲明式的事務配置方式,是AOP給你封裝好的。

通知:

定義:切面也需要完成工作。在 AOP 術語中,切面的工作被稱為通知。

工作內容:通知定義了切面是什麽以及何時使用。除了描述切面要完成的工作,通知還解決何時執行這個工作。

Spring 切面可應用的 5 種通知類型:

Before——在方法調用之前調用通知

After——在方法完成之後調用通知,無論方法執行成功與否

After-returning——在方法執行成功之後調用通知

After-throwing——在方法拋出異常後進行通知

Around——通知包裹了被通知的方法,在被通知的方法調用之前和調用之後執行自定義的行為

連接點:

定義:連接點是一個應用執行過程中能夠插入一個切面的點。 連接點可以是調用方法時、拋出異常時、甚至修改字段時、 切面代碼可以利用這些點插入到應用的正規流程中 程序執行過程中能夠應用通知的所有點。

切點:

定義:如果通知定義了“什麽”和“何時”。那麽切點就定義了“何處”。切點會匹配通知所要織入的一個或者多個連接點。 通常使用明確的類或者方法來指定這些切點。

作用:定義通知被應用的位置(在哪些連接點)

切面:

定義:切面是通知和切點的集合,通知和切點共同定義了切面的全部功能——它是什麽,在何時何處完成其功能。

引入: 引入允許我們向現有的類中添加方法或屬性

織入: 織入是將切面應用到目標對象來創建的代理對象過程。 切面在指定的連接點被織入到目標對象中,在目標對象的生命周期中有多個點可以織入。

AOP原理:面向切面編程,就是把可重用的功能提取出來,然後將這些通用功能在合適的時候織入到應用程序中,比如事務管理、權限控制、日誌記錄、性能統計等。

動態代理的實現:

CGLIB中的動態代理是JDK proxy的一個很好的補充,在JDK中實現代理時,要求代理類必須是繼承接口的類,因為JDK最後生成的proxy class其實就是實現了被代理類所繼承的接口並且繼承了java中的Proxy類,通過反射找到接口的方法,調用InvocationHandler的invoke 方法實現攔截。CGLIb中最後生成的proxy class是一個繼承被代理類的class,通過重寫被代理類中的非final的方法實現代理。

總結為: JDK proxy:代理類必須實現接口,不需要引來第三方庫

CGLIB: 代理類不能是final,代理的方法也不能是final(繼承限制),針對類實現的代理,必須依賴CGLib類庫。(hibernate中相關的代理采用的是CGLib來執行)。

2.Spring裏面註解用過沒有?autowired 和resource區別

@Resource和@Autowired都是做bean的註入時使用,其實@Resource並不是Spring的註解,它的包是javax.annotation.Resource,需要導入,但是Spring支持該註解的註入。

1、共同點

兩者都可以寫在字段和setter方法上。兩者如果都寫在字段上,那麽就不需要再寫setter方法。

2、不同點

(1)@Autowired

@Autowired為Spring提供的註解,需要導入包org.springframework.beans.factory.annotation.Autowired;只按照byType註入。

技術分享圖片

@Autowired註解是按照類型(byType)裝配依賴對象,默認情況下它要求依賴對象必須存在,如果允許null值,可以設置它的required屬性為false。如果我們想使用按照名稱(byName)來裝配,可以結合@Qualifier註解一起使用。如下:

技術分享圖片

(2)@Resource

@Resource默認按照ByName自動註入,由J2EE提供,需要導入包javax.annotation.Resource。@Resource有兩個重要的屬性:name和type,而Spring將@Resource註解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。

所以,如果使用name屬性,則使用byName的自動註入策略,而使用type屬性時則使用byType自動註入策略。如果既不制定name也不制定type屬性,這時將通過反射機制使用byName自動註入策略。

技術分享圖片

註:最好是將@Resource放在setter方法上,因為這樣更符合面向對象的思想,通過set、get去操作屬性,而不是直接去操作屬性。

3.Linux命令,怎麽日誌文件裏面找關鍵字

1、查看日誌 前 n行

  cat 文件名 | head -n 數量

  demo:

    cat test.log | head -n 200  # 查看test.log前200行

2、查看日誌 尾 n行

  cat 文件名 | tail -n 數量

  demo:

    cat test.log | tail -n 200  # 查看test.log倒數200行

3、根據 關鍵詞 查看日誌 並返回關鍵詞所在行

  方法一:cat 路徑/文件名 | grep 關鍵詞

  demo:

    cat test.log | grep "http"  # 返回test.log中包含http的所有行

  方法二:grep -i 關鍵詞 路徑/文件名 (與方法一效果相同,不同寫法而已)

  demo:

    grep -i "http" ./test.log  # 返回test.log中包含http的所有行

單個文件可以使用vi或vim編輯器打開日誌文件,使用編輯器裏的查找功能。在查看模式下,符號/後面跟關鍵字向下查找,符號?後面跟關鍵字向上查找,按n查找下一個,按N查找上一個。

4.怎麽殺死一個進程

方法1: 通過kill 進程id的方式可以實現, 首先需要知道進程id, 例如,想要殺死firefox的進程,通過 ps -ef|grep firefox,可以查到firefox的進程id: 然後通過 kill 3781 就可以關閉進程了. 補充: 1. kill -9 來強制終止退出, 例如: kill -9 3781 kill -9 -1 終止你擁有的全部進程。

方法2: killall 通過程序的名字,來殺死進程 例如: killall firefox 註意: 該命令可以使用 -9 參數來強制殺死進程, killall -9 firefox

方法3: pkill 通過程序的名字, 直接殺死所有進程 例如: pkill firefox

5.MQ,zookeeper,dubbo,redis,是否了解分布式,是否了解負載均衡?

MQ 消息隊列(上遊--消息隊列--下遊) 在高並發環境下,由於來不及同步處理,請求往往會發生阻塞,比如大量的insert、update之類的請求同時到達mysql,直接導致無數的行鎖和表鎖,從而觸發too many connections錯誤,通過消息隊列,可以異步處理請求,從而緩解系統壓力。

MQ的不足是: 1)系統更復雜,多了一個MQ組件 2)消息傳遞路徑更長,延時會增加 3)消息可靠性和重復性互為矛盾,消息不丟不重難以同時保證 4)上遊無法知道下遊的執行結果,這一點是很致命的。 調用方實時依賴執行結果的業務場景,請使用調用,而不是MQ。

什麽時候使用MQ

【典型場景一:數據驅動的任務依賴】

什麽是任務依賴,舉個栗子,互聯網公司經常在淩晨進行一些數據統計任務,這些任務之間有一定的依賴關系,比如:

1)task3需要使用task2的輸出作為輸入

2)task2需要使用task1的輸出作為輸入 這樣的話,tast1, task2, task3之間就有任務依賴關系,必須task1先執行,再task2執行,載task3執行。

采用MQ解耦: 1)task1準時開始,結束後發一個“task1 done”的消息 2)task2訂閱“task1 done”的消息,收到消息後第一時間啟動執行,結束後發一個“task2 done”的消息 3)task3同理

采用MQ的優點是:

1)不需要預留buffer,上遊任務執行完,下遊任務總會在第一時間被執行

2)依賴多個任務,被多個任務依賴都很好處理,只需要訂閱相關消息即可

3)有任務執行時間變化,下遊任務都不需要調整執行時間

需要特別說明的是,MQ只用來傳遞上遊任務執行完成的消息,並不用於傳遞真正的輸入輸出數據。

【典型場景二:上遊不關心執行結果】

上遊需要關註執行結果時要用“調用”,上遊不關註執行結果時,就可以使用MQ了。

舉個栗子,58同城的很多下遊需要關註“用戶發布帖子”這個事件,比如招聘用戶發布帖子後,招聘業務要獎勵58豆,房產用戶發布帖子後,房產業務要送2個置頂,二手用戶發布帖子後,二手業務要修改用戶統計數據。

如果使用調用關系,會導致上下遊邏輯+物理依賴嚴重

優化方案是,采用MQ解耦: 1)帖子發布成功後,向MQ發一個消息 2)哪個下遊關註“帖子發布成功”的消息,主動去MQ訂閱

其優點是:1.上遊執行時間短,2.上下遊邏輯+物理解耦,,模塊之間不相互依賴.3.新增一個下遊消息關註方,上遊不需要修改任何代碼

典型場景三:上遊關註執行結果,但執行時間很長 有時候上遊需要關註執行結果,但執行結果時間很長(典型的是調用離線處理,或者跨公網調用),也經常使用回調網關+MQ來解耦。

舉個栗子,微信支付,跨公網調用微信的接口,執行時間會比較長,但調用方又非常關註執行結果,此時一般怎麽玩呢?

一般采用“回調網關+MQ”方案來解耦:

1)調用方直接跨公網調用微信接口

2)微信返回調用成功,此時並不代表返回成功

3)微信執行完成後,回調統一網關

4)網關將返回結果通知MQ

5)請求方收到結果通知

總結

MQ是一個互聯網架構中常見的解耦利器。

什麽時候不使用MQ? 上遊實時關註執行結果

什麽時候使用MQ? 1)數據驅動的任務依賴

2)上遊不關心多下遊執行結果

3)異步返回執行時間長

zookeeper

1.ZooKeeper是什麽?
ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,它是集群的管理者,監視著集群中各個節點的狀態,根據節點提交的反饋進行下一步合理操作。最終,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶

2.ZooKeeper提供了什麽?

1)文件系統

2)通知機制

3.Zookeeper文件系統

每個子目錄項如 NameService 都被稱作為znode,和文件系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在於znode是可以存儲數據的。

有四種類型的znode:

1、PERSISTENT-持久化目錄節點

客戶端與zookeeper斷開連接後,該節點依舊存在

2、PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點

客戶端與zookeeper斷開連接後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號

3、EPHEMERAL-臨時目錄節點

客戶端與zookeeper斷開連接後,該節點被刪除

4、EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點

客戶端與zookeeper斷開連接後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號

4.Zookeeper通知機制

客戶端註冊監聽它關心的目錄節點,當目錄節點發生變化(數據改變、被刪除、子目錄節點增加刪除)時,zookeeper會通知客戶端。

5.Zookeeper做了什麽?

1.命名服務 2.配置管理 3.集群管理 4.分布式鎖 5.隊列管理

6.Zookeeper命名服務

在zookeeper的文件系統裏創建一個目錄,即有唯一的path。在我們使用tborg無法確定上遊程序的部署機器時即可與下遊程序約定好path,通過path即能互相探索發現。

7.Zookeeper的配置管理

程序總是需要配置的,如果程序分散部署在多臺機器上,要逐個改變配置就變得困難。現在把這些配置全部放到zookeeper上去,保存在 Zookeeper 的某個目錄節點中,然後所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 Zookeeper 的通知,然後從 Zookeeper 獲取新的配置信息應用到系統中就好

8.Zookeeper集群管理

所謂集群管理無在乎兩點:是否有機器退出和加入、選舉master。

對於第一點,所有機器約定在父目錄GroupMembers下創建臨時目錄節點,然後監聽父目錄節點的子節點變化消息。一旦有機器掛掉,該機器與 zookeeper的連接斷開,其所創建的臨時目錄節點被刪除,所有其他機器都收到通知:某個兄弟目錄被刪除,於是,所有人都知道:它上船了。

新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount又有了,對於第二點,我們稍微改變一下,所有機器創建臨時順序編號目錄節點,每次選取編號最小的機器作為master就好。

9.Zookeeper分布式鎖

有了zookeeper的一致性文件系統,鎖的問題變得容易。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。

對於第一類,我們將zookeeper上的一個znode看作是一把鎖,通過createznode的方式來實現。所有客戶端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。用完刪除掉自己創建的distribute_lock 節點就釋放出鎖。

對於第二類, /distribute_lock 已經預先存在,所有客戶端在它下面創建臨時順序編號目錄節點,和選master一樣,編號最小的獲得鎖,用完刪除,依次方便。

10.Zookeeper隊列管理

兩種類型的隊列:

1、同步隊列,當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達。

2、隊列按照 FIFO 方式進行入隊和出隊操作。

第一類,在約定目錄下創建臨時目錄節點,監聽節點數目是否是我們要求的數目。

第二類,和分布式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。

11.Zookeeper設計目的

1.最終一致性:client不論連接到哪個Server,展示給它都是同一個視圖,這是zookeeper最重要的性能。

2.可靠性:具有簡單、健壯、良好的性能,如果消息被到一臺服務器接受,那麽它將被所有的服務器接受。

3.實時性:Zookeeper保證客戶端將在一個時間間隔範圍內獲得服務器的更新信息,或者服務器失效的信息。但由於網絡延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數據,如果需要最新數據,應該在讀數據之前調用sync()接口。

4.等待無關(wait-free):慢的或者失效的client不得幹預快速的client的請求,使得每個client都能有效的等待。

5.原子性:更新只能成功或者失敗,沒有中間狀態。

6.順序性:包括全局有序和偏序兩種:全局有序是指如果在一臺服務器上消息a在消息b前發布,則在所有Server上消息a都將在消息b前被發布;偏序是指如果一個消息b在消息a後被同一個發送者發布,a必將排在b前面。

12.Zookeeper工作原理

Zookeeper 的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰後,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和 leader的狀態同步以後,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。

為了保證事務的順序一致性,zookeeper采用了遞增的事務id號(zxid)來標識事務。所有的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64位的數字,它高32位是epoch用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬於那個leader的統治時期。低32位用於遞增計數。

13.Zookeeper 下 Server工作狀態

每個Server在工作過程中有三種狀態:

LOOKING:當前Server不知道leader是誰,正在搜尋
LEADING:當前Server即為選舉出來的leader
FOLLOWING:leader已經選舉出來,當前Server與之同步

14.Zookeeper選主流程(basic paxos)

當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的Server都恢復到一個正確的狀態。Zk的選舉算法有兩種:一種是基於basic paxos實現的,另外一種是基於fast paxos算法實現的。系統默認的選舉算法為fast paxos。

1.選舉線程由當前Server發起選舉的線程擔任,其主要功能是對投票結果進行統計,並選出推薦的Server;

2.選舉線程首先向所有Server發起一次詢問(包括自己);

3.選舉線程收到回復後,驗證是否是自己發起的詢問(驗證zxid是否一致),然後獲取對方的id(myid),並存儲到當前詢問對象列表中,最後獲取對方提議的leader相關信息(id,zxid),並將這些信息存儲到當次選舉的投票記錄表中;

4.收到所有Server回復以後,就計算出zxid最大的那個Server,並將這個Server相關信息設置成下一次要投票的Server;

5.線程將當前zxid最大的Server設置為當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數,設置當前推薦的leader為獲勝的Server,將根據獲勝的Server相關信息設置自己的狀態,否則,繼續這個過程,直到leader被選舉出來。 通過流程分析我們可以得出:要使Leader獲得多數Server的支持,則Server總數必須是奇數2n+1,且存活的Server的數目不得少於n+1. 每個Server啟動後都會重復以上流程。在恢復模式下,如果是剛從崩潰狀態恢復的或者剛啟動的server還會從磁盤快照中恢復數據和會話信息,zk會記錄事務日誌並定期進行快照,方便在恢復時進行狀態恢復。

redis

Redis是一款開源的、高性能的鍵-值存儲(key-value store)。它常被稱作是一款數據結構服務器(data structure server)。

Redis的鍵是String類型,值可以包括字符串(strings)類型,同時它還包括哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等數據類型。 對於這些數據類型,你可以執行原子操作。

為了獲得優異的性能,Redis采用了內存中(in-memory)數據集(dataset)的方式。同時,Redis支持數據的持久化,需要經常將內存中的數據同步到磁盤來保證持久化。

Redis同樣支持主從復制(master-slave replication),並且具有非常快速的非阻塞首次同步( non-blocking first synchronization)、網絡斷開自動重連等功能。同時Redis還具有其它一些特性,其中包括簡單的事物支持、發布訂閱 ( pub/sub)、管道(pipeline)和虛擬內存(vm)等 。

Redis功能:

持久化:

redis是一個支持持久化的內存數據庫,即redis需要經常將內存中的數據同步到磁盤來保證持久化,這是相對memcache來說的一個大的優勢。redis支持兩種持久化方式,一種是 Snapshotting(快照)也是默認方式,另一種是Append-only file(縮寫aof)的方式。

主從復制:

主從復制允許多個slave server擁有和master server相同的數據庫副本。下面是關於redis主從復制的一些特點
1.master可以有多個slave。
2.除了多個slave連到相同的master外,slave也可以連接其他slave形成圖狀結構。
3.主從復制不會阻塞master。也就是說當一個或多個slave與master進行初次同步數據時,master可以繼續處理client發來的請求。相反slave在初次同步數據時則會阻塞,不能處理client的請求。
4.主從復制可以用來提高系統的可伸縮性(我們可以用多個slave 專門用於client的讀請求,比如sort操作可以使用slave來處理),也可以用來做簡單的數據冗余。
5.可以在master禁用數據持久化,只需要註釋掉master 配置文件中的所有save配置,然後只在slave上配置數據持久化。

事務:

redis對事務的支持目前還比較簡單。redis只能保證一個client發起的事務中的命令可以連續的執行,而中間不會插入其他client的命令。
Multi 事物開始
Exec 執行事務
Discard 放棄事物
Watch 監聽key
Unwatch 放棄所有key的監聽
watch 命令會監視給定的key,當exec時候如果監視的key從調用watch後發生過變化,則整個事務會失敗。註意watch的key是對整個連接有效的,和事務一樣,如果連接斷開,監視和事務都會被自動清除。

發布訂閱:

發布訂閱(pub/sub)是一種消息通信模式。訂閱者可以通過subscribe和psubscribe命令向redis server訂閱自己感興趣的消息類型,redis將消息類型稱為通道(channel)。當發布者通過publish命令向redis server發送特定類型的消息時。訂閱該消息類型的全部client都會收到此消息。這裏消息的傳遞是多對多的。一個client可以訂閱多個 channel,也可以向多個channel發送消息。
Subscribe
Unsubscribe
Psubscribe
Punsubscribe
Publish

管道:

redis是一個cs模式的tcp server,使用和http類似的請求響應協議。一個client可以通過一個socket連接發起多個請求命令。每個請求命令發出後client通常 會阻塞並等待redis服務處理,redis處理完後請求命令後會將結果通過響應報文返回給client。

虛擬內存:

redis沒有使用os提供的虛擬內存機制而是自己實現了自己的虛擬內存機制 ,但是思路和目的都是相同的。就是暫時把不經常訪問的數據從內存交換到磁盤中,從而騰出內存空間用於其他需要訪問的數據。

Redis應用場景:

1.取最新N個數據的操作
比如典型的取你網站的最新文章,通過下面方式,我們可以將最新的5000條評論的ID放在Redis的List集合中,並將超出集合部分從數據庫獲取
使用LPUSH latest.comments<ID>命令,向list集合中插入數據
插入完成後再用LTRIM latest.comments 0 5000命令使其永遠只保存最近5000個ID
然後我們在客戶端獲取某一頁評論時可以用下面的邏輯(偽代碼)
FUNCTION get_latest_comments(start,num_items):
id_list = redis.lrange("latest.comments",start,start+num_items-1)
IF id_list.length < num_items
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
END
RETURN id_list
END
如果你還有不同的篩選維度,比如某個分類的最新N條,那麽你可以再建一個按此分類的List,只存ID的話,Redis是非常高效的。

2.排行榜應用,取TOP N操作

這個需求與上面需求的不同之處在於,前面操作以時間為權重,這個是以某個條件為權重,比如按頂的次數排序,這時候就需要我們的sorted set出馬了,將你要排序的值設置成sorted set的score,將具體的數據設置成相應的value,每次只需要執行一條ZADD命令即可。
3.需要精準設定過期時間的應用
比如你可以把上面說到的sorted set的score值設置成過期時間的時間戳,那麽就可以簡單地通過過期時間排序,定時清除過期數據了,不僅是清除Redis中的過期數據,你完全可以把Redis裏這個過期時間當成是對數據庫中數據的索引,用Redis來找出哪些數據需要過期刪除,然後再精準地從數據庫中刪除相應的記錄。
4.計數器應用
Redis的命令都是原子性的,你可以輕松地利用INCR,DECR命令來構建計數器系統。

5.Uniq操作,獲取某段時間所有數據排重值
這個使用Redis的set數據結構最合適了,只需要不斷地將數據往set中扔就行了,set意為集合,所以會自動排重。
6.實時系統,反垃圾系統
通過上面說到的set功能,你可以知道一個終端用戶是否進行了某個操作,可以找到其操作的集合並進行分析統計對比等。沒有做不到,只有想不到。
7.Pub/Sub構建實時消息系統
Redis的Pub/Sub系統可以構建實時的消息系統,比如很多用Pub/Sub構建的實時聊天系統的例子。
8.構建隊列系統
使用list可以構建隊列系統,使用sorted set甚至可以構建有優先級的隊列系統。
9.緩存
這個不必說了,性能優於Memcached(在某些方面,並不是全面優於),數據結構更多樣化。

Redis總結:

Redis使用最佳方式是全部數據in-memory。
Redis更多場景是作為Memcached的替代者來使用。
當需要除key/value之外的更多數據類型支持時,使用Redis更合適。
當存儲的數據不能被剔除時,使用Redis更合適。(持久化)

對數據高並發讀寫
對海量數據的高效率存儲和訪問
對數據的高可擴展性和高可用性(分布式)

redis和memcached的區別:

1 Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲。
2 Redis支持數據的備份,即master-slave模式的數據備份。
3 Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。

4 memcache掛掉後,數據不可恢復; redis數據丟失後可以通過aof恢復

在Redis中,並不是所有的數據都一直存儲在內存中的。這是和Memcached相比一個最大的區別(我個人是這麽認為的)。

java面試題目