mysql教程欄目為大家介紹spring必須掌握的內(nèi)容。

大家好!我是熱心的朝陽(yáng)群眾。
Spring框架在面試中是一個(gè)必問點(diǎn),里面究竟有哪些內(nèi)容呢?讓我們一起來看看。這也是我在面試中經(jīng)常會(huì)問到的問題,也是體現(xiàn)一個(gè)程序員對(duì)框架理解的能力。
介紹一下Spring框架
Spring是一種輕量級(jí)框架,旨在提高開發(fā)人員的開發(fā)效率以及系統(tǒng)的可維護(hù)性。
我們一般說的Spring框架就是Spring Framework,它是很多模塊的集合,使用這些模塊可以很方便地協(xié)助我們進(jìn)行開發(fā)。這些模塊是核心容器、數(shù)據(jù)訪問/集成、Web、AOP(面向切面編程)、工具、消息和測(cè)試模塊。比如Core Container中的Core組件是Spring所有組件的核心,Beans組件和Context組件是實(shí)現(xiàn)IOC和DI的基礎(chǔ),AOP組件用來實(shí)現(xiàn)面向切面編程。
Spring的6個(gè)特征:
-
核心技術(shù):依賴注入(DI),AOP,事件(Events),資源,i18n,驗(yàn)證,數(shù)據(jù)綁定,類型轉(zhuǎn)換,SpEL; -
測(cè)試:模擬對(duì)象,TestContext框架,Spring mvc測(cè)試,WebTestClient; -
數(shù)據(jù)訪問:事務(wù),DAO支持,JDBC,ORM,編組xml; -
Web支持:Spring MVC和Spring WebFlux Web框架; -
集成:遠(yuǎn)程處理,JMS,JCA,JMX,電子郵件,任務(wù),調(diào)度,緩存; -
語(yǔ)言:kotlin,Groovy,動(dòng)態(tài)語(yǔ)言;
列舉一些重要的Spring模塊
下圖對(duì)應(yīng)的是Spring 4.x的版本,目前最新的5.x版本中Web模塊的Portlet組件已經(jīng)被廢棄掉,同時(shí)增加了用于異步響應(yīng)式處理的WebFlux組件。

-
Spring Core:基礎(chǔ),可以說Spring其他所有的功能都依賴于該類庫(kù)。主要提供IOC和DI功能。 -
Spring Aspects:該模塊為與AspectJ的集成提供支持。 -
Spring AOP:提供面向方面的編程實(shí)現(xiàn)。 -
Spring JDBC:Java數(shù)據(jù)庫(kù)連接。 -
Spring JMS:Java消息服務(wù)。 -
Spring ORM:用于支持hibernate等ORM工具。 -
Spring Web:為創(chuàng)建Web應(yīng)用程序提供支持。 -
Spring Test:提供了對(duì)junit和TestNG測(cè)試的支持。
談?wù)勛约簩?duì)于Spring IOC和AOP的理解
IOC
IOC(Inversion Of Controll,控制反轉(zhuǎn))是一種設(shè)計(jì)思想,就是將原本在程序中手動(dòng)創(chuàng)建對(duì)象的控制權(quán),交由給Spring框架來管理。IOC在其他語(yǔ)言中也有應(yīng)用,并非Spring特有。IOC容器是Spring用來實(shí)現(xiàn)IOC的載體,IOC容器實(shí)際上就是一個(gè)map(key, value),Map中存放的是各種對(duì)象。
將對(duì)象之間的相互依賴關(guān)系交給IOC容器來管理,并由IOC容器完成對(duì)象的注入。這樣可以很大程度上簡(jiǎn)化應(yīng)用的開發(fā),把應(yīng)用從復(fù)雜的依賴關(guān)系中解放出來。IOC容器就像是一個(gè)工廠一樣,當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)對(duì)象的時(shí)候,只需要配置好配置文件/注解即可,完全不用考慮對(duì)象是如何被創(chuàng)建出來的。在實(shí)際項(xiàng)目中一個(gè)Service類可能由幾百甚至上千個(gè)類作為它的底層,假如我們需要實(shí)例化這個(gè)Service,可能要每次都搞清楚這個(gè)Service所有底層類的構(gòu)造函數(shù),這可能會(huì)把人逼瘋。如果利用IOC的話,你只需要配置好,然后在需要的地方引用就行了,大大增加了項(xiàng)目的可維護(hù)性且降低了開發(fā)難度。
Spring時(shí)代我們一般通過XML文件來配置Bean,后來開發(fā)人員覺得用XML文件來配置不太好,于是Sprng Boot注解配置就慢慢開始流行起來。
AOP
AOP(Aspect-Oriented Programming,面向切面編程)能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任(例如事務(wù)處理、日志管理、權(quán)限控制等)封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可擴(kuò)展性和可維護(hù)性。
Spring AOP是基于動(dòng)態(tài)代理的,如果要代理的對(duì)象實(shí)現(xiàn)了某個(gè)接口,那么Spring AOP就會(huì)使用JDK動(dòng)態(tài)代理去創(chuàng)建代理對(duì)象;而對(duì)于沒有實(shí)現(xiàn)接口的對(duì)象,就無法使用JDK動(dòng)態(tài)代理,轉(zhuǎn)而使用CGlib動(dòng)態(tài)代理生成一個(gè)被代理對(duì)象的子類來作為代理。

當(dāng)然也可以使用AspectJ,Spring AOP中已經(jīng)集成了AspectJ,AspectJ應(yīng)該算得上是Java生態(tài)系統(tǒng)中最完整的AOP框架了。使用AOP之后我們可以把一些通用功能抽象出來,在需要用到的地方直接使用即可,這樣可以大大簡(jiǎn)化代碼量。我們需要增加新功能也方便,提高了系統(tǒng)的擴(kuò)展性。日志功能、事務(wù)管理和權(quán)限管理等場(chǎng)景都用到了AOP。
Spring AOP和AspectJ AOP的區(qū)別
Spring AOP是屬于運(yùn)行時(shí)增強(qiáng),而AspectJ是編譯時(shí)增強(qiáng)。Spring AOP基于代理(Proxying),而AspectJ基于字節(jié)碼操作(Bytecode Manipulation)。
Spring AOP已經(jīng)集成了AspectJ,AspectJ應(yīng)該算得上是Java生態(tài)系統(tǒng)中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加強(qiáng)大,但是Spring AOP相對(duì)來說更簡(jiǎn)單。
如果我們的切面比較少,那么兩者性能差異不大。但是,當(dāng)切面太多的話,最好選擇AspectJ,它比SpringAOP快很多。
Spring中的bean的作用域有哪些?
-
singleton:唯一bean實(shí)例,Spring中的bean默認(rèn)都是單例的。 -
prototype:每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。 -
request:每一次http請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,該bean僅在當(dāng)前HTTP request內(nèi)有效。 -
Session:每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean,該bean僅在當(dāng)前HTTP session內(nèi)有效。 -
global-session:全局session作用域,僅僅在基于Portlet的Web應(yīng)用中才有意義,Spring5中已經(jīng)沒有了。Portlet是能夠生成語(yǔ)義代碼(例如html)片段的小型Java Web插件。它們基于Portlet容器,可以像servlet一樣處理HTTP請(qǐng)求。但是與Servlet不同,每個(gè)Portlet都有不同的會(huì)話。
Spring中的單例bean的線程安全問題了解嗎?
大部分時(shí)候我們并沒有在系統(tǒng)中使用多線程,所以很少有人會(huì)關(guān)注這個(gè)問題。單例bean存在線程問題,主要是因?yàn)楫?dāng)多個(gè)線程操作同一個(gè)對(duì)象的時(shí)候,對(duì)這個(gè)對(duì)象的非靜態(tài)成員變量的寫操作會(huì)存在線程安全問題。
有兩種常見的解決方案:
-
在bean對(duì)象中盡量避免定義可變的成員變量(不太現(xiàn)實(shí))。 -
在類中定義一個(gè)ThreadLocal成員變量,將需要的可變成員變量保存在ThreadLocal中(推薦的一種方式)。
Spring中的bean生命周期?
-
Bean容器找到配置文件中Spring Bean的定義。 -
Bean容器利用Java Reflection API創(chuàng)建一個(gè)Bean的實(shí)例。 -
如果涉及到一些屬性值,利用set()方法設(shè)置一些屬性值。 -
如果Bean實(shí)現(xiàn)了BeanNameAware接口,調(diào)用setBeanName()方法,傳入Bean的名字。 -
如果Bean實(shí)現(xiàn)了BeanClassLoaderAware接口,調(diào)用setBeanClassLoader()方法,傳入ClassLoader對(duì)象的實(shí)例。 -
如果Bean實(shí)現(xiàn)了BeanFactoryAware接口,調(diào)用setBeanClassFacotory()方法,傳入ClassLoader對(duì)象的實(shí)例。 -
與上面的類似,如果實(shí)現(xiàn)了其他*Aware接口,就調(diào)用相應(yīng)的方法。 -
如果有和加載這個(gè)Bean的Spring容器相關(guān)的BeanPostProcessor對(duì)象,執(zhí)行postProcessBeforeInitialization()方法。 -
如果Bean實(shí)現(xiàn)了InitializingBean接口,執(zhí)行afeterPropertiesSet()方法。 -
如果Bean在配置文件中的定義包含init-method屬性,執(zhí)行指定的方法。 -
如果有和加載這個(gè)Bean的Spring容器相關(guān)的BeanPostProcess對(duì)象,執(zhí)行postProcessAfterInitialization()方法。 -
當(dāng)要銷毀Bean的時(shí)候,如果Bean實(shí)現(xiàn)了DisposableBean接口,執(zhí)行destroy()方法。 -
當(dāng)要銷毀Bean的時(shí)候,如果Bean在配置文件中的定義包含destroy-method屬性,執(zhí)行指定的方法。

說說自己對(duì)于Spring MVC的了解?
談到這個(gè)問題,我們不得不提提之前Model1和Model2這兩個(gè)沒有Spring MVC的時(shí)代。
**Model1時(shí)代:**很多學(xué)Java比較晚的后端程序員可能并沒有接觸過Model1模式下的JavaWeb應(yīng)用開發(fā)。在Model1模式下,整個(gè)Web應(yīng)用幾乎全部用JSP頁(yè)面組成,只用少量的JavaBean來處理數(shù)據(jù)庫(kù)連接,訪問等操作。這個(gè)模式下JSP即是控制層又是表現(xiàn)層。顯而易見,這種模式存在很多問題。比如將控制邏輯和表現(xiàn)邏輯混雜在一起,導(dǎo)致代碼重用率極低;又比如前端和后端相互依賴,難以進(jìn)行測(cè)試并且開發(fā)效率極低。
Model2時(shí)代:學(xué)過Servlet并做過相關(guān)Demo的朋友應(yīng)該了解Java Bean(Model)+JSP(View)+Servlet(Controller)這種開發(fā)模式,這就是早期的Java Web MVC開發(fā)模式。Model是系統(tǒng)中涉及的數(shù)據(jù),也就是dao和bean;View是用來展示模型中的數(shù)據(jù),只是用來展示;Controller是將用戶請(qǐng)求都發(fā)送給Servlet做處理,返回?cái)?shù)據(jù)給JSP并展示給用戶。
Model2模式下還存在很多問題,Model2的抽象和封裝程度還遠(yuǎn)遠(yuǎn)不夠,使用Model2進(jìn)行開發(fā)時(shí)不可避免地會(huì)重復(fù)造輪子,這就大大降低了程序的可維護(hù)性和可復(fù)用性。于是很多Java Web開發(fā)相關(guān)的mvc框架應(yīng)運(yùn)而生,比如Struts2,但是由于Struts2比較笨重,隨著Spring輕量級(jí)開發(fā)框架的流行,Spring生態(tài)圈出現(xiàn)了Spring MVC框架。Spring MVC是當(dāng)前最優(yōu)秀的MVC框架,相比于Struts2,Spring MVC使用更加簡(jiǎn)單和方便,開發(fā)效率更高,并且Spring MVC運(yùn)行速度更快。
MVC是一種設(shè)計(jì)模式,Spring MVC是一款很優(yōu)秀的MVC框架。Spring MVC可以幫助我們進(jìn)行更簡(jiǎn)潔的Web層的開發(fā),并且它天生與Spring框架集成。Spring MVC下我們一般把后端項(xiàng)目分為Service層(處理業(yè)務(wù))、Dao層(數(shù)據(jù)庫(kù)操作)、Entity層(實(shí)體類)、Controller層(控制層,返回?cái)?shù)據(jù)給前臺(tái)頁(yè)面)。
Spring MVC的簡(jiǎn)單原理圖如下:
談?wù)凷pring MVC的工作原理
流程說明:
1.客戶端(瀏覽器)發(fā)送請(qǐng)求,直接請(qǐng)求到DispatcherServlet。
2.DispatcherServlet根據(jù)請(qǐng)求信息調(diào)用HandlerMapping,解析請(qǐng)求對(duì)應(yīng)的Handler。
3.解析到對(duì)應(yīng)的Handler(也就是我們平常說的Controller控制器)。
4.HandlerAdapter會(huì)根據(jù)Handler來調(diào)用真正的處理器來處理請(qǐng)求和執(zhí)行相對(duì)應(yīng)的業(yè)務(wù)邏輯。
5.處理器處理完業(yè)務(wù)后,會(huì)返回一個(gè)ModelAndView對(duì)象,Model是返回的數(shù)據(jù)對(duì)象,View是邏輯上的View。
6.ViewResolver會(huì)根據(jù)邏輯View去查找實(shí)際的View。
7.DispatcherServlet把返回的Model傳給View(視圖渲染)。
8.把View返回給請(qǐng)求者(瀏覽器)。
##Spring框架中用到了哪些設(shè)計(jì)模式?
-
工廠設(shè)計(jì)模式:Spring使用工廠模式通過BeanFactory和ApplicationContext創(chuàng)建bean對(duì)象。 -
代理設(shè)計(jì)模式:Spring AOP功能的實(shí)現(xiàn)。 -
單例設(shè)計(jì)模式:Spring中的bean默認(rèn)都是單例的。 -
模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template結(jié)尾的對(duì)數(shù)據(jù)庫(kù)操作的類,它們就使用到了模板模式。 -
包裝器設(shè)計(jì)模式:我們的項(xiàng)目需要連接多個(gè)數(shù)據(jù)庫(kù),而且不同的客戶在每次訪問中根據(jù)需要會(huì)去訪問不同的數(shù)據(jù)庫(kù)。這種模式讓我們可以根據(jù)客戶的需求能夠動(dòng)態(tài)切換不同的數(shù)據(jù)源。 -
觀察者模式:Spring事件驅(qū)動(dòng)模型就是觀察者模式很經(jīng)典的一個(gè)應(yīng)用。 -
適配器模式:Spring AOP的增強(qiáng)或通知(Advice)使用到了適配器模式、Spring MVC中也是用到了適配器模式適配Controller。
@Component和@Bean的區(qū)別是什么?
-
作用對(duì)象不同。@Component注解作用于類,而@Bean注解作用于方法。 -
@Component注解通常是通過類路徑掃描來自動(dòng)偵測(cè)以及自動(dòng)裝配到Spring容器中(我們可以使用@ComponentScan注解定義要掃描的路徑)。@Bean注解通常是在標(biāo)有該注解的方法中定義產(chǎn)生這個(gè)bean,告訴Spring這是某個(gè)類的實(shí)例,當(dāng)我需要用它的時(shí)候還給我。 -
@Bean注解比@Component注解的自定義性更強(qiáng),而且很多地方只能通過@Bean注解來注冊(cè)bean。比如當(dāng)引用第三方庫(kù)的類需要裝配到Spring容器的時(shí)候,就只能通過@Bean注解來實(shí)現(xiàn)。
@Bean注解的使用示例:
@Configurationpublic?class?AppConfig?{????@Bean????public?TransferService?transferService()?{????????return?new?TransferServiceImpl();????}}復(fù)制代碼
上面的代碼相當(dāng)于下面的XML配置:
<beans>????<bean></bean></beans>復(fù)制代碼
下面這個(gè)例子是無法通過@Component注解實(shí)現(xiàn)的:
@Beanpublic?OneService?getService(status)?{????case?(status)??{????????when?1:????????????????return?new?serviceImpl1();????????when?2:????????????????return?new?serviceImpl2();????????when?3:????????????????return?new?serviceImpl3();????}}復(fù)制代碼
將一個(gè)類聲明為Spring的bean的注解有哪些?
我們一般使用@Autowired注解去自動(dòng)裝配bean。而想要把一個(gè)類標(biāo)識(shí)為可以用@Autowired注解自動(dòng)裝配的bean,可以采用以下的注解實(shí)現(xiàn):
-
@Component注解。通用的注解,可標(biāo)注任意類為Spring組件。如果一個(gè)Bean不知道屬于哪一個(gè)層,可以使用@Component注解標(biāo)注。 -
@Repository注解。對(duì)應(yīng)持久層,即Dao層,主要用于數(shù)據(jù)庫(kù)相關(guān)操作。 -
@Service注解。對(duì)應(yīng)服務(wù)層,即Service層,主要涉及一些復(fù)雜的邏輯,需要用到Dao層(注入)。 -
@Controller注解。對(duì)應(yīng)Spring MVC的控制層,即Controller層,主要用于接受用戶請(qǐng)求并調(diào)用Service層的方法返回?cái)?shù)據(jù)給前端頁(yè)面。
Spring事務(wù)管理的方式有幾種?
-
編程式事務(wù):在代碼中硬編碼(不推薦使用)。 -
聲明式事務(wù):在配置文件中配置(推薦使用),分為基于XML的聲明式事務(wù)和基于注解的聲明式事務(wù)。
Spring事務(wù)中的隔離級(jí)別有哪幾種?
在TransactionDefinition接口中定義了五個(gè)表示隔離級(jí)別的常量:
**ISOLATION_DEFAULT:**使用后端數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別,Mysql默認(rèn)采用的REPEATABLE_READ隔離級(jí)別;oracle默認(rèn)采用的READ_COMMITTED隔離級(jí)別。
**ISOLATION_READ_UNCOMMITTED:**最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀。
**ISOLATION_READ_COMMITTED:**允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生
**ISOLATION_REPEATABLE_READ:**對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生。
**ISOLATION_SERIALIZABLE:**最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。但是這將嚴(yán)重影響程序的性能。通常情況下也不會(huì)用到該級(jí)別。
Spring事務(wù)中有哪幾種事務(wù)傳播行為?
在TransactionDefinition接口中定義了八個(gè)表示事務(wù)傳播行為的常量。
支持當(dāng)前事務(wù)的情況:
**PROPAGATION_REQUIRED:**如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。
PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。(mandatory:強(qiáng)制性)。
不支持當(dāng)前事務(wù)的情況:
PROPAGATION_REQUIRES_NEW: 創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
PROPAGATION_NEVER: 以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。
###其他情況:
PROPAGATION_NESTED: 如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運(yùn)行;如果當(dāng)前沒有事務(wù),則該取值等價(jià)于PROPAGATION_REQUIRED。
結(jié)束
希望大家能掌握這些內(nèi)容,也能夠繼續(xù)支持我,感謝。
更多相關(guān)免費(fèi)學(xué)習(xí)推薦:mysql教程(視頻)