如何實作一個IOC容器
1、組態檔配置包掃描路徑
2、遞回包掃描獲取.class檔案
3、反射、確定需要交給IOC管理的類
4、對需要注入的類進行依賴注入
組態檔中指定需要掃描的包路徑
定義一些注解,分別表示訪問控制層、業務服務層、資料持久層、依賴注入注解、獲取組態檔注 解
從組態檔中獲取需要掃描的包路徑,獲取到當前路徑下的檔案資訊及檔案夾資訊,我們將當前路 徑下所有以.class結尾的檔案添加到一個Set集合中進行存盤
遍歷這個set集合,獲取在類上有指定注解的類,并將其交給IOC容器,定義一個安全的Map用來存盤這些物件
遍歷這個IOC容器,獲取到每一個類的實體,判斷里面是有有依賴其他的類的實體,然后進行遞回注入
spring是什么?
輕量級的開源的J2EE框架,它是一個容器框架,用來裝javabean(java物件),中間層框架(萬能膠) 可以起一個連接作用,比如說把Struts和hibernate粘合在一起運用,可以讓我們的企業開發更快、更簡潔
Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器框架
--從大小與開銷兩方面而言Spring都是輕量級的,
--通過控制反轉(IoC)的技術達到松耦合的目的
--提供了面向切面編程的豐富支持,允許通過分離應用的業務邏輯與系統級服務進行內聚性的開發
--包含并管理應用物件(Bean)的配置和生命周期,這個意義上是一個容器,
--將簡單的組件配置、組合成為復雜的應用,這個意義上是一個框架,
談談你對AOP的理解
系統是由許多不同的組件所組成的,每一個組件各負責一塊特定功能,除了實作自身核心功能之外,這 些組件還經常承擔著額外的職責,例如日志、事務管理和安全這樣的核心服務經常融入到自身具有核心 業務邏輯的組件中去,這些系統服務經常被稱為橫切關注點,因為它們會跨越系統的多個組件,
當我們需要為分散的物件引入公共行為的時候,OOP則顯得無能為力,也就是說,OOP允許你定義從上到下的關系,但并不適合定義從左到右的關系,例如日志功能,
日志代碼往往水平地散布在所有物件層次中,而與它所散布到的物件的核心功能毫無關系, 在OOP設計中,它導致了大量代碼的重復,而不利于各個模塊的重用,
AOP:將程式中的交叉業務邏輯(比如安全,日志,事務等),封裝成一個切面,然后注入到目標物件
(具體業務邏輯)中去,AOP可以對某個物件或某些物件的功能進行增強,比如物件中的方法進行增強,可以在執行某個方法之前額外的做一些事情,在某個方法執行之后額外的做一些事情
談談你對IOC的理解
容器概念、控制反轉、依賴注入
ioc容器:實際上就是個map(key,value),里面存的是各種物件(在xml里配置的bean節點、
@repository、@service、@controller、@component),在專案啟動的時候會讀取組態檔里面的bean節點,根據全限定類名使用反射創建物件放到map里、掃描到打上上述注解的類還是通過反射創建物件放到map里,
這個時候map里就有各種物件了,接下來我們在代碼里需要用到里面的物件時,再通過DI注入(autowired、resource等注解,xml里bean節點內的ref屬性,專案啟動的時候會讀取xml節點ref屬性根據id注入,也會掃描這些注解,根據型別或id注入;id就是物件名),
控制反轉:
沒有引入IOC容器之前,物件A依賴于物件B,那么物件A在初始化或者運行到某一點的時候,自己必須主動去創建物件B或者使用已經創建的物件B,無論是創建還是使用物件B,控制權都在自己手上,
引入IOC容器之后,物件A與物件B之間失去了直接聯系,當物件A運行到需要物件B的時候,IOC容器會主動創建一個物件B注入到物件A需要的地方,
通過前后的對比,不難看出來:物件A獲得依賴物件B的程序,由主動行為變為了被動行為,控制權顛倒過來了,這就是“控制反轉”這個名稱的由來,
全部物件的控制權全部上繳給“第三方”IOC容器,所以,IOC容器成了整個系統的關鍵核心,它起到了一種類似“粘合劑”的作用,把系統中的所有物件粘合在一起發揮作用,如果沒有這個“粘合劑”,物件與對 象之間會彼此失去聯系,這就是有人把IOC容器比喻成“粘合劑”的由來,
依賴注入:
“獲得依賴物件的程序被反轉了”,控制被反轉之后,獲得依賴物件的程序由自身管理變為了由IOC容器主動注入,依賴注入是實作IOC的方法,就是由IOC容器在運行期間,動態地將某種依賴關系注入到物件之中,
BeanFactory和ApplicationContext有什么區別?
ApplicationContext是BeanFactory的子介面
ApplicationContext提供了更完整的功能:
①繼承MessageSource,因此支持國際化,
②統一的資源檔案訪問方式,
③提供在監聽器中注冊bean的事件,
④同時加載多個組態檔,
⑤載入多個(有繼承關系)背景關系 ,使得每一個背景關系都專注于一個特定的層次,比如應用的web層,
BeanFactroy采用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(呼叫getBean()),才對該Bean進行加載實體化,這樣,我們就不能發現一些存在的Spring的配置問 題,如果Bean的某一個屬性沒有注入,BeanFacotry加載后,直至第一次使用呼叫getBean方法 才會拋出例外,
ApplicationContext,它是在容器啟動時,一次性創建了所有的Bean,這樣,在容器啟動時,我 們就可以發現Spring中存在的配置錯誤,這樣有利于檢查所依賴屬性是否注入,
ApplicationContext啟動后預載入所有的單實體Bean,通過預載入單實體bean ,確保當你需要的時候,你就不用等待,因為它們已經創建好了,
相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用記憶體空間,當應用程式配置
Bean較多時,程式啟動較慢,
BeanFactory通常以編程的方式被創建,ApplicationContext還能以宣告的方式創建,如使用ContextLoader,
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的 使用,但兩者之間的區別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊,
描述一下Spring Bean的生命周期?
1、決議類得到BeanDefinition
2、如果有多個構造方法,則要推斷構造方法
3、確定好構造方法后,進行實體化得到一個物件
4、對物件中的加了@Autowired注解的屬性進行屬性填充
5、回呼Aware方法,比如BeanNameAware,BeanFactoryAware
6、呼叫BeanPostProcessor的初始化前的方法
7、呼叫初始化方法
8、呼叫BeanPostProcessor的初始化后的方法,在這里會進行AOP
9、如果當前創建的bean是單例的則會把bean放入單例池
10、使用bean
11、Spring容器關閉時呼叫DisposableBean中destory()方法
解釋下Spring支持的幾種bean的作用域,
singleton:默認,每個容器中只有一個bean的實體,單例的模式由BeanFactory自身來維護,該 物件的生命周期是與Spring IOC容器一致的(但在第一次被注入時才會創建),
prototype:為每一個bean請求提供一個實體,在每次注入時都會創建一個新的物件
request:bean被定義為在每個HTTP請求中創建一個單例物件,也就是說在單個請求中都會復用 這一個單例物件,
session:與request范圍類似,確保每個session中有一個bean的實體,在session過期后,bean會隨之失效,
application:bean被定義為在ServletContext的生命周期中復用一個單例物件,
websocket:bean被定義為在websocket的生命周期中復用一個單例物件,
global-session:全域作用域,global-session和Portlet應用相關,
當你的應用部署在Portlet容器中作業時,它包含很多portlet,如果你想要宣告讓所有的portlet共用全域的存盤變數的話,那么這全域變數需要存盤在global-session中,全域作用域與Servlet中的session作用域效果相同,
Spring框架中的單例Bean是執行緒安全的么?
Spring中的Bean默認是單例模式的,框架并沒有對bean進行多執行緒的封裝處理,
如果Bean是有狀態的 那就需要開發人員自己來進行執行緒安全的保證,最簡單的辦法就是改變bean的作用域 把 "singleton"改為’‘protopyte’ 這樣每次請求Bean就相當于是 new Bean() 這樣就可以保證執行緒的安全了,
有狀態就是有資料存盤功能
無狀態就是不會保存資料 controller、service和dao層本身并不是執行緒安全的,只是如果只 是呼叫里面的方法,而且多執行緒呼叫一個實體的方***在記憶體中復制變數,這是自己的執行緒的工 作記憶體,是安全的,
Dao會操作資料庫Connection,Connection是帶有狀態的,比如說資料庫事務,Spring的事務管理器 使用Threadlocal為不同執行緒維護了一套獨立的connection副本,保證執行緒之間不會互相影響(Spring 是如何保證事務獲取同一個Connection的)
不要在bean中宣告任何有狀態的實體變數或類變數,如果必須如此,那么就使用ThreadLocal把變數變 為執行緒私有的,如果bean的實體變數或類變數需要在多個執行緒之間共享,那么就只能使用synchronized、lock、CAS等這些實作執行緒同步的方法了,
Spring 框架中都用到了哪些設計模式?
簡單工廠:
由一個工廠類根據傳入的引數,動態決定應該創建哪一個產品類,
Spring中的BeanFactory就是簡單工廠模式的體現,根據傳入一個唯一的標識來獲得Bean物件,但是否是 在傳入引數后創建還是傳入引數前創建這個要根據具體情況來定,
工廠方法:
實作了FactoryBean介面的bean是一類叫做factory的bean,其特點是,spring會在使用getBean()調 用獲得該bean時,會自動呼叫該bean的getObject()方法,所以回傳的不是factory這個bean,而是這個bean.getOjbect()方法的回傳值,
單例模式:
保證一個類僅有一個實體,并提供一個訪問它的全域訪問點
spring對單例的實作: spring中的單例模式完成了后半句話,即提供了全域的訪問點BeanFactory,但沒有從構造器級別去控制單例,這是因為spring管理的是任意的java物件,
配接器模式:
Spring定義了一個適配介面,使得每一種Controller有一種對應的配接器實作類,讓配接器代替
controller執行相應的方法,這樣在擴展Controller時,只需要增加一個配接器類就完成了SpringMVC的擴展了,
裝飾器模式:
動態地給一個物件添加一些額外的職責,就增加功能來說,Decorator模式相比生成子類更為靈活,
Spring中用到的包裝器模式在類名上有兩種表現:一種是類名中含有Wrapper,另一種是類名中含有Decorator,
動態代理:
切面在應用運行的時刻被織入,一般情況下,在織入切面時,AOP容器會為目標物件創建動態的創建一個代理 物件,SpringAOP就是以這種方式織入切面的,
織入:把切面應用到目標物件并創建新的代理物件的程序,
觀察者模式:
spring的事件驅動模型使用的是 觀察者模式 ,Spring中Observer模式常用的地方是listener的實作,
策略模式:
Spring框架的資源訪問Resource介面,該介面提供了更強的資源訪問能力,Spring 框架本身大量使用了
Resource 介面來訪問底層資源,
模板方法:父類定義了骨架(呼叫哪些方法及順序),某些特定方法由子類實作,
最大的好處:代碼復用,減少重復代碼,除了子類要實作的特定方法,其他方法及方法呼叫順序都在父類中預先寫好了,
refresh方法
Spring事務的實作方式和原理以及隔離級別?
在使用Spring框架時,可以有兩種使用事務的方式,一種是編程式的,一種是申明式的,
@Transactional注解就是申明式的,
首先,事務這個概念是資料庫層面的,Spring只是基于資料庫中的事務進行了擴展,以及提供了一些能讓程式員更加方便操作事務的方式,
比如我們可以通過在某個方法上增加@Transactional注解,就可以開啟事務,這個方法中所有的sql都 會在一個事務中執行,統一成功或失敗,
在一個方法上加了@Transactional注解后,Spring會基于這個類生成一個代理物件,會將這個代理物件 作為bean,當在使用這個代理物件的方法時,如果這個方法上存在@Transactional注解,那么代理邏輯會先把事務的自動提交設定為false,然后再去執行原本的業務邏輯方法,如果執行業務邏輯方法沒有出現例外,那么代理邏輯中就會將事務進行提交,如果執行業務邏輯方法出現了例外,那么則會將事務 進行回滾,
當然,針對哪些例外回滾事務是可以配置的,可以利用@Transactional注解中的rollbackFor屬性進行 配置,默認情況下會對RuntimeException和Error進行回滾,
spring事務隔離級別就是資料庫的隔離級別:外加一個默認級別read uncommitted(未提交讀)
read committed(提交讀、不可重復讀)
repeatable read(可重復讀) serializable(可串行化)
資料庫的配置隔離級別是Read Commited,而Spring配置的隔離級別是Repeatable Read,請問這時隔離級別是以哪一個為準?
以Spring配置的為準,如果spring設定的隔離級別資料庫不支持,效果取決于資料庫
spring事務傳播機制
多個事務方法相互呼叫時,事務如何在這些方法間傳播
方法A是一個事務的方法,方法A執行程序中呼叫了方法B,那么方法B有無事務以及方法B對事務的要求不同都 會對方法A的事務具體執行造成影響,同時方法A的事務對方法B的事務執行也有影響,這種影響具體是什么就 由兩個方法所定義的事務傳播型別所決定,
REQUIRED(Spring默認的事務傳播型別):如果當前沒有事務,則自己新建一個事務,如果當前存在事 務,則加入這個事務
SUPPORTS:當前存在事務,則加入當前事務,如果當前沒有事務,就以非事務方法執行MANDATORY:當前存在事務,則加入當前事務,如果當前事務不存在,則拋出例外,REQUIRES_NEW:創建一個新事務,如果存在當前事務,則掛起該事務,
NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則掛起當前事務NEVER:不使用事務,如果當前事務存在,則拋出例外
NESTED:如果當前事務存在,則在嵌套事務中執行,否則REQUIRED的操作一樣(開啟一個事務)
和REQUIRES_NEW的區別
REQUIRES_NEW是新建一個事務并且新開啟的這個事務與原有事務無關,而NESTED則是當前存在事務時(我 們把當前事務稱之為父事務)會開啟一個嵌套事務(稱之為一個子事務), 在NESTED情況下父事務回滾時, 子事務也會回滾,而在REQUIRES_NEW情況下,原有事務回滾,不會影響新開啟的事務,
和REQUIRED的區別
REQUIRED情況下,呼叫方存在事務時,則被呼叫方和呼叫方使用同一事務,那么被呼叫方出現例外時,由于 共用一個事務,所以無論呼叫方是否catch其例外,事務都會回滾 而在NESTED情況下,被呼叫方發生例外時,呼叫方可以catch其例外,這樣只有子事務回滾,父事務不受影響
spring事務什么時候會失效?
spring事務的原理是AOP,進行了切面增強,那么失效的根本原因是這個AOP不起作用了!常見情況有如下幾種
1、發生自呼叫,類里面使用this呼叫本類的方法(this通常省略),此時這個this物件不是代理類,而是UserService物件本身!
解決方法很簡單,讓那個this變成UserService的代理類即可!
2、方法不是public的
@Transactional 只能用于 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式,
3、資料庫不支持事務
4、沒有被spring管理
5、例外被吃掉,事務不會回滾(或者拋出的例外沒有被定義,默認為RuntimeException)
什么是bean的自動裝配,有哪些方式?
開啟自動裝配,只需要在xml組態檔中定義“autowire”屬性,
<bean id="cutomer" autowire="" />
autowire屬性有五種裝配的方式:
no – 預設情況下,自動配置是通過“ref”屬性手動設定 ,
手動裝配:以value或ref的方式明確指定屬性值都是手動裝配, 需要通過‘ref’屬性來連接bean,
byName-根據bean的屬性名稱進行自動裝配,
Cutomer的屬性名稱是person,Spring會將bean id為person的bean通過setter方法進行自動裝配,
<bean id="cutomer" autowire="byName"/>
<bean id="person" />
byType-根據bean的型別進行自動裝配,
Cutomer的屬性person的型別為Person,Spirng會將Person型別通過setter方法進行自動裝配,
<bean id="cutomer" autowire="byType"/>
<bean id="person" />
constructor-類似byType,不過是應用于構造器的引數,如果一個bean與構造器引數的型別形 同,則進行自動裝配,否則導致例外,
Cutomer建構式的引數person的型別為Person,Spirng會將Person型別通過構造方法進行自動裝 配,
<bean id="cutomer" autowire="construtor"/>
<bean id="person" />
autodetect-如果有默認的構造器,則通過constructor方式進行自動裝配,否則使用byType方式進行自動裝配,
如果有默認的構造器,則通過constructor方式進行自動裝配,否則使用byType方式進行自動裝配,
@Autowired自動裝配bean,可以在欄位、setter方法、建構式上使用,
Spring Boot、Spring MVC 和 Spring 有什么區別
spring是一個IOC容器,用來管理Bean,使用依賴注入實作控制反轉,可以很方便的整合各種框架,提供AOP機制彌補OOP的代碼重復問題、更方便將不同類不同方法中的共同處理抽取成切面、自動注入給方法執行,比如日志、例外等
springmvc是spring對web框架的一個解決方案,提供了一個總的前端控制器Servlet,用來接收請求, 然后定義了一套路由策略(url到handle的映射)及適配執行handle,將handle結果使用視圖決議技術 生成視圖展現給前端
springboot是spring提供的一個快速開發工具包,讓程式員能更方便、更快速的開發spring+springmvc應用,簡化了配置(約定了默認配置),整合了一系列的解決方案(starter機制)、redis、mongodb、es,可以開箱即用
SpringMVC 作業流程
用戶發送請求至前端控制器 DispatcherServlet,
DispatcherServlet 收到請求呼叫 HandlerMapping 處理器映射器,
處理器映射器找到具體的處理器(可以根據 xml 配置、注解進行查找),生成處理器及處理器攔截器
(如果有則生成)一并回傳給 DispatcherServlet,
DispatcherServlet 呼叫 HandlerAdapter 處理器配接器,
HandlerAdapter 經過適配呼叫具體的處理器(Controller,也叫后端控制器)
Controller 執行完成回傳 ModelAndView,
HandlerAdapter 將 controller 執行結果 ModelAndView 回傳給 DispatcherServlet,
DispatcherServlet 將 ModelAndView 傳給 ViewReslover 視圖決議器,
ViewReslover 決議后回傳具體 View,
DispatcherServlet 根據 View 進行渲染視圖(即將模型資料填充至視圖中),
DispatcherServlet 回應用戶,
Spring MVC的主要組件?
Handler:也就是處理器,它直接應對著MVC中的C也就是Controller層,它的具體表現形式有很多,可 以是類,也可以是方法,在Controller層中@RequestMapping標注的所有方法都可以看成是一個
Handler,只要可以實際處理請求就可以是Handler
1、HandlerMapping
initHandlerMappings(context),處理器映射器,根據用戶請求的資源uri來查找Handler的,在
SpringMVC中會有很多請求,每個請求都需要一個Handler處理,具體接收到一個請求之后使用哪個Handler進行,這就是HandlerMapping需要做的事,
2、HandlerAdapter
initHandlerAdapters(context),配接器,因為SpringMVC中的Handler可以是任意的形式,只要能處理請求就ok,但是Servlet需要的處理方法的結構卻是固定的,都是以request和response為引數的方 法,
如何讓固定的Servlet處理方法呼叫靈活的Handler來進行處理呢?這就是HandlerAdapter要做的事情,
Handler是用來干活的工具;HandlerMapping用于根據需要干的活找到相應的工具;HandlerAdapter是使用工具干活的人,
3、HandlerExceptionResolver
initHandlerExceptionResolvers(context), 其它組件都是用來干活的,在干活的程序中難免會出現問題,出問題后怎么辦呢?這就需要有一個專門的角色對例外情況進行處理,在SpringMVC中就是
HandlerExceptionResolver,具體來說,此組件的作用是根據例外設定ModelAndView,之后再交給render方法進行渲染,
4、ViewResolver
initViewResolvers(context),ViewResolver用來將String型別的視圖名和Locale決議為View型別的視 圖,View是用來渲染頁面的,也就是將程式回傳的引數填入模板里,生成html(也可能是其它型別) 檔案,這里就有兩個關鍵問題:使用哪個模板?用什么技術(規則)填入引數?這其實是ViewResolver 主要要做的作業,ViewResolver需要找到渲染所用的模板和所用的技術(也就是視圖的型別)進行渲染,具體的渲染程序則交由不同的視圖自己完成,
5、RequestToViewNameTranslator
initRequestToViewNameTranslator(context),ViewResolver是根據ViewName查找View,但有的Handler處理完后并沒有設定View也沒有設定ViewName,這時就需要從request獲取ViewName了, 如何從request中獲取ViewName就是RequestToViewNameTranslator要做的事情了,
RequestToViewNameTranslator在Spring MVC容器里只可以配置一個,所以所有request到
ViewName的轉換規則都要在一個Translator里面全部實作,
6、LocaleResolver
initLocaleResolver(context), 決議視圖需要兩個引數:一是視圖名,另一個是Locale,視圖名是處理器回傳的,Locale是從哪里來的?這就是LocaleResolver要做的事情,LocaleResolver用于從request 決議出Locale,Locale就是zh-cn之類,表示一個區域,有了這個就可以對不同區域的用戶顯示不同的 結果,SpringMVC主要有兩個地方用到了Locale:一是ViewResolver視圖決議的時候;二是用到國際化資源或者主題的時候,
7、ThemeResolver
initThemeResolver(context),用于決議主題,SpringMVC中一個主題對應一個properties檔案,里面 存放著跟當前主題相關的所有資源、如圖片、css樣式等,SpringMVC的主題也支持國際化,同一個主題不同區域也可以顯示不同的風格,SpringMVC中跟主題相關的類有 ThemeResolver、ThemeSource 和Theme,主題是通過一系列資源來具體體現的,要得到一個主題的資源,首先要得到資源的名稱,這是ThemeResolver的作業,然后通過主題名稱找到對應的主題(可以理解為一個配置)檔案,這是
ThemeSource的作業,最后從主題中獲取資源就可以了,
8、MultipartResolver
initMultipartResolver(context),用于處理上傳請求,處理方法是將普通的request包裝成MultipartHttpServletRequest,后者可以直接呼叫getFile方法獲取File,如果上傳多個檔案,還可以呼叫getFileMap得到FileName->File結構的Map,此組件中一共有三個方法,作用分別是判斷是不是上傳 請求,將request包裝成MultipartHttpServletRequest、處理完后清理上傳程序中產生的臨時資源,
9、FlashMapManager
initFlashMapManager(context),用來管理FlashMap的,FlashMap主要用在redirect中傳遞引數,
Spring Boot 自動配置原理?
@Import + @Configuration + Spring spi
自動配置類由各個starter提供,使用@Configuration + @Bean定義配置類,放到META-INF/spring.factories下
使用Spring spi掃描META-INF/spring.factories下的配置類使用@Import匯入自動配置類
如何理解 Spring Boot 中的 Starter
使用spring + springmvc使用,如果需要引入mybatis等框架,需要到xml中定義mybatis需要的bean
starter就是定義一個starter的jar包,寫一個@Configuration配置類、將這些bean定義在里面,然后在starter包的META-INF/spring.factories中寫入該配置類,springboot會按照約定來加載該配置類
開發人員只需要將相應的starter包依賴進應用,進行相應的屬性配置(使用默認配置時,不需要配置),就可以直接進行代碼開發,使用對應的功能了,比如mybatis-spring-boot--starter,spring- boot-starter-redis
什么是嵌入式服務器?為什么要使用嵌入式服務器?
節省了下載安裝tomcat,應用也不需要再打war包,然后放到webapp目錄下再運行 只需要一個安裝了 Java 的虛擬機,就可以直接在上面部署應用程式了springboot已經內置了tomcat.jar,運行main方法時會去啟動tomcat,并利用tomcat的spi機制加載springmvc
在黑夜里夢想著光,心中覆寫悲傷,在悲傷里忍受孤獨,空守一絲溫暖, 我的淚水是無底深海,對你的愛已無言,相信無盡的力量,那是真愛永在, 我的信仰是無底深海,澎湃著心中火焰,燃燒無盡的力量,那是忠誠永在轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/445914.html
標籤:其他
