Spring
簡介
Spring 是一種用來簡化企業級應用開發的開源框架,包括Spring Framework, Spring Data, Spring Security,Spring Boot,SpringMVC等。Spring 家族最核心的概念當屬 AOP 和 IoC,詳解見下節。其中 Spring 優點如下:
降低了組件之間的耦合性 ,實現了軟件各層之間的解耦
可以使用便捷的眾多服務,如事務管理,消息服務等
容器提供了AOP技術,利用它很容易實現如權限攔截,運行期監控等功能
Spring對于主流的應用框架提供了集成支持,如Hibernate、JPA等
Spring屬于低侵入式設計,代碼的污染極低
Spring的高度開放性,開發者可以自由選擇Spring的部分或全部
AOP和IOC
AOP(Aspect Oriented Programming,面向切面編程)
AOP簡單說就是在目標方法執行前后自定義一些操作,一般都是基于代理模式來實現的,Spring支持兩種代理模式,JDK原生代理和CGLib代理。AOP給程序帶來良好的擴展性和封裝性,可以實現業務代碼與非業務代碼的隔離。比如可以在不改變目標代碼的前提下實現目標方法的增強:埋點業務處理、方法執行時間監控,打印日志,權限控制等等。
JDK動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。只能對實現了接口的類生成代理。
CGLib動態代理是利用ASM開源包,對代理對象類的Class文件加載進來,通過修改其字節碼生成子類來處理。
切面(Aspect):類是對物體特征的抽象,切面就是對橫切關注點的抽象。
切點(Pointcut):對連接點進行攔截的定義。
連接點(Joinpoint):被攔截到的點,比如方法(Spring中一般是方法)、字段、構造器。
通知(Advice):指攔截到連接點后要執行的代碼,通知分為前置、后置、異常、最終、環繞五類。
AOP:在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想
IoC(Inversion of Control,控制反轉)
IOC (Inversion of Control,控制反轉):對象之間的依賴關系由容器來創建。本來對象之間的關系是由開發者自己創建和維護的,在使用Spring框架后,對象之間的關系由容器來創建和維護,將開發者做的事讓容器做,這就是控制反轉。BeanFactory接口是Spring Ioc容器的核心接口。
DI (Dependecy Injection,依賴注入):我們在使用Spring容器的時候,容器通過調用set方法或者是構造器來建立對象之間的依賴關系。注入方式有設值注入、構造注入、注解注入、接口注入(基本不用),設值注入直觀,自然;構造注入可以在構造器中決定依賴關系的順序。
控制反轉是目標,依賴注入是我們實現控制反轉的一種手段。
SpringMVC和Struts
SpringMVC執行流程如下:
客戶端向Spring容器發起一個HTTP請求。
發起的請求被前端控制器(DispatcherServlet)攔截。
查詢處理器映射(HandlerMapping)得到執行鏈,并請求相應的處理器適配器(HandlerAdapter)。
執行處理器(Handler)并處理請求,以ModelAndView(屬性值和返回頁面)的形式返回。此處Handler即平時編寫的Controller。
前端控制器查詢視圖解析器(ViewResolver),并返回View。
成功渲染視圖則返回給客戶端,否則拋異常。
比較點SpringMVCStruts核心控制器DispatcherServletFilterDispatcher配置文件量少(AOP)量大(Interceptor機制)RESTful API易實現(方法級別)實現費勁(類級別)處理Ajax請求@ResponseBody返回響應文本攔截器集成Ajax性能稍快稍慢
DispatcherServlet初始化流程如下:
加載配置文件
掃描所有的相關類
初始化所有相關類的Class實例,并將其保存到IoC容器
自動化的依賴注入(Autowired)
初始化HandlerMapping
Spring事務
數據庫事務是指作為單個邏輯工作單元執行的一系列操作,要么完全地執行,要么完全地不執行。事務滿足原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability) 四大特性。
事務隔離級別
數據讀的三類問題:
問題解釋臟讀事務 A 讀取了事務 B 未提交的數據(發現讀到的數據是臟數據)不可重復讀事務 A 讀取了事務 B 已提交的更改數據(發現與前一次讀的不一致)幻讀事務 A 讀取了事務 B 已提交的新增數據(發現之前沒有這條數據的)
事務的四種隔離級別見下表,MySQL默認為REPEATABLE_READ:
隔離級別(簡寫)含義隱患READ_UNCOMMITTED允許讀未提交臟讀、不可重復讀、幻讀READ_COMMITTED允許讀已提交不可重復讀、幻讀REPEATABLE_READ允許重復讀幻讀SERIALIZABLE序列化讀–
事務管理
Spring事務管理器的接口是PlatformTransactionManager,通過這個接口,Spring為各個平臺如JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager、JpaTransactionManager)等都提供了對應的事務管理器。
事務的傳播特性
當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播,根據如下代碼中方法 A 有無事務,Spring定義了7種傳播行為(默認為REQUIRED):
@Transactionalvoid A(){ }@Transactionalvoid B(){A(); }
傳播行為(簡寫)含義REQUIRED如果沒有,就開啟一個事務;如果有,就加入當前事務(方法A加入到方法B)REQUIRES_NEW如果沒有,就開啟一個事務;如果有,就將當前事務掛起NESTED如果沒有,就開啟一個事務;如果有,就在當前事務中嵌套其他事務(主事務提交或回滾,子事務也會提交或回滾)SUPPORTS如果沒有,就以非事務方式執行;如果有,就使用當前事務NOT_SUPPORTED如果沒有,就以非事務方式執行;如果有,就將當前事務掛起NEVER如果沒有,就以非事務方式執行;如果有,就拋出異常MANDATORY如果沒有,就拋出異常;如果有,就使用當前事務
Spring Boot
Spring Boot來自于 Spring 大家族,是一套全新的框架,它默認幫我們進行了很多配置,集成了大量常用的第三方庫(例如 Jackson、JDBC、MongoDB、Redis、Mail 等),這些第三方庫幾乎都可以開箱即用。Spring Boot可以幫助我們快速搭建一個項目,從而讓開發者能夠更加專注于業務邏輯。
Spring擴展
實現BeanPostProcess接口在Bean生成前后進行操作。
實現BeanFactoryPostProcessor接口配置Bean元屬性。
實現FactoryBean接口定制個性化的Bean。
MyBatis
MyBatis是一款優秀的持久層框架,它幾乎避免了所有的JDBC代碼和手動設置參數以及獲取結果集,它可以使用XML或注解來將接口和POJO映射成數據庫中的記錄。
MyBatis與Spring集成的時候Spring提供了全局唯一的SqlSessionTemplate,SqlSessionTemplate 實現了SqlSession接口,那么如何保證多個線程調用同一個dao時拿到的SqlSession不會錯亂呢?這個時候就用到了ThreadLocal,SqlSessionUtils.getSqlSession()會首先查看當前線程資源map有無SqlSession,有則返回無則新建然后返回,這樣就能保證一條業務始終用的是同一個數據庫連接,也就能正確處理數據庫事務。
MyBatis和Hibernate
比較點MyBatisHibernate特點半自動(手寫SQL)全自動(根據映射生成SQL)SQL直接優化方便復雜數據庫移植性弱強緩存機制欠缺更優日志系統欠缺完整
Statement和PreparedStatement的區別
/PreparedStatement extends Statement///Statement用法sql1 ="select * from tbl_user where username='"+ u +"' and password='"+ p +"'";statement = conn.createStatement(); result1 = statement.executeQuery(sql1); //PrepareStatement用法sql2 ="select * from tbl_user where username=? and password=?"; prepareStatement = conn.prepareStatement(sql2); pstmt.setString(1, u); pstmt.setString(2, p); result2 = prepareStatement.executeQuery();
比較點StatementPreparedStatement用途執行靜態SQL語句并返回結果執行已預編譯SQL語句并返回結果可讀性低(字符串拼接)高(Set方法設值)效率低(字符串拼接)高(占位符)安全性低(SQL注入)高
消息隊列
消息隊列中間件是分布式系統中重要的組件,主要主要解決應用耦合、異步消息、流量削鋒等問題,具有異步性、可靠性(存儲到本地硬盤)、松耦合、分布式的特性。
主要特點是異步處理
主要目的是減少請求響應時間、解耦
主要使用場景是將比較耗時且不需同步返回結果的操作當做消息存入隊列
流量削峰的一種解決方案
MQ推送模式改為定時或者批量拉取模式
消息接收方實現批量處理等方式
RabbitMQ
RabbitMQ 是一個由 ErLang 開發的AMQP的開源實現。
交換機(Exchange)的功能主要是接收消息并且轉發到綁定的隊列,交換機不存儲消息,交換機本質是一張路由查詢表。
Direct:綁定時設定一個路由鍵,消息的路由鍵匹配才會被投送到隊列中。
Topic:根據模糊匹配轉發消息(最靈活)。
Headers:設置頭部參數類型的交換機。
Fanout:轉發消息到所有綁定隊列,消息廣播的模式。
路由鍵(routing_key)在消息中,而綁定鍵(binding_key)作用于交換機和隊列之間。當消息中的路由鍵和綁定鍵對應上的時候,交換機就知道將該消息存入哪個隊列。
分布式
分布式:一個業務分拆多個子業務,部署在不同的服務器上(廚師和配菜師的關系)
集群:同一個業務,部署在多個服務器上(兩個廚師的關系)
微服務
微服務架構風格是一種使用一套小服務來開發單個應用的方式,每個服務運行在自己的進程中,并使用輕量級機制通信(通常是HTTP API),這些服務能夠通過自動化部署機制來獨立部署、可以使用不同的編程語言實現、可以使用不同的數據存儲技術,并保持最低限度的集中式管理。
時下熱門的微服務開發框架有:Spring Cloud、Dubbo
RESTful
URL定位資源,HTTP動詞描述操作
GET:讀取資源
POST:創建資源
PUT:更新資源
DELETE:刪除資源
使用PUT方式更新時,必須發送資源所有的屬性
Nginx
反向代理
正向代理:隱藏真實的請求客戶端,服務端不知道真實的客戶端是誰,正向代理服務器會代替客戶端向服務器發送請求。正向代理代理的對象是客戶端。
反向代理:隱藏真實的響應服務端,客戶端不知道真實的服務端是誰,反向代理服務器會把請求轉發到真實的服務器。反向代理代理的對象是服務端。
10086總機就是一種反向代理,客戶不知道真正提供服務人的是誰。
負載均衡
四層負載均衡:工作在OSI模型的傳輸層,它在接收到客戶端的流量以后通過修改數據包的地址信息將流量轉發到應用服務器,因此四層負載均衡的主要工作就是轉發。
七層負載均衡:工作在OSI模型的應用層,七層負載均衡在接到客戶端的流量以后,還需要一個完整的TCP/IP協議棧與客戶端建立一條完整的連接,并將應用層的請求流量解析出來,再按照調度算法選擇一個應用服務器,并與應用服務器建立另外一條連接將請求發送過去,因此七層負載均衡的主要工作就是代理。
設計模式
設計模式的六大原則
單一職責原則:一個類只負責一個功能領域中的相應職責。
開閉原則:一個軟件實體應當對擴展開放,對修改關閉。
里氏替換原則:所有引用父類的地方必須能透明地使用其子類的對象。
依賴倒置原則:抽象不應該依賴于細節,細節應當依賴于抽象。(要針對接口編程,而不是針對實現編程)。
接口隔離原則:使用多個專門的接口,而不使用單一的總接口。
迪米特法則:一個軟件實體應當盡可能少地與其他實體發生相互作用。
單例、工廠、觀察者、適配器、責任鏈
單例模式:一個類負責創建自己的對象,同時確保只有單個對象被創建,并提供一種訪問其唯一對象的方式。
工廠模式:在創建對象時不暴露創建邏輯,并通過使用一個共同的接口來指向新創建的對象。
觀察者模式:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。
適配器模式:負責加入獨立的或不兼容的接口功能的類,使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
責任鏈模式:為請求創建了一個接收者對象的鏈,沿著這條鏈傳遞請求,直到有對象處理它為止,對請求的發送者和接收者進行解耦。
寫出生產者消費者模式
生產者生產數據到緩沖區中,消費者從緩沖區中取數據。如果緩沖區已經滿了,則生產者線程阻塞;如果緩沖區為空,那么消費者線程阻塞。
publicclassProducerAndConsumer{ staticBlockingQueueresourceQueue =newLinkedBlockingQueue(10); public static void main(String[] args) {Producerp =newProducer();//生產者Consumerc1 =newConsumer();//消費者1Consumerc2 =newConsumer();//消費者2Consumerc3 =newConsumer();//消費者3p.start(); c1.start(); c2.start(); c3.start(); }}/**
- 資源
/classResource{ int id; publicResource(int id) {this.id = id; }}/*
- 生產者
/classProducerextendsThread{ int p =1;@Overridepublic void run() {while(true) {try{Resourceresource =newResource(p++);System.out.println("生產資源"+ resource.id);ProducerAndConsumer.resourceQueue.put(resource); }catch(InterruptedExceptione) { e.printStackTrace(); } } }}/*
- 消費者
*/classConsumerextendsThread{@Overridepublic void run() {while(true) {try{System.out.println("消費資源"+ ((Resource)ProducerAndConsumer.resourceQueue.take()).id); }catch(InterruptedExceptione) { e.printStackTrace(); } } }}
高內聚、低耦合
耦合性:也稱塊間聯系。指軟件各模塊之間相互聯系緊密程度的一種度量。模塊之間聯系越緊密,則其耦合性就越強。模塊間耦合高低取決于模塊間接口的復雜性、調用的方式及傳遞的信息。
內聚性:也稱塊內聯系。指軟件模塊內部各元素彼此結合緊密程度的一種度量。模塊內各元素(語名之間、程序段之間)聯系越緊密,則其內聚性就越高。
高內聚、低耦合的系統具有更好的重用性,維護性,擴展性,可以更高效的完成系統的維護開發,持續的支持業務的發展,而不會成為業務發展的障礙