節(jié)后面試必備:Spring 面試 63 問(wèn)

Sping原理
Spring是一個(gè)輕量級(jí)Java開(kāi)發(fā)框架,最早有Rod Johnson創(chuàng)建,目的是為了解決企業(yè)級(jí)應(yīng)用開(kāi)發(fā)的業(yè)務(wù)邏輯層和其他各層的耦合問(wèn)題。它是一個(gè)分層的JavaSE/JavaEE full-stack(一站式)輕量級(jí)開(kāi)源框架,為開(kāi)發(fā)Java應(yīng)用程序提供全面的基礎(chǔ)架構(gòu)支持。Spring負(fù)責(zé)基礎(chǔ)架構(gòu),因此Java開(kāi)發(fā)者可以專注于應(yīng)用程序的開(kāi)發(fā)。
Spring是一個(gè)全面的、企業(yè)應(yīng)用開(kāi)發(fā)一站式的解決方案,貫穿表現(xiàn)層、業(yè)務(wù)層、持久層。但是它仍然可以和其他的框架無(wú)縫整合。
Spring 特點(diǎn)
輕量級(jí): 組件大小與開(kāi)銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個(gè)大小只有1M多的JAR文件中發(fā)布,并且Spring所需的處理開(kāi)銷也是微不足道的。此外,Spring是非侵入式,典型案例,Spring應(yīng)用中的對(duì)象不依賴于Spring特定的類
控制反轉(zhuǎn): Spring通過(guò)控制反轉(zhuǎn)(IOC)技術(shù)實(shí)現(xiàn)解耦。一個(gè)對(duì)象依賴的其他對(duì)象會(huì)通過(guò)被動(dòng)的方式傳遞進(jìn)來(lái),而不需要對(duì)象自己創(chuàng)建或者查找依賴。
面向切面: 支持切面(AOP)編程,并且吧應(yīng)用業(yè)務(wù)邏輯和系統(tǒng)服務(wù)區(qū)分開(kāi)。
容器: Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器。可以配置每個(gè)bean如何被創(chuàng)建、銷毀,bean的作用范圍是單例還是每次都生成一個(gè)新的實(shí)例,以及他們是如何相互關(guān)聯(lián)。
框架集合: 將簡(jiǎn)單的組件配置,組合成為復(fù)雜的框架;應(yīng)用對(duì)象被申明式組合;提供許多基礎(chǔ)功能(事務(wù)管理、持久化框架繼承),提供應(yīng)用邏輯開(kāi)發(fā)接口
Spring 框架優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
方便解耦,簡(jiǎn)化開(kāi)發(fā):Spring就是一個(gè)大工廠,可以將所有對(duì)象的創(chuàng)建和依賴關(guān)系的維護(hù),交給Spring管理。 AOP編程的支持:Spring提供面向切面編程,可以方便的實(shí)現(xiàn)對(duì)程序進(jìn)行權(quán)限攔截、運(yùn)行監(jiān)控等功能。 聲明式事務(wù)的支持:只需要通過(guò)配置就可以完成對(duì)事務(wù)的管理,而無(wú)需手動(dòng)編程。 方便程序的測(cè)試:Spring對(duì)Junit4支持,可以通過(guò)注解方便的測(cè)試Spring程序。 方便集成各種優(yōu)秀框架:Spring不排斥各種優(yōu)秀的開(kāi)源框架,其內(nèi)部提供了對(duì)各種優(yōu)秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。 降低JavaEE API的使用難度:Spring對(duì)JavaEE開(kāi)發(fā)中非常難用的一些API(JDBC、JavaMail、遠(yuǎn)程調(diào)用等),都提供了封裝,使這些API應(yīng)用難度大大降低。
缺點(diǎn)
Spring依賴反射,反射影響性能 使用門檻升高,入門Spring需要較長(zhǎng)時(shí)間
Spring 框架中都用到了哪些設(shè)計(jì)模式
Spring 框架中使用到了大量的設(shè)計(jì)模式,下面列舉了比較有代表性的:
代理模式—在 AOP 和 remoting 中被用的比較多。單例模式—在 spring 配置文件中定義的 bean 默認(rèn)為單例模式。模板方法—用來(lái)解決代碼重復(fù)的問(wèn)題。比如. RestTemplate, JmsTemplate, JpaTempl ate。前端控制器—Spring 提供了 DispatcherServlet 來(lái)對(duì)請(qǐng)求進(jìn)行分發(fā)。視圖幫助(View Helper )—Spring 提供了一系列的 JSP 標(biāo)簽,高效宏來(lái)輔助將分散的代碼整合在視圖里。依賴注入—貫穿于 BeanFactory / ApplicationContext 接口的核心理念。工廠模式—BeanFactory 用來(lái)創(chuàng)建對(duì)象的實(shí)例
Spring核心組件
Spring 總共大約有 20 個(gè)模塊, 由 1300 多個(gè)不同的文件構(gòu)成。而這些組件被分別整合在核心容器(Core Container) 、 AOP(Aspect Oriented Programming)和設(shè)備支持(Instrmentation) 、數(shù)據(jù)訪問(wèn)與集成(Data Access/Integeration) 、 Web、 消息(Messaging) 、 Test等 6 個(gè)模塊中。以下是 Spring 5 的模塊結(jié)構(gòu)圖:

spring core:提供了框架的基本組成部分,包括控制反轉(zhuǎn)(Inversion of Control,IOC)和依賴注入(Dependency Injection,DI)功能。spring beans:提供了BeanFactory,是工廠模式的一個(gè)經(jīng)典實(shí)現(xiàn),Spring將管理對(duì)象稱為Bean。spring context:構(gòu)建于 core 封裝包基礎(chǔ)上的 context 封裝包,提供了一種框架式的對(duì)象訪問(wèn)方法。spring jdbc:提供了一個(gè)JDBC的抽象層,消除了煩瑣的JDBC編碼和數(shù)據(jù)庫(kù)廠商特有的錯(cuò)誤代碼解析, 用于簡(jiǎn)化JDBC。spring aop:提供了面向切面的編程實(shí)現(xiàn),讓你可以自定義攔截器、切點(diǎn)等。spring Web:提供了針對(duì) Web 開(kāi)發(fā)的集成特性,例如文件上傳,利用 servlet listeners 進(jìn)行 ioc 容器初始化和針對(duì) Web 的 ApplicationContext。spring test:主要為測(cè)試提供支持的,支持使用JUnit或TestNG對(duì)Spring組件進(jìn)行單元測(cè)試和集成測(cè)試。
Spring 控制反轉(zhuǎn)(IOC)
控制反轉(zhuǎn)(IOC)概念
控制反轉(zhuǎn)即IOC (Inversion of Control),它把傳統(tǒng)上由程序代碼直接操控的對(duì)象的調(diào)用權(quán)交給容器,通過(guò)容器來(lái)實(shí)現(xiàn)對(duì)象組件的裝配和管理。
Spring 通過(guò)一個(gè)配置文件描述 Bean 及 Bean 之間的依賴關(guān)系,利用 Java 語(yǔ)言的反射功能(依賴注入DI)實(shí)例化 Bean 并建立 Bean 之間的依賴關(guān)系。Spring 的 IoC 容器在完成這些底層工作的基礎(chǔ)上,還提供 了 Bean 實(shí)例緩存、生命周期管理、 Bean 實(shí)例代理、事件發(fā)布、資源裝載等高級(jí)服務(wù)。
Spring 容器高層視圖
Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相應(yīng)的 Bean 配
置注冊(cè)表,然后根據(jù)這張注冊(cè)表實(shí)例化 Bean,裝配好 Bean 之間的依賴關(guān)系,為上層應(yīng)用提供準(zhǔn)
備就緒的運(yùn)行環(huán)境。其中 Bean 緩存池為 HashMap 實(shí)現(xiàn)

IOC 容器實(shí)現(xiàn)
BeanFactory-框架基礎(chǔ)設(shè)施
BeanFactory 是 Spring 框架的基礎(chǔ)設(shè)施,面向 Spring 本身;
ApplicationContext 面向使用Spring 框架的開(kāi)發(fā)者,幾乎所有的應(yīng)用場(chǎng)合我們都直接使用 ApplicationContext 而非底層的 BeanFactory。

BeanDefinitionRegistry 注冊(cè)表:Spring 配置文件中每一個(gè)節(jié)點(diǎn)元素在 Spring 容器里都通過(guò)一個(gè) BeanDefinition 對(duì)象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注冊(cè)BeanDefinition 對(duì)象的方法。 BeanFactory 頂層接口:位于類結(jié)構(gòu)樹(shù)的頂端 ,它最主要的方法就是 getBean(String beanName),該方法從容器中返回特定名稱的 Bean,BeanFactory 的功能通過(guò)其他的接口得到不斷擴(kuò)展: ListableBeanFactory:該接口定義了訪問(wèn)容器中 Bean 基本信息的若干方法,如查看 Bean 的個(gè)數(shù)、獲取某一類型Bean 的配置名、查看容器中是否包括某一 Bean 等方法; HierarchicalBeanFactory 父子級(jí):父子級(jí)聯(lián) IoC 容器的接口,子容器可以通過(guò)接口方法訪問(wèn)父容器;通過(guò)HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子層級(jí)關(guān)聯(lián)的容器體系,子容器可以訪問(wèn)父容器中的 Bean,但父容器不能訪問(wèn)子容器的 Bean。Spring 使用父子容器實(shí)現(xiàn)了很多功能,比如在 Spring MVC 中,展現(xiàn)層 Bean 位于一個(gè)子容器中,而業(yè)務(wù)層和持久層的 Bean 位于父容器中。這樣,展現(xiàn)層 Bean 就可以引用業(yè)務(wù)層和持久層的 Bean,而業(yè)務(wù)層和持久層的 Bean 則看不到展現(xiàn)層的 Bean。 ConfigurableBeanFactory:是一個(gè)重要的接口,增強(qiáng)了 IoC 容器的可定制性,它定義了設(shè)置類裝載器、屬性編輯器、容器初始化后置處理器等方法; AutowireCapableBeanFactory 自動(dòng)裝配:定義了將容器中的 Bean 按某種規(guī)則(如按名字匹配、按類型匹配等)進(jìn)行自動(dòng)裝配的方法; SingletonBeanRegistry 運(yùn)行期間注冊(cè)單例 Bean:定義了允許在運(yùn)行期間向容器注冊(cè)單實(shí)例 Bean 的方法;對(duì)于單實(shí)例( singleton)的 Bean 來(lái)說(shuō),BeanFactory 會(huì)緩存 Bean 實(shí)例,所以第二次使用 getBean() 獲取 Bean 時(shí)將直接從IoC 容器的緩存中獲取 Bean 實(shí)例。Spring 在 DefaultSingletonBeanRegistry 類中提供了一個(gè)用于緩存單實(shí)例 Bean 的緩存器,它是一個(gè)用 HashMap 實(shí)現(xiàn)的緩存器,單實(shí)例的 Bean 以beanName 為鍵保存在這個(gè) HashMap 中。 依賴日志框架:在初始化 BeanFactory 時(shí),必須為其提供一種日志框架,比如使用 Log4J, 即在類路徑下提供 Log4J 配置文件,這樣啟動(dòng) Spring 容器才不會(huì)報(bào)錯(cuò)。
ApplicationContext 面向開(kāi)發(fā)應(yīng)用
ApplicationContext 由 BeanFactory 派生而來(lái),提供了更多面向?qū)嶋H應(yīng)用的功能。
ApplicationContext 繼承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基礎(chǔ)
上,還通過(guò)多個(gè)其他的接口擴(kuò)展了 BeanFactory 的功能:

ClassPathXmlApplicationContext:默認(rèn)從類路徑加載配置文件 FileSystemXmlApplicationContext:默認(rèn)從文件系統(tǒng)中裝載配置文件 ApplicationEventPublisher:讓容器擁有發(fā)布應(yīng)用上下文事件的功能,包括容器啟動(dòng)事件、關(guān)閉事件等。 MessageSource:為應(yīng)用提供 i18n 國(guó)際化消息訪問(wèn)的功能; ResourcePatternResolver :所有 ApplicationContext 實(shí)現(xiàn)類都實(shí)現(xiàn)了類似于 PathMatchingResourcePatternResolver:通過(guò)帶前綴的 Ant 風(fēng)格的資源文件路徑裝載 Spring 的配置文件。 LifeCycle:該接口是 Spring 2.0 加入的,該接口提供了 start()和 stop()兩個(gè)方法,主要用于控制異步處理過(guò)程。在具體使用時(shí),該接口同時(shí)被 ApplicationContext 實(shí)現(xiàn)及具體Bean 實(shí)現(xiàn), ApplicationContext 會(huì)將 start/stop 的信息傳遞給容器中所有實(shí)現(xiàn)了該接口的 Bean,以達(dá)到管理和控制 JMX、任務(wù)調(diào)度等目的。 ConfigurableApplicationContext :擴(kuò)展于 ApplicationContext,它新增加了兩個(gè)主要的方法:refresh()和 close(),讓 ApplicationContext 具有啟動(dòng)、刷新和關(guān)閉應(yīng)用上下文的能力。在應(yīng)用上下文關(guān)閉的情況下調(diào)用 refresh()即可啟動(dòng)應(yīng)用上下文,在已經(jīng)啟動(dòng)的狀態(tài)下,調(diào)用 refresh()則清除緩存并重新裝載配置信息,而調(diào)用 close()則可關(guān)閉應(yīng)用上下文。
BeanFactory 和 ApplicationContext有什么區(qū)別?
BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當(dāng)做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
依賴關(guān)系
BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實(shí)例化,控制bean的生命周期,維護(hù)bean之間的依賴關(guān)系。
ApplicationContext:接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
繼承MessageSource,因此支持國(guó)際化。 統(tǒng)一的資源文件訪問(wèn)方式。 提供在監(jiān)聽(tīng)器中注冊(cè)bean的事件。 同時(shí)加載多個(gè)配置文件。 載入多個(gè)(有繼承關(guān)系)上下文 ,使得每一個(gè)上下文都專注于一個(gè)特定的層次,比如應(yīng)用的web層。
加載方式
BeanFactroy:采用的是延遲加載形式來(lái)注入Bean的,即只有在使用到某個(gè)Bean時(shí)(調(diào)getBean()),才對(duì)該Bean進(jìn)行加載實(shí)例化。這樣,我們就不能發(fā)現(xiàn)一些存在的Spring的配置問(wèn)題。如果Bean的某一個(gè)屬性沒(méi)有注入,BeanFacotry加載后,直至第一次使用調(diào)用getBean方法才會(huì)拋出異常。
ApplicationContext:它是在容器啟動(dòng)時(shí),一次性創(chuàng)建了所有的Bean。這樣,在容器啟動(dòng)時(shí),我們就可以發(fā)現(xiàn)Spring中存在的配置錯(cuò)誤,這樣有利于檢查所依賴屬性是否注入。ApplicationContext啟動(dòng)后預(yù)載入所有的單實(shí)例Bean,通過(guò)預(yù)載入單實(shí)例bean ,確保當(dāng)你需要的時(shí)候,你就不用等待,因?yàn)樗鼈円呀?jīng)創(chuàng)建好了。
相對(duì)于基本的BeanFactory,ApplicationContext 唯一的不足是占用內(nèi)存空間。當(dāng)應(yīng)用程序配置Bean較多時(shí),程序啟動(dòng)較慢。
創(chuàng)建方式
BeanFactory通常以編程的方式被創(chuàng)建,ApplicationContext還能以聲明的方式創(chuàng)建,如使用ContextLoader。
注冊(cè)方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區(qū)別是:BeanFactory需要手動(dòng)注冊(cè),而ApplicationContext則是自動(dòng)注冊(cè)。
ApplicationContext通常的實(shí)現(xiàn)
FileSystemXmlApplicationContext :此容器從一個(gè)XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構(gòu)造函數(shù)。 ClassPathXmlApplicationContext:此容器也從一個(gè)XML文件中加載beans的定義,這里,你需要正確設(shè)置classpath因?yàn)檫@個(gè)容器將在classpath里找bean配置。 WebXmlApplicationContext:此容器加載一個(gè)XML文件,此文件定義了一個(gè)WEB應(yīng)用的所有bean。
Spring的依賴注入
其主要實(shí)現(xiàn)方式有兩種:依賴注入和依賴查找。
依賴注入: 相對(duì)于IoC而言,依賴注入(DI)更加準(zhǔn)確地描述了IoC的設(shè)計(jì)理念。所謂依賴注入(Dependency Injection),即組件之間的依賴關(guān)系由容器在應(yīng)用系統(tǒng)運(yùn)行期來(lái)決定,也就是由容器動(dòng)態(tài)地將某種依賴關(guān)系的目標(biāo)對(duì)象實(shí)例注入到應(yīng)用系統(tǒng)中的各個(gè)關(guān)聯(lián)的組件之中。組件不做定位查詢,只提供普通的Java方法讓容器去決定依賴關(guān)系。
依賴注入的基本原則
應(yīng)用組件不應(yīng)該負(fù)責(zé)查找資源或者其他依賴的協(xié)作對(duì)象。配置對(duì)象的工作應(yīng)該由IoC容器負(fù)責(zé),“查找資源”的邏輯應(yīng)該從應(yīng)用組件的代碼中抽取出來(lái),交給IoC容器負(fù)責(zé)。容器全權(quán)負(fù)責(zé)組件的裝配,它會(huì)把符合依賴關(guān)系的對(duì)象通過(guò)屬性(JavaBean中的setter)或者是構(gòu)造器傳遞給需要的對(duì)象。
依賴注入優(yōu)勢(shì)
依賴注入之所以更流行是因?yàn)樗且环N更可取的方式:讓容器全權(quán)負(fù)責(zé)依賴查詢,受管組件只需要暴露JavaBean的setter方法或者帶參數(shù)的構(gòu)造器或者接口,使容器可以在初始化時(shí)組裝對(duì)象的依賴關(guān)系。其與依賴查找方式相比,主要優(yōu)勢(shì)為:
查找定位操作與應(yīng)用代碼完全無(wú)關(guān) 不依賴于容器的API,可以很容易地在任何容器以外使用應(yīng)用對(duì)象 不需要特殊的接口,絕大多數(shù)對(duì)象可以做到完全不必依賴容器
依賴注入實(shí)現(xiàn)方式
依賴注入是時(shí)下最流行的IoC實(shí)現(xiàn)方式,依賴注入分為接口注入(Interface Injection),Setter方法注入(Setter Injection)和構(gòu)造器注入(Constructor Injection)三種方式。其中接口注入由于在靈活性和易用性比較差,現(xiàn)在從Spring4開(kāi)始已被廢棄。
構(gòu)造器依賴注入:構(gòu)造器依賴注入通過(guò)容器觸發(fā)一個(gè)類的構(gòu)造器來(lái)實(shí)現(xiàn)的,該類有一系列參數(shù),每個(gè)參數(shù)代表一個(gè)對(duì)其他類的依賴 Setter方法注入:Setter方法注入是容器通過(guò)調(diào)用無(wú)參構(gòu)造器或無(wú)參static工廠 方法實(shí)例化bean之后,調(diào)用該bean的setter方法,即實(shí)現(xiàn)了基于setter的依賴注入
構(gòu)造器依賴注入和 Setter方法注入的區(qū)別

兩種依賴方式都可以使用,構(gòu)造器注入和Setter方法注入。最好的解決方案是用構(gòu)造器參數(shù)實(shí)現(xiàn)強(qiáng)制依賴,setter方法實(shí)現(xiàn)可選依賴。
WebApplication 體系架構(gòu)
WebApplicationContext 是專門為 Web 應(yīng)用準(zhǔn)備的,它允許從相對(duì)于 Web 根目錄的路徑中裝載配置文件完成初始化工作。從 WebApplicationContext 中可以獲得ServletContext 的引用,整個(gè) Web 應(yīng)用上下文對(duì)象將作為屬性放置到 ServletContext 中,以便 Web 應(yīng)用環(huán)境可以訪問(wèn) Spring 應(yīng)用上下文。

Spring Bean 定義
一個(gè)Spring Bean 的定義包含容器必知的所有配置元數(shù)據(jù),包括如何創(chuàng)建一個(gè)bean,它的生命周期詳情及它的依賴。
Spring元數(shù)據(jù)配置方式 XML配置文件 基于注解的配置 基于java的配置
Spring Bean 作用域
Spring 3 中為 Bean 定義了 5 中作用域,分別為 singleton(單例)、prototype(原型)、request、session 和 global session,5 種作用域說(shuō)明如下:
singleton:?jiǎn)卫J剑ǘ嗑€程下不安全)。Spring IoC 容器中只會(huì)存在一個(gè)共享的 Bean 實(shí)例,無(wú)論有多少個(gè)Bean 引用它,始終指向同一對(duì)象。該模式在多線程下是不安全的。Singleton 作用域是Spring 中的缺省作用域,也可以顯示的將 Bean 定義為 singleton 模式,配置為: prototype:原型模式每次使用時(shí)創(chuàng)建。每次通過(guò) Spring 容器獲取 prototype 定義的 bean 時(shí),容器都將創(chuàng)建一個(gè)新的 Bean 實(shí)例,每個(gè) Bean 實(shí)例都有自己的屬性和狀態(tài),而 singleton 全局只有一個(gè)對(duì)象。根據(jù)經(jīng)驗(yàn),對(duì)有狀態(tài)的bean使用prototype作用域,而對(duì)無(wú)狀態(tài)的bean使用singleton 作用域。 Request:一次 request 一個(gè)實(shí)例。在一次 Http 請(qǐng)求中,容器會(huì)返回該 Bean 的同一實(shí)例。而對(duì)不同的 Http 請(qǐng)求則會(huì)產(chǎn)生新的 Bean,而且該 bean 僅在當(dāng)前 Http Request 內(nèi)有效,當(dāng)前 Http 請(qǐng)求結(jié)束,該 bean實(shí)例也將會(huì)被銷毀。 session:在一次 Http Session 中,容器會(huì)返回該 Bean 的同一實(shí)例。而對(duì)不同的 Session 請(qǐng)求則會(huì)創(chuàng)建新的實(shí)例,該 bean 實(shí)例僅在當(dāng)前 Session 內(nèi)有效。同 Http 請(qǐng)求相同,每一次session 請(qǐng)求創(chuàng)建新的實(shí)例,而不同的實(shí)例之間不共享屬性,且實(shí)例僅在自己的 session 請(qǐng)求內(nèi)有效,請(qǐng)求結(jié)束,則實(shí)例將被銷毀。 global Session:在一個(gè)全局的 Http Session 中,容器會(huì)返回該 Bean 的同一個(gè)實(shí)例,僅在使用 portlet context 時(shí)有效。
Spring處理線程并發(fā)問(wèn)題
在一般情況下,只有無(wú)狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因?yàn)镾pring對(duì)一些Bean中非線程安全狀態(tài)采用ThreadLocal進(jìn)行處理,解決線程安全問(wèn)題。
ThreadLocal和線程同步機(jī)制都是為了解決多線程中相同變量的訪問(wèn)沖突問(wèn)題。同步機(jī)制采用了“時(shí)間換空間”的方式,僅提供一份變量,不同的線程在訪問(wèn)前需要獲取鎖,沒(méi)獲得鎖的線程則需要排隊(duì)。而ThreadLocal采用了“空間換時(shí)間”的方式。
ThreadLocal會(huì)為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對(duì)象,在編寫多線程代碼時(shí),可以把不安全的變量封裝進(jìn)ThreadLocal。
Spring Bean 生命周期

實(shí)例化
實(shí)例化一個(gè) Bean,也就是我們常說(shuō)的 new。
IOC 依賴注入
按照 Spring 上下文對(duì)實(shí)例化的 Bean 進(jìn)行配置,也就是 IOC 注入。
setBeanName 實(shí)現(xiàn)
如果這個(gè) Bean 已經(jīng)實(shí)現(xiàn)了 BeanNameAware 接口,會(huì)調(diào)用它實(shí)現(xiàn)的 setBeanName(String)方法,此處傳遞的就是 Spring 配置文件中 Bean 的 id 值
BeanFactoryAware 實(shí)現(xiàn)
如果這個(gè) Bean 已經(jīng)實(shí)現(xiàn)了 BeanFactoryAware 接口,會(huì)調(diào)用它實(shí)現(xiàn)的 setBeanFactory,
setBeanFactory(BeanFactory)傳遞的是 Spring 工廠自身(可以用這個(gè)方式來(lái)獲取其它 Bean,只需在 Spring 配置文件中配置一個(gè)普通的 Bean 就可以)。
ApplicationContextAware 實(shí)現(xiàn)
如果這個(gè) Bean 已經(jīng)實(shí)現(xiàn)了 ApplicationContextAware 接口,會(huì)調(diào)用 setApplicationContext(ApplicationContext)方法,傳入 Spring 上下文(同樣這個(gè)方式也可以實(shí)現(xiàn)步驟 4 的內(nèi)容,但比 4 更好,因?yàn)?ApplicationContext 是 BeanFactory 的子接口,有更多的實(shí)現(xiàn)方法)
postProcessBeforeInitialization 接口實(shí)現(xiàn)-初始化預(yù)處理
如果這個(gè) Bean 關(guān)聯(lián)了 BeanPostProcessor 接口,將會(huì)調(diào)用 postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 經(jīng)常被用作是 Bean 內(nèi)容的更改,并且由于這個(gè)是在 Bean 初始化結(jié)束時(shí)調(diào)用那個(gè)的方法,也可以被應(yīng)用于內(nèi)存或緩存技術(shù)。
init-method
如果 Bean 在 Spring 配置文件中配置了 init-method 屬性會(huì)自動(dòng)調(diào)用其配置的初始化方法。
postProcessAfterInitialization
如果這個(gè) Bean 關(guān)聯(lián)了 BeanPostProcessor 接口,將會(huì)調(diào)用 postProcessAfterInitialization(Object obj, String s)方法。
注:以上工作完成以后就可以應(yīng)用這個(gè) Bean 了,那這個(gè) Bean 是一個(gè) Singleton 的,所以一般情況下我們調(diào)用同一個(gè) id 的 Bean 會(huì)是在內(nèi)容地址相同的實(shí)例,當(dāng)然在 Spring 配置文件中也可以配置非 Singleton。
Destroy 過(guò)期自動(dòng)清理階段
當(dāng) Bean 不再需要時(shí),會(huì)經(jīng)過(guò)清理階段,如果 Bean 實(shí)現(xiàn)了 DisposableBean 這個(gè)接口,會(huì)調(diào)用那個(gè)其實(shí)現(xiàn)的 destroy()方法;
destroy-method 自配置清理
最后,如果這個(gè) Bean 的 Spring 配置中配置了 destroy-method屬性,會(huì)自動(dòng)調(diào)用其配置的銷毀方法。
bean生命周期方法
bean 標(biāo)簽有兩個(gè)重要的屬性(init-method 和 destroy-method)。用它們你可以自己定制
初始化和注銷方法。它們也有相應(yīng)的注解(@PostConstruct 和@PreDestroy)。
""?class=""?init-method="初始化方法"?destroy-method="銷毀方法">
什么是Spring的內(nèi)部bean?什么是Spring inner beans?
在Spring框架中,當(dāng)一個(gè)bean僅被用作另一個(gè)bean的屬性時(shí),它能被聲明為一個(gè)內(nèi)部bean。
內(nèi)部bean可以用setter注入“屬性”和構(gòu)造方法注入“構(gòu)造參數(shù)”的方式來(lái)實(shí)現(xiàn),內(nèi)部bean通常是匿名的,它們的Scope一般是prototype。
Spring 依賴注入四種方式構(gòu)造器注入
/*帶參數(shù),方便利用構(gòu)造器進(jìn)行注入*/
?
?public?CatDaoImpl(String?message){
?
?this.?message?=?message;
?
?}
<bean?id="CatDaoImpl"?class="com.CatDaoImpl">
?
<constructor-arg?value="?message?">constructor-arg>
?
bean>
setter 方法注入
?public?class?Id?{
?
?private?int?id;
?
?public?int?getId()?{?return?id;?}
?
?public?void?setId(int?id)?{?this.id?=?id;?}
?
}
<bean?id="id"?class="com.id?">?<property?name="id"?value="123">property>?bean>
靜態(tài)工廠注入
靜態(tài)工廠顧名思義,就是通過(guò)調(diào)用靜態(tài)工廠的方法來(lái)獲取自己需要的對(duì)象,為了讓 spring 管理所有對(duì)象,我們不能直接通過(guò)"工程類.靜態(tài)方法()"來(lái)獲取對(duì)象,而是依然通過(guò) spring 注入的形式獲取:
public?class?DaoFactory?{?//靜態(tài)工廠
?
?public?static?final?FactoryDao?getStaticFactoryDaoImpl(){
?
?return?new?StaticFacotryDaoImpl();
?
?}
?
}
?
public?class?SpringAction?{
?
?private?FactoryDao?staticFactoryDao;?//注入對(duì)象
?
?//注入對(duì)象的?set?方法
?
?public?void?setStaticFactoryDao(FactoryDao?staticFactoryDao)?{
?
?this.staticFactoryDao?=?staticFactoryDao;
?
?}
?
}
?
?
?<bean?name="springAction"?class="?SpringAction"?>
?
?
?
?<property?name="staticFactoryDao"?ref="staticFactoryDao">property>
?
?bean>
?
?
?
<bean?name="staticFactoryDao"?class="DaoFactory"
?
factory-method="getStaticFactoryDaoImpl">bean>
實(shí)例工廠
實(shí)例工廠的意思是獲取對(duì)象實(shí)例的方法不是靜態(tài)的,所以你需要首先 new 工廠類,再調(diào)用普通的實(shí)例方法:
?public?class?DaoFactory?{?//實(shí)例工廠
?
?public?FactoryDao?getFactoryDaoImpl(){
?
?return?new?FactoryDaoImpl();
?
?}
?
}
?
public?class?SpringAction?{
?
?private?FactoryDao?factoryDao;?//注入對(duì)象
?
?public?void?setFactoryDao(FactoryDao?factoryDao)?{
?
?this.factoryDao?=?factoryDao;
?
?}
?
}
?<bean?name="springAction"?class="SpringAction">
?
?
?
?<property?name="factoryDao"?ref="factoryDao">property>
?
?bean>
?
?
?
<bean?name="daoFactory"?class="com.DaoFactory">bean>
?
<bean?name="factoryDao"?factory-bean="daoFactory"
?
factory-method="getFactoryDaoImpl">bean>
5 種不同方式的自動(dòng)裝配
Spring 裝配包括手動(dòng)裝配和自動(dòng)裝配,手動(dòng)裝配是有基于 xml 裝配、構(gòu)造方法、setter 方法等自動(dòng)裝配有五種自動(dòng)裝配的方式,可以用來(lái)指導(dǎo) Spring 容器用自動(dòng)裝配方式來(lái)進(jìn)行依賴注入。
no:默認(rèn)的方式是不進(jìn)行自動(dòng)裝配,通過(guò)顯式設(shè)置 ref 屬性來(lái)進(jìn)行裝配。byName:通過(guò)參數(shù)名 自動(dòng)裝配,Spring 容器在配置文件中發(fā)現(xiàn) bean 的 autowire 屬性被設(shè)置成 byName,之后容器試圖匹配、裝配和該 bean 的屬性具有相同名字的 bean。byType:通過(guò)參數(shù)類型自動(dòng)裝配,Spring 容器在配置文件中發(fā)現(xiàn) bean 的 autowire 屬性被設(shè)置成 byType,之后容器試圖匹配、裝配和該 bean 的屬性具有相同類型的 bean。如果有多個(gè) bean 符合條件,則拋出錯(cuò)誤。constructor:這個(gè)方式類似于 byType, 但是要提供給構(gòu)造器參數(shù),如果沒(méi)有確定的帶參數(shù)的構(gòu)造器參數(shù)類型,將會(huì)拋出異常。autodetect:首先嘗試使用 constructor 來(lái)自動(dòng)裝配,如果無(wú)法工作,則使用 byType 方式。
Spring 中注入一個(gè) Java Collection
Spring 提供了以下四種集合類的配置元素:
: 該標(biāo)簽用來(lái)裝配可重復(fù)的 list 值。: 該標(biāo)簽用來(lái)裝配沒(méi)有重復(fù)的 set 值。: 該標(biāo)簽可用來(lái)注入鍵和值可以為任何類型的鍵值對(duì)。: 該標(biāo)簽支持注入鍵和值都是字符串類型的鍵值對(duì)。
<beans>?
??
?<bean?id="javaCollection"?class="com.howtodoinjava.JavaCollection">?
??
?<property?name="customList">?
?<list>?
?<value>INDIAvalue>?
?<value>Pakistanvalue>?
?<value>USAvalue>?
?<value>UKvalue>?
?list>?
?property>?
?
??
?<property?name="customSet">?
?<set>?
?<value>INDIAvalue>?
?<value>Pakistanvalue>?
?<value>USAvalue>?
?<value>UKvalue>?
?set>?
?property>?
?
??
?<property?name="customMap">?
?<map>?
?<entry?key="1"?value="INDIA"/>?
?<entry?key="2"?value="Pakistan"/>?
?<entry?key="3"?value="USA"/>?
?<entry?key="4"?value="UK"/>?
?map>?
?property>?
?
??
?<property?name="customProperies">?
?<props>?
?<prop?key="admin">[email protected]prop>?
?<prop?key="support">[email protected]prop>?
?props>?
?property>?
?
?bean>?
beans>
使用@Autowired注解自動(dòng)裝配的過(guò)程
在使用@Autowired注解之前需要在Spring配置文件進(jìn)行配置,。
在啟動(dòng)spring IoC時(shí),容器自動(dòng)裝載了一個(gè)AutowiredAnnotationBeanPostProcessor后置處理器,當(dāng)容器掃描到@Autowied、@Resource或@Inject時(shí),就會(huì)在IoC容器自動(dòng)查找需要的bean,并裝配給該對(duì)象的屬性。在使用@Autowired時(shí),首先在容器中查詢對(duì)應(yīng)類型的bean:
如果查詢結(jié)果剛好為一個(gè),就將該bean裝配給 @Autowired指定的數(shù)據(jù);如果查詢的結(jié)果不止一個(gè),那么 @Autowired會(huì)根據(jù)名稱來(lái)查找;如果上述查找的結(jié)果為空,那么會(huì)拋出異常。解決方法時(shí),使用 required=false。
Spring AOP
AOP原理
OOP(Object-Oriented Programming)面向?qū)ο缶幊蹋试S開(kāi)發(fā)者定義縱向的關(guān)系,但并適用于定義橫向的關(guān)系,導(dǎo)致了大量代碼的重復(fù),而不利于各個(gè)模塊的重用。
AOP(Aspect-Oriented Programming),一般稱為面向切面編程,作為面向?qū)ο蟮囊环N補(bǔ)充,用于將那些與業(yè)務(wù)無(wú)關(guān),但卻對(duì)多個(gè)對(duì)象產(chǎn)生影響的公共行為和邏輯,抽取并封裝為一個(gè)可重用的模塊,這個(gè)模塊被命名為“切面”(Aspect),減少系統(tǒng)中的重復(fù)代碼,降低了模塊間的耦合度,同時(shí)提高了系統(tǒng)的可維護(hù)性。
AOP 主要應(yīng)用場(chǎng)景有
Authentication 權(quán)限 Caching 緩存 Context passing 內(nèi)容傳遞 Error handling 錯(cuò)誤處理 Lazy loading 懶加載 Debugging 調(diào)試 logging, tracing, profiling and monitoring 記錄跟蹤 優(yōu)化 校準(zhǔn) Performance optimization 性能優(yōu)化 Persistence 持久化 Resource pooling 資源池 Synchronization 同步 Transactions 事務(wù)
AOP 核心概念
切面(aspect):類是對(duì)物體特征的抽象,切面就是對(duì)橫切關(guān)注點(diǎn)的抽象 橫切關(guān)注點(diǎn):對(duì)哪些方法進(jìn)行攔截,攔截后怎么處理,這些關(guān)注點(diǎn)稱之為橫切關(guān)注點(diǎn) 連接點(diǎn)(joinpoint):被攔截到的點(diǎn),因?yàn)?Spring 只支持方法類型的連接點(diǎn),所以在 Spring中連接點(diǎn)指的就是被攔截到的方法,實(shí)際上連接點(diǎn)還可以是字段或者構(gòu)造器 切入點(diǎn)(pointcut):對(duì)連接點(diǎn)進(jìn)行攔截的定義 通知(advice):所謂通知指的就是指攔截到連接點(diǎn)之后要執(zhí)行的代碼,通知分為前置、后置、異常、最終、環(huán)繞通知五類 目標(biāo)對(duì)象:代理的目標(biāo)對(duì)象 織入(weave):將切面應(yīng)用到目標(biāo)對(duì)象并導(dǎo)致代理對(duì)象創(chuàng)建的過(guò)程 編譯期:切面在目標(biāo)類編譯時(shí)被織入。AspectJ的織入編譯器是以這種方式織入切面的; 類加載期:切面在目標(biāo)類加載到JVM時(shí)被織入。需要特殊的類加載器,它可以在目標(biāo)類被引入應(yīng)用之前增強(qiáng)該目標(biāo)類的字節(jié)碼。AspectJ5的加載時(shí)織入就支持以這種方式織入切面; 運(yùn)行期:切面在應(yīng)用運(yùn)行的某個(gè)時(shí)刻被織入。一般情況下,在織入切面時(shí),AOP容器會(huì)為目標(biāo)對(duì)象動(dòng)態(tài)地創(chuàng)建一個(gè)代理對(duì)象。SpringAOP就是以這種方式織入切面。 引入(introduction):在不修改代碼的前提下,引入可以在運(yùn)行期為類動(dòng)態(tài)地添加一些方法或字段
Spring 中的代理
將 Advice 應(yīng)用于目標(biāo)對(duì)象后創(chuàng)建的對(duì)象稱為代理。在客戶端對(duì)象的情況下,目標(biāo)對(duì)象和代理對(duì)象是相同的。
Advice + Target Object = Proxy
AOP 實(shí)現(xiàn)方式
AOP實(shí)現(xiàn)的關(guān)鍵在于代理模式,AOP代理主要分為靜態(tài)代理和動(dòng)態(tài)代理。
AspectJ 靜態(tài)代理的增強(qiáng),所謂靜態(tài)代理,就是AOP框架會(huì)在編譯階段生成AOP代理類,因此也稱為編譯時(shí)增強(qiáng),他會(huì)在編譯階段將AspectJ(切面)織入到Java字節(jié)碼中,運(yùn)行的時(shí)候就是增強(qiáng)之后的AOP對(duì)象。 Spring AOP使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說(shuō)AOP框架不會(huì)去修改字節(jié)碼,而是每次運(yùn)行時(shí)在內(nèi)存中臨時(shí)為方法生成一個(gè)AOP對(duì)象,這個(gè)AOP對(duì)象包含了目標(biāo)對(duì)象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對(duì)象的方法。
AOP 兩種代理方式
Spring 提供了兩種方式來(lái)生成代理對(duì)象: JDK Proxy 和 Cglib,具體使用哪種方式生成由AopProxyFactory 根據(jù) AdvisedSupport 對(duì)象的配置來(lái)決定。默認(rèn)的策略是如果目標(biāo)類是接口,則使用 JDK 動(dòng)態(tài)代理技術(shù),否則使用 Cglib 來(lái)生成代理。
JDK 動(dòng)態(tài)接口代理
JDK 動(dòng)態(tài)代理主要涉及到 java.lang.reflect 包中的兩個(gè)類:Proxy 和 InvocationHandler。
InvocationHandler是一個(gè)接口,通過(guò)實(shí)現(xiàn)該接口定義橫切邏輯,并通過(guò)反射機(jī)制調(diào)用目標(biāo)類的代碼,動(dòng)態(tài)將橫切邏輯和業(yè)務(wù)邏輯編制在一起。
Proxy 利用 InvocationHandler 動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的實(shí)例,生成目標(biāo)類的代理對(duì)象。
CGLib 動(dòng)態(tài)代理
CGLib 全稱為 Code Generation Library,是一個(gè)強(qiáng)大的高性能,高質(zhì)量的代碼生成類庫(kù),可以在運(yùn)行期擴(kuò)展 Java 類與實(shí)現(xiàn) Java 接口,CGLib 封裝了 asm,可以再運(yùn)行期動(dòng)態(tài)生成新的 class。和 JDK 動(dòng)態(tài)代理相比較:JDK 創(chuàng)建代理有一個(gè)限制,就是只能為接口創(chuàng)建代理實(shí)例,而對(duì)于沒(méi)有通過(guò)接口定義業(yè)務(wù)方法的類,則可以通過(guò) CGLib 創(chuàng)建動(dòng)態(tài)代理。
實(shí)現(xiàn)原理
@Aspect
?
public?class?TransactionDemo?{
?
?@Pointcut(value="execution(*?com.yangxin.core.service.*.*.*(..))")
?
?public?void?point(){
?
?}
?
?@Before(value="point()")
?
?public?void?before(){
?
?System.out.println("transaction?begin");
?
?}
?
?@AfterReturning(value?=?"point()")
?
?public?void?after(){
?
?System.out.println("transaction?commit");
?
?}
?
?@Around("point()")
?
?public?void?around(ProceedingJoinPoint?joinPoint)?throws?Throwable{
?
?System.out.println("transaction?begin");
?
?joinPoint.proceed();
?
?System.out.println("transaction?commit");
?
?}?}
Spring在運(yùn)行時(shí)通知對(duì)象
通過(guò)在代理類中包裹切面,Spring在運(yùn)行期把切面織入到Spring管理的bean中。代理封裝了目標(biāo)類,并攔截被通知方法的調(diào)用,再把調(diào)用轉(zhuǎn)發(fā)給真正的目標(biāo)bean。當(dāng)代理攔截到方法調(diào)用時(shí),在調(diào)用目標(biāo)bean方法之前,會(huì)執(zhí)行切面邏輯。
直到應(yīng)用需要被代理的bean時(shí),Spring才創(chuàng)建代理對(duì)象。如果使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載所有bean的時(shí)候,Spring才會(huì)創(chuàng)建被代理的對(duì)象。因?yàn)镾pring運(yùn)行時(shí)才創(chuàng)建代理對(duì)象,所以我們不需要特殊的編譯器來(lái)織入SpringAOP的切面。
Spring只支持方法級(jí)別的連接點(diǎn)
因?yàn)镾pring基于動(dòng)態(tài)代理,所以Spring只支持方法連接點(diǎn)。Spring缺少對(duì)字段連接點(diǎn)的支持,而且它不支持構(gòu)造器連接點(diǎn)。方法之外的連接點(diǎn)攔截功能,我們可以利用Aspect來(lái)補(bǔ)充。
在Spring AOP 中,關(guān)注點(diǎn)和橫切關(guān)注的區(qū)別是什么?在 spring aop 中 concern 和 cross-cutting concern 的不同之處
關(guān)注點(diǎn)(concern)是應(yīng)用中一個(gè)模塊的行為,一個(gè)關(guān)注點(diǎn)可能會(huì)被定義成一個(gè)我們想實(shí)現(xiàn)的一個(gè)功能。
橫切關(guān)注點(diǎn)(cross-cutting concern)是一個(gè)關(guān)注點(diǎn),此關(guān)注點(diǎn)是整個(gè)應(yīng)用都會(huì)使用的功能,并影響整個(gè)應(yīng)用,比如日志,安全和數(shù)據(jù)傳輸,幾乎應(yīng)用的每個(gè)模塊都需要的功能。因此這些都屬于橫切關(guān)注點(diǎn)。
Spring通知類型
在AOP術(shù)語(yǔ)中,切面的工作被稱為通知,實(shí)際上是程序執(zhí)行時(shí)要通過(guò)SpringAOP框架觸發(fā)的代碼段。Spring切面可以應(yīng)用5種類型的通知:
前置通知(Before):在目標(biāo)方法被調(diào)用之前調(diào)用通知功能; 后置通知(After):在目標(biāo)方法完成之后調(diào)用通知,此時(shí)不會(huì)關(guān)心方法的輸出是什么; 返回通知(After-returning ):在目標(biāo)方法成功執(zhí)行之后調(diào)用通知; 異常通知(After-throwing):在目標(biāo)方法拋出異常后調(diào)用通知; 環(huán)繞通知(Around):通知包裹了被通知的方法,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為。
同一個(gè)aspect,不同advice的執(zhí)行順序:
沒(méi)有異常情況下的執(zhí)行順序:
around before advice before advice target method 執(zhí)行 around after advice after advice afterReturning
有異常情況下的執(zhí)行順序:
around before advice before advice target method 執(zhí)行 around after advice after advice afterThrowing:異常發(fā)生 java.lang.RuntimeException: 異常發(fā)生
Spring MVC
Spring MVC 原理
Spring 的模型-視圖-控制器(MVC)框架是圍繞一個(gè) DispatcherServlet 來(lái)設(shè)計(jì)的,這個(gè) Servlet會(huì)把請(qǐng)求分發(fā)給各個(gè)處理器,并支持可配置的處理器映射、視圖渲染、本地化、時(shí)區(qū)與主題渲染等,甚至還能支持文件上傳。

Http 請(qǐng)求到 DispatcherServlet
(1) 客戶端請(qǐng)求提交到 DispatcherServlet。
HandlerMapping 尋找處理器
(2) 由 DispatcherServlet 控制器查詢一個(gè)或多個(gè) HandlerMapping,找到處理請(qǐng)求的Controller。
調(diào)用處理器 Controller
(3) DispatcherServlet 將請(qǐng)求提交到 Controller。
Controller 調(diào)用業(yè)務(wù)邏輯處理后,返回 ModelAndView
(4)(5)調(diào)用業(yè)務(wù)處理和返回結(jié)果:Controller 調(diào)用業(yè)務(wù)邏輯處理后,返回 ModelAndView。
DispatcherServlet 查詢 ModelAndView
(6)(7)處理視圖映射并返回模型:DispatcherServlet 查詢一個(gè)或多個(gè) ViewResoler 視圖解析器,找到 ModelAndView 指定的視圖。
ModelAndView 反饋瀏覽器 HTTP
(8) Http 響應(yīng):視圖負(fù)責(zé)將結(jié)果顯示到客戶端。
Spring DATA
Spring ORM理解
Spring 通過(guò)提供ORM模塊,支持我們?cè)谥苯覬DBC之上使用一個(gè)對(duì)象/關(guān)系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS,JPA,TopLink,JDO,OJB 。Spring的事務(wù)管理同樣支持以上所有ORM框架及JDBC。
解釋JDBC抽象和DAO模塊
通過(guò)使用JDBC抽象和DAO模塊,保證數(shù)據(jù)庫(kù)代碼的簡(jiǎn)潔,并能避免數(shù)據(jù)庫(kù)資源錯(cuò)誤關(guān)閉導(dǎo)致的問(wèn)題,它在各種不同的數(shù)據(jù)庫(kù)的錯(cuò)誤信息之上,提供了一個(gè)統(tǒng)一的異常訪問(wèn)層。它還利用Spring的AOP 模塊給Spring應(yīng)用中的對(duì)象提供事務(wù)管理服務(wù)。
Spring DAO 的支持
Spring DAO(數(shù)據(jù)訪問(wèn)對(duì)象) 使得 JDBC,Hibernate 或 JDO 這樣的數(shù)據(jù)訪問(wèn)技術(shù)更容易以一種統(tǒng)一的方式工作。這使得用戶容易在持久性技術(shù)之間切換。它還允許您在編寫代碼時(shí),無(wú)需考慮捕獲每種技術(shù)不同的異常。
Spring JDBC API
JdbcTemplate SimpleJdbcTemplate NamedParameterJdbcTemplate SimpleJdbcInsert SimpleJdbcCall
JdbcTemplate是什么
JdbcTemplate 類提供了很多便利的方法解決諸如把數(shù)據(jù)庫(kù)數(shù)據(jù)轉(zhuǎn)變成基本數(shù)據(jù)類型或?qū)ο螅瑘?zhí)行寫好的或可調(diào)用的數(shù)據(jù)庫(kù)操作語(yǔ)句,提供自定義的數(shù)據(jù)錯(cuò)誤處理。
使用Spring通過(guò)什么方式訪問(wèn)Hibernate?
有兩種方式訪問(wèn)Hibernate:
使用 Hibernate 模板和回調(diào)進(jìn)行控制反轉(zhuǎn) 擴(kuò)展 HibernateDAOSupport 并應(yīng)用 AOP 攔截器節(jié)點(diǎn)
Spring 支持的 ORM
Spring 支持以下 ORM:
Hibernate iBatis JPA (Java Persistence API) TopLink JDO (Java Data Objects) OJB
如何通過(guò) HibernateDaoSupport 將 Spring 和 Hibernate 結(jié)合起來(lái)?
用 Spring 的 SessionFactory 調(diào)用 LocalSessionFactory。集成過(guò)程分三步:
配置 the Hibernate SessionFactory 繼承 HibernateDaoSupport 實(shí)現(xiàn)一個(gè) DAO 在 AOP 支持的事務(wù)中裝配
Spring 支持的事務(wù)管理類型
Spring 支持兩種類型的事務(wù)管理:
編程式事務(wù)管理:這意味你通過(guò)編程的方式管理事務(wù),給你帶來(lái)極大的靈活性,但是 難維護(hù)。 聲明式事務(wù)管理:這意味著你可以將業(yè)務(wù)代碼和事務(wù)管理分離,你只需用注解和 XML 配置來(lái)管理事務(wù)。
Spring 框架的事務(wù)管理有哪些優(yōu)點(diǎn)?
它為不同的事務(wù) API 如 JTA,JDBC,Hibernate,JPA 和 JDO,提供一個(gè)不變 的編程模式。
它為編程式事務(wù)管理提供了一套簡(jiǎn)單的 API 而不是一些復(fù)雜的事務(wù) API 如 它支持聲明式事務(wù)管理。它和 Spring 各種數(shù)據(jù)訪問(wèn)抽象層很好得集成。
你更傾向用那種事務(wù)管理類型?
大多數(shù) Spring 框架的用戶選擇聲明式事務(wù)管理,因?yàn)樗鼘?duì)應(yīng)用代碼的影響最小,因 此更符合一個(gè)無(wú)侵入的輕量級(jí)容器的思想。聲明式事務(wù)管理要優(yōu)于編程式事務(wù)管理, 雖然比編程式事務(wù)管理(這種方式允許你通過(guò)代碼控制事務(wù))少了一點(diǎn)靈活性。
Spring常用注解
聲明bean的注解
@Component:組件,沒(méi)有明確的角色@Service:在業(yè)務(wù)邏輯層使用@Repository:在數(shù)據(jù)訪問(wèn)層使用@Controller:在展現(xiàn)層使用,控制層的聲明@RestController:@Controller和@ResponseBody組合,,控制層的聲明
注入bean的注解
@Autowired:
Spring自帶的注解,通過(guò)AutowiredAnnotationBeanPostProcessor 類實(shí)現(xiàn)的依賴注入,作用在CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE。默認(rèn)是根據(jù)類型(byType )進(jìn)行自動(dòng)裝配的。如果有多個(gè)類型一樣的Bean候選者,需要指定按照名稱(byName )進(jìn)行裝配,則需要配合@Qualifier。
指定名稱后,如果Spring IOC容器中沒(méi)有對(duì)應(yīng)的組件bean拋出NoSuchBeanDefinitionException。也可以將@Autowired中required配置為false,如果配置為false之后,當(dāng)沒(méi)有找到相應(yīng)bean的時(shí)候,系統(tǒng)不會(huì)拋異常
@Inject:
JSR330 (Dependency Injection for Java)中的規(guī)范,需要導(dǎo)入javax.inject.Inject jar包 ,才能實(shí)現(xiàn)注入 作用CONSTRUCTOR、METHOD、FIELD上
根據(jù)類型進(jìn)行自動(dòng)裝配的,如果需要按名稱進(jìn)行裝配,則需要配合@Named
@Resource:
JSR250規(guī)范的實(shí)現(xiàn),在javax.annotation包下,作用TYPE、FIELD、METHOD上。
默認(rèn)根據(jù)屬性名稱進(jìn)行自動(dòng)裝配的,如果有多個(gè)類型一樣的Bean候選者,則可以通過(guò)name進(jìn)行指定進(jìn)行注入
java配置類相關(guān)注解
@Configuration:聲明當(dāng)前類為配置類,相當(dāng)于xml形式的Spring配置(類上),聲明當(dāng)前類為配置類,其中內(nèi)部組合了@Component注解,表明這個(gè)類是一個(gè)bean(類上)@Bean:注解在方法上,聲明當(dāng)前方法的返回值為一個(gè)bean,替代xml中的方式(方法上)@ComponentScan:用于對(duì)Component進(jìn)行掃描,相當(dāng)于xml中的(類上)@WishlyConfiguration:為@Configuration與@ComponentScan的組合注解,可以替代這兩個(gè)注解
切面(AOP)相關(guān)注解
Spring支持AspectJ的注解式切面編程
@Aspect:聲明一個(gè)切面(類上),使用@After、@Before、@Around定義建言(advice),可直接將攔截規(guī)則(切點(diǎn))作為參數(shù)。@After:在方法執(zhí)行之后執(zhí)行(方法上)@Before:在方法執(zhí)行之前執(zhí)行(方法上)@Around:在方法執(zhí)行之前與之后執(zhí)行(方法上)@PointCut:聲明切點(diǎn)在java配置類中使用@EnableAspectJAutoProxy注解開(kāi)啟Spring對(duì)AspectJ代理的支持(類上)
@Bean的屬性支持
@Scope 設(shè)置Spring容器如何新建Bean實(shí)例(方法上,得有@Bean),其設(shè)置類型包括:
Singleton:?jiǎn)卫?一個(gè)Spring容器中只有一個(gè)bean實(shí)例,默認(rèn)模式Protetype:每次調(diào)用新建一個(gè)beanRequest:web項(xiàng)目中,給每個(gè)http request新建一個(gè)beanSession:web項(xiàng)目中,給每個(gè)http session新建一個(gè)beanGlobal:Session給每一個(gè) global http session新建一個(gè)Bean實(shí)例@StepScope:在Spring Batch中還有涉及(Spring Batch 之 背景框架簡(jiǎn)介_(kāi)vincent-CSDN博客)@PostConstruct:由JSR-250提供,在構(gòu)造函數(shù)執(zhí)行完之后執(zhí)行,等價(jià)于xml配置文件中bean的initMethod@PreDestory:由JSR-250提供,在Bean銷毀之前執(zhí)行,等價(jià)于xml配置文件中bean的destroyMethod
@Value注解
為屬性注入值,支持如下方式的注入:
注入普通字符

注入操作系統(tǒng)屬性

注入表達(dá)式結(jié)果

注入其它bean屬性

注入文件資源

注入網(wǎng)站資源

注入配置文件

@PropertySource 加載配置文件(類上),還需配置一個(gè)PropertySourcesPlaceholderConfigurer的bean。
環(huán)境切換
@Profile:通過(guò)設(shè)定Environment的ActiveProfiles來(lái)設(shè)定當(dāng)前context需要使用的配置環(huán)境。(類或方法上)@Conditional:Spring4中可以使用此注解定義條件話的bean,通過(guò)實(shí)現(xiàn)Condition接口,并重寫matches方法,從而決定該bean是否被實(shí)例化。(方法上)
異步相關(guān)
@EnableAsync:配置類中,通過(guò)此注解開(kāi)啟對(duì)異步任務(wù)的支持,敘事性AsyncConfigurer接口(類上)@Async:在實(shí)際執(zhí)行的bean方法使用該注解來(lái)申明其是一個(gè)異步任務(wù)(方法上或類上所有的方法都將異步,需要@EnableAsync開(kāi)啟異步任務(wù))
定時(shí)任務(wù)相關(guān)
@EnableScheduling:在配置類上使用,開(kāi)啟計(jì)劃任務(wù)的支持(類上)@Scheduled:來(lái)申明這是一個(gè)任務(wù),包括cron,fixDelay,fixRate等類型(方法上,需先開(kāi)啟計(jì)劃任務(wù)的支持)
@Enable 注解說(shuō)明
這些注解主要用來(lái)開(kāi)啟對(duì)xxx的支持。
@EnableAspectJAutoProxy:開(kāi)啟對(duì)AspectJ自動(dòng)代理的支持@EnableAsync:開(kāi)啟異步方法的支持@EnableScheduling:開(kāi)啟計(jì)劃任務(wù)的支持@EnableWebMvc:開(kāi)啟Web MVC的配置支持@EnableConfigurationProperties:開(kāi)啟對(duì)@ConfigurationProperties注解配置Bean的支持@EnableJpaRepositories:開(kāi)啟對(duì)SpringData JPA Repository的支持@EnableTransactionManagement:開(kāi)啟注解式事務(wù)的支持@EnableCaching:開(kāi)啟注解式的緩存支持
測(cè)試相關(guān)注解
@RunWith:運(yùn)行器,Spring中通常用于對(duì)JUnit的支持@ContextConfiguration:用來(lái)加載配置ApplicationContext,其中classes屬性用來(lái)加載配置類
SpringMVC部分
@EnableWebMvc:在配置類中開(kāi)啟Web MVC的配置支持,如一些ViewResolver或者M(jìn)essageConverter等,若無(wú)此句,重寫WebMvcConfigurerAdapter方法(用于對(duì)SpringMVC的配置)。@Controller:聲明該類為SpringMVC中的Controller@RequestMapping:用于映射Web請(qǐng)求,包括訪問(wèn)路徑和參數(shù)(類或方法上)@ResponseBody:支持將返回值放在response內(nèi),而不是一個(gè)頁(yè)面,通常用戶返回json數(shù)據(jù)(返回值旁或方法上)@RequestBody:允許request的參數(shù)在request體中,而不是在直接連接在地址后面。(放在參數(shù)前)@PathVariable:用于接收路徑參數(shù),比如@RequestMapping(“/hello/{name}”)申明的路徑,將注解放在參數(shù)中前,即可獲取該值,通常作為Restful的接口實(shí)現(xiàn)方法。@RestController:該注解為一個(gè)組合注解,相當(dāng)于@Controller和@ResponseBody的組合,注解在類上,意味著,該Controller的所有方法都默認(rèn)加上了@ResponseBody。@ControllerAdvice:通過(guò)該注解,我們可以將對(duì)于控制器的全局配置放置在同一個(gè)位置,注解了@Controller的類的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,這對(duì)所有注解了 @RequestMapping的控制器內(nèi)的方法有效。@ExceptionHandler:用于全局處理控制器里的異常@InitBinder:用來(lái)設(shè)置WebDataBinder,WebDataBinder用來(lái)自動(dòng)綁定前臺(tái)請(qǐng)求參數(shù)到Model中。@ModelAttribute:本來(lái)的作用是綁定鍵值對(duì)到Model里,在@ControllerAdvice中是讓全局的@RequestMapping:都能獲得在此處設(shè)置的鍵值對(duì)。
2022年粉絲福利? http://download.java1234.com/ 每月送?666?套Java資源網(wǎng)站?VIP會(huì)員,供大伙一起學(xué)Java 如果沒(méi)過(guò)鋒哥微信的 加一下鋒哥微信備注?VIP?即可開(kāi)通
