javascript
面试必备:Spring 面试 63 问!
作者 |?夏目
blog.csdn.net/wuzhiwei549/article/details/122324261
Sping原理
Spring是一個輕量級Java開發框架,最早有Rod Johnson創建,目的是為了解決企業級應用開發的業務邏輯層和其他各層的耦合問題。它是一個分層的JavaSE/JavaEE full-stack(一站式)輕量級開源框架,為開發Java應用程序提供全面的基礎架構支持。Spring負責基礎架構,因此Java開發者可以專注于應用程序的開發。
Spring是一個全面的、企業應用開發一站式的解決方案,貫穿表現層、業務層、持久層。但是它仍然可以和其他的框架無縫整合。
Spring 特點
輕量級: 組件大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小只有1M多的JAR文件中發布,并且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式,典型案例,Spring應用中的對象不依賴于Spring特定的類
控制反轉: Spring通過控制反轉(IOC)技術實現解耦。一個對象依賴的其他對象會通過被動的方式傳遞進來,而不需要對象自己創建或者查找依賴。
面向切面: 支持切面(AOP)編程,并且吧應用業務邏輯和系統服務區分開。
容器: Spring包含并管理應用對象的配置和生命周期,在這個意義上它是一種容器。可以配置每個bean如何被創建、銷毀,bean的作用范圍是單例還是每次都生成一個新的實例,以及他們是如何相互關聯。
框架集合: 將簡單的組件配置,組合成為復雜的框架;應用對象被申明式組合;提供許多基礎功能(事務管理、持久化框架繼承),提供應用邏輯開發接口
Spring 框架優缺點
優點
方便解耦,簡化開發:Spring就是一個大工廠,可以將所有對象的創建和依賴關系的維護,交給Spring管理。
AOP編程的支持:Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能。
聲明式事務的支持:只需要通過配置就可以完成對事務的管理,而無需手動編程。
方便程序的測試:Spring對Junit4支持,可以通過注解方便的測試Spring程序。
方便集成各種優秀框架:Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
降低JavaEE API的使用難度:Spring對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。
缺點
Spring依賴反射,反射影響性能
使用門檻升高,入門Spring需要較長時間
Spring 框架中都用到了哪些設計模式
Spring 框架中使用到了大量的設計模式,下面列舉了比較有代表性的:
代理模式—在 AOP 和 remoting 中被用的比較多。
單例模式—在 spring 配置文件中定義的 bean 默認為單例模式。
模板方法—用來解決代碼重復的問題。比如. RestTemplate, JmsTemplate, JpaTempl ate。
前端控制器—Spring 提供了 DispatcherServlet 來對請求進行分發。
視圖幫助(View Helper )—Spring 提供了一系列的 JSP 標簽,高效宏來輔助將分散的代碼整合在視圖里。
依賴注入—貫穿于 BeanFactory / ApplicationContext 接口的核心理念。
工廠模式—BeanFactory 用來創建對象的實例
Spring核心組件
Spring 總共大約有 20 個模塊, 由 1300 多個不同的文件構成。而這些組件被分別整合在核心容器(Core Container) 、 AOP(Aspect Oriented Programming)和設備支持(Instrmentation) 、數據訪問與集成(Data Access/Integeration) 、 Web、 消息(Messaging) 、 Test等 6 個模塊中。以下是 Spring 5 的模塊結構圖:
spring core:提供了框架的基本組成部分,包括控制反轉(Inversion of Control,IOC)和依賴注入(Dependency Injection,DI)功能。
spring beans:提供了BeanFactory,是工廠模式的一個經典實現,Spring將管理對象稱為Bean。
spring context:構建于 core 封裝包基礎上的 context 封裝包,提供了一種框架式的對象訪問方法。
spring jdbc:提供了一個JDBC的抽象層,消除了煩瑣的JDBC編碼和數據庫廠商特有的錯誤代碼解析, 用于簡化JDBC。
spring aop:提供了面向切面的編程實現,讓你可以自定義攔截器、切點等。
spring Web:提供了針對 Web 開發的集成特性,例如文件上傳,利用 servlet listeners 進行 ioc 容器初始化和針對 Web 的 ApplicationContext。
spring test:主要為測試提供支持的,支持使用JUnit或TestNG對Spring組件進行單元測試和集成測試。
Spring 控制反轉(IOC)
控制反轉(IOC)概念
控制反轉即IOC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理。
Spring 通過一個配置文件描述 Bean 及 Bean 之間的依賴關系,利用 Java 語言的反射功能(依賴注入DI)實例化 Bean 并建立 Bean 之間的依賴關系。Spring 的 IoC 容器在完成這些底層工作的基礎上,還提供 了 Bean 實例緩存、生命周期管理、 Bean 實例代理、事件發布、資源裝載等高級服務。
Spring 容器高層視圖
Spring 啟動時讀取應用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相應的 Bean 配
置注冊表,然后根據這張注冊表實例化 Bean,裝配好 Bean 之間的依賴關系,為上層應用提供準
備就緒的運行環境。其中 Bean 緩存池為 HashMap 實現
IOC 容器實現
BeanFactory-框架基礎設施
BeanFactory 是 Spring 框架的基礎設施,面向 Spring 本身;
ApplicationContext 面向使用Spring 框架的開發者,幾乎所有的應用場合我們都直接使用 ApplicationContext 而非底層的 BeanFactory。
BeanDefinitionRegistry 注冊表:Spring 配置文件中每一個節點元素在 Spring 容器里都通過一個 BeanDefinition 對象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注冊BeanDefinition 對象的方法。
BeanFactory 頂層接口:位于類結構樹的頂端 ,它最主要的方法就是 getBean(String beanName),該方法從容器中返回特定名稱的 Bean,BeanFactory 的功能通過其他的接口得到不斷擴展:
ListableBeanFactory:該接口定義了訪問容器中 Bean 基本信息的若干方法,如查看 Bean 的個數、獲取某一類型Bean 的配置名、查看容器中是否包括某一 Bean 等方法;
HierarchicalBeanFactory 父子級:父子級聯 IoC 容器的接口,子容器可以通過接口方法訪問父容器;通過HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子層級關聯的容器體系,子容器可以訪問父容器中的 Bean,但父容器不能訪問子容器的 Bean。Spring 使用父子容器實現了很多功能,比如在 Spring MVC 中,展現層 Bean 位于一個子容器中,而業務層和持久層的 Bean 位于父容器中。這樣,展現層 Bean 就可以引用業務層和持久層的 Bean,而業務層和持久層的 Bean 則看不到展現層的 Bean。
ConfigurableBeanFactory:是一個重要的接口,增強了 IoC 容器的可定制性,它定義了設置類裝載器、屬性編輯器、容器初始化后置處理器等方法;
AutowireCapableBeanFactory 自動裝配:定義了將容器中的 Bean 按某種規則(如按名字匹配、按類型匹配等)進行自動裝配的方法;
SingletonBeanRegistry 運行期間注冊單例 Bean:定義了允許在運行期間向容器注冊單實例 Bean 的方法;對于單實例( singleton)的 Bean 來說,BeanFactory 會緩存 Bean 實例,所以第二次使用 getBean() 獲取 Bean 時將直接從IoC 容器的緩存中獲取 Bean 實例。Spring 在 DefaultSingletonBeanRegistry 類中提供了一個用于緩存單實例 Bean 的緩存器,它是一個用 HashMap 實現的緩存器,單實例的 Bean 以beanName 為鍵保存在這個 HashMap 中。
依賴日志框架:在初始化 BeanFactory 時,必須為其提供一種日志框架,比如使用 Log4J, 即在類路徑下提供 Log4J 配置文件,這樣啟動 Spring 容器才不會報錯。
ApplicationContext 面向開發應用
ApplicationContext 由 BeanFactory 派生而來,提供了更多面向實際應用的功能。
ApplicationContext 繼承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基礎
上,還通過多個其他的接口擴展了 BeanFactory 的功能:
ClassPathXmlApplicationContext:默認從類路徑加載配置文件
FileSystemXmlApplicationContext:默認從文件系統中裝載配置文件
ApplicationEventPublisher:讓容器擁有發布應用上下文事件的功能,包括容器啟動事件、關閉事件等。
MessageSource:為應用提供 i18n 國際化消息訪問的功能;
ResourcePatternResolver :所有 ApplicationContext 實現類都實現了類似于
PathMatchingResourcePatternResolver:通過帶前綴的 Ant 風格的資源文件路徑裝載 Spring 的配置文件。
LifeCycle:該接口是 Spring 2.0 加入的,該接口提供了 start()和 stop()兩個方法,主要用于控制異步處理過程。在具體使用時,該接口同時被 ApplicationContext 實現及具體Bean 實現, ApplicationContext 會將 start/stop 的信息傳遞給容器中所有實現了該接口的 Bean,以達到管理和控制 JMX、任務調度等目的。
ConfigurableApplicationContext :擴展于 ApplicationContext,它新增加了兩個主要的方法:refresh()和 close(),讓 ApplicationContext 具有啟動、刷新和關閉應用上下文的能力。在應用上下文關閉的情況下調用 refresh()即可啟動應用上下文,在已經啟動的狀態下,調用 refresh()則清除緩存并重新裝載配置信息,而調用 close()則可關閉應用上下文。
BeanFactory 和 ApplicationContext有什么區別?
BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
依賴關系
BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命周期,維護bean之間的依賴關系。
ApplicationContext:接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
繼承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則是自動注冊。
ApplicationContext通常的實現
FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這里,你需要正確設置classpath因為這個容器將在classpath里找bean配置。
WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的所有bean。
Spring的依賴注入
其主要實現方式有兩種:依賴注入和依賴查找。
依賴注入: 相對于IoC而言,依賴注入(DI)更加準確地描述了IoC的設計理念。所謂依賴注入(Dependency Injection),即組件之間的依賴關系由容器在應用系統運行期來決定,也就是由容器動態地將某種依賴關系的目標對象實例注入到應用系統中的各個關聯的組件之中。組件不做定位查詢,只提供普通的Java方法讓容器去決定依賴關系。
依賴注入的基本原則
應用組件不應該負責查找資源或者其他依賴的協作對象。配置對象的工作應該由IoC容器負責,“查找資源”的邏輯應該從應用組件的代碼中抽取出來,交給IoC容器負責。容器全權負責組件的裝配,它會把符合依賴關系的對象通過屬性(JavaBean中的setter)或者是構造器傳遞給需要的對象。
依賴注入優勢
依賴注入之所以更流行是因為它是一種更可取的方式:讓容器全權負責依賴查詢,受管組件只需要暴露JavaBean的setter方法或者帶參數的構造器或者接口,使容器可以在初始化時組裝對象的依賴關系。其與依賴查找方式相比,主要優勢為:
查找定位操作與應用代碼完全無關
不依賴于容器的API,可以很容易地在任何容器以外使用應用對象
不需要特殊的接口,絕大多數對象可以做到完全不必依賴容器
依賴注入實現方式
依賴注入是時下最流行的IoC實現方式,依賴注入分為接口注入(Interface Injection),Setter方法注入(Setter Injection)和構造器注入(Constructor Injection)三種方式。其中接口注入由于在靈活性和易用性比較差,現在從Spring4開始已被廢棄。
構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系列參數,每個參數代表一個對其他類的依賴
Setter方法注入:Setter方法注入是容器通過調用無參構造器或無參static工廠 方法實例化bean之后,調用該bean的setter方法,即實現了基于setter的依賴注入
構造器依賴注入和 Setter方法注入的區別
兩種依賴方式都可以使用,構造器注入和Setter方法注入。最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴。
WebApplication 體系架構
WebApplicationContext 是專門為 Web 應用準備的,它允許從相對于 Web 根目錄的路徑中裝載配置文件完成初始化工作。從 WebApplicationContext 中可以獲得ServletContext 的引用,整個 Web 應用上下文對象將作為屬性放置到 ServletContext 中,以便 Web 應用環境可以訪問 Spring 應用上下文。
Spring Bean 定義
一個Spring Bean 的定義包含容器必知的所有配置元數據,包括如何創建一個bean,它的生命周期詳情及它的依賴。
Spring元數據配置方式
XML配置文件
基于注解的配置
基于java的配置
Spring Bean 作用域
Spring 3 中為 Bean 定義了 5 中作用域,分別為 singleton(單例)、prototype(原型)、request、session 和 global session,5 種作用域說明如下:
singleton:單例模式(多線程下不安全)。Spring IoC 容器中只會存在一個共享的 Bean 實例,無論有多少個Bean 引用它,始終指向同一對象。該模式在多線程下是不安全的。Singleton 作用域是Spring 中的缺省作用域,也可以顯示的將 Bean 定義為 singleton 模式,配置為:
prototype:原型模式每次使用時創建。每次通過 Spring 容器獲取 prototype 定義的 bean 時,容器都將創建一個新的 Bean 實例,每個 Bean 實例都有自己的屬性和狀態,而 singleton 全局只有一個對象。根據經驗,對有狀態的bean使用prototype作用域,而對無狀態的bean使用singleton 作用域。
Request:一次 request 一個實例。在一次 Http 請求中,容器會返回該 Bean 的同一實例。而對不同的 Http 請求則會產生新的 Bean,而且該 bean 僅在當前 Http Request 內有效,當前 Http 請求結束,該 bean實例也將會被銷毀。
session:在一次 Http Session 中,容器會返回該 Bean 的同一實例。而對不同的 Session 請求則會創建新的實例,該 bean 實例僅在當前 Session 內有效。同 Http 請求相同,每一次session 請求創建新的實例,而不同的實例之間不共享屬性,且實例僅在自己的 session 請求內有效,請求結束,則實例將被銷毀。
global Session:在一個全局的 Http Session 中,容器會返回該 Bean 的同一個實例,僅在使用 portlet context 時有效。
Spring處理線程并發問題
在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因為Spring對一些Bean中非線程安全狀態采用ThreadLocal進行處理,解決線程安全問題。
ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在訪問前需要獲取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。
ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。
Spring Bean 生命周期
實例化
實例化一個 Bean,也就是我們常說的 new。
IOC 依賴注入
按照 Spring 上下文對實例化的 Bean 進行配置,也就是 IOC 注入。
setBeanName 實現
如果這個 Bean 已經實現了 BeanNameAware 接口,會調用它實現的 setBeanName(String)方法,此處傳遞的就是 Spring 配置文件中 Bean 的 id 值
BeanFactoryAware 實現
如果這個 Bean 已經實現了 BeanFactoryAware 接口,會調用它實現的 setBeanFactory,
setBeanFactory(BeanFactory)傳遞的是 Spring 工廠自身(可以用這個方式來獲取其它 Bean,只需在 Spring 配置文件中配置一個普通的 Bean 就可以)。
ApplicationContextAware 實現
如果這個 Bean 已經實現了 ApplicationContextAware 接口,會調用setApplicationContext(ApplicationContext)方法,傳入 Spring 上下文(同樣這個方式也可以實現步驟 4 的內容,但比 4 更好,因為 ApplicationContext 是 BeanFactory 的子接口,有更多的實現方法)
postProcessBeforeInitialization 接口實現-初始化預處理
如果這個 Bean 關聯了 BeanPostProcessor 接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 經常被用作是 Bean 內容的更改,并且由于這個是在 Bean 初始化結束時調用那個的方法,也可以被應用于內存或緩存技術。
init-method
如果 Bean 在 Spring 配置文件中配置了 init-method 屬性會自動調用其配置的初始化方法。
postProcessAfterInitialization
如果這個 Bean 關聯了 BeanPostProcessor 接口,將會調用postProcessAfterInitialization(Object obj, String s)方法。
注:以上工作完成以后就可以應用這個 Bean 了,那這個 Bean 是一個 Singleton 的,所以一般情況下我們調用同一個 id 的 Bean 會是在內容地址相同的實例,當然在 Spring 配置文件中也可以配置非 Singleton。
Destroy 過期自動清理階段
當 Bean 不再需要時,會經過清理階段,如果 Bean 實現了 DisposableBean 這個接口,會調用那個其實現的 destroy()方法;
destroy-method 自配置清理
最后,如果這個 Bean 的 Spring 配置中配置了 destroy-method 屬性,會自動調用其配置的銷毀方法。
bean生命周期方法
bean 標簽有兩個重要的屬性(init-method 和 destroy-method)。用它們你可以自己定制
初始化和注銷方法。它們也有相應的注解(@PostConstruct 和@PreDestroy)。
<bean?id=""?class=""?init-method="初始化方法"?destroy-method="銷毀方法">什么是Spring的內部bean?什么是Spring inner beans?
在Spring框架中,當一個bean僅被用作另一個bean的屬性時,它能被聲明為一個內部bean。
內部bean可以用setter注入“屬性”和構造方法注入“構造參數”的方式來實現,內部bean通常是匿名的,它們的Scope一般是prototype。
Spring 依賴注入四種方式構造器注入
/*帶參數,方便利用構造器進行注入*/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>靜態工廠注入
靜態工廠顧名思義,就是通過調用靜態工廠的方法來獲取自己需要的對象,為了讓 spring 管理所有對象,我們不能直接通過"工程類.靜態方法()"來獲取對象,而是依然通過 spring 注入的形式獲取:
public?class?DaoFactory?{?//靜態工廠public?static?final?FactoryDao?getStaticFactoryDaoImpl(){return?new?StaticFacotryDaoImpl();}}public?class?SpringAction?{private?FactoryDao?staticFactoryDao;?//注入對象//注入對象的?set?方法public?void?setStaticFactoryDao(FactoryDao?staticFactoryDao)?{this.staticFactoryDao?=?staticFactoryDao;}}<!--factory-method="getStaticFactoryDaoImpl"指定調用哪個工廠方法--><bean?name="springAction"?class="?SpringAction"?><!--使用靜態工廠的方法注入對象,對應下面的配置文件--><property?name="staticFactoryDao"?ref="staticFactoryDao"></property></bean><!--此處獲取對象的方式是從工廠類中獲取靜態方法--><bean?name="staticFactoryDao"?class="DaoFactory"factory-method="getStaticFactoryDaoImpl"></bean>實例工廠
實例工廠的意思是獲取對象實例的方法不是靜態的,所以你需要首先 new 工廠類,再調用普通的實例方法:
public?class?DaoFactory?{?//實例工廠public?FactoryDao?getFactoryDaoImpl(){return?new?FactoryDaoImpl();}}public?class?SpringAction?{private?FactoryDao?factoryDao;?//注入對象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 種不同方式的自動裝配
Spring 裝配包括手動裝配和自動裝配,手動裝配是有基于 xml 裝配、構造方法、setter 方法等自動裝配有五種自動裝配的方式,可以用來指導 Spring 容器用自動裝配方式來進行依賴注入。
no:默認的方式是不進行自動裝配,通過顯式設置 ref 屬性來進行裝配。
byName:通過參數名 自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byName,之后容器試圖匹配、裝配和該 bean 的屬性具有相同名字的 bean。
byType:通過參數類型自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byType,之后容器試圖匹配、裝配和該 bean 的屬性具有相同類型的 bean。如果有多個 bean 符合條件,則拋出錯誤。
constructor:這個方式類似于 byType, 但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。
autodetect:首先嘗試使用 constructor 來自動裝配,如果無法工作,則使用 byType 方式。
Spring 中注入一個 Java Collection
Spring 提供了以下四種集合類的配置元素:
<list> : 該標簽用來裝配可重復的 list 值。
<set> : 該標簽用來裝配沒有重復的 set 值。
<map>: 該標簽可用來注入鍵和值可以為任何類型的鍵值對。
<props> : 該標簽支持注入鍵和值都是字符串類型的鍵值對。
使用@Autowired注解自動裝配的過程
在使用@Autowired注解之前需要在Spring配置文件進行配置,<context:annotation-config />。
在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,并裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:
如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的數據;
如果查詢的結果不止一個,那么@Autowired會根據名稱來查找;
如果上述查找的結果為空,那么會拋出異常。解決方法時,使用required=false。
Spring AOP
AOP原理
OOP(Object-Oriented Programming)面向對象編程,允許開發者定義縱向的關系,但并適用于定義橫向的關系,導致了大量代碼的重復,而不利于各個模塊的重用。
AOP(Aspect-Oriented Programming),一般稱為面向切面編程,作為面向對象的一種補充,用于將那些與業務無關,但卻對多個對象產生影響的公共行為和邏輯,抽取并封裝為一個可重用的模塊,這個模塊被命名為“切面”(Aspect),減少系統中的重復代碼,降低了模塊間的耦合度,同時提高了系統的可維護性。
AOP 主要應用場景有
Authentication 權限
Caching 緩存
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading 懶加載
Debugging 調試
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準
Performance optimization 性能優化
Persistence 持久化
Resource pooling 資源池
Synchronization 同步
Transactions 事務
AOP 核心概念
切面(aspect):類是對物體特征的抽象,切面就是對橫切關注點的抽象
橫切關注點:對哪些方法進行攔截,攔截后怎么處理,這些關注點稱之為橫切關注點
連接點(joinpoint):被攔截到的點,因為 Spring 只支持方法類型的連接點,所以在 Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
切入點(pointcut):對連接點進行攔截的定義
通知(advice):所謂通知指的就是指攔截到連接點之后要執行的代碼,通知分為前置、后置、異常、最終、環繞通知五類
目標對象:代理的目標對象
織入(weave):將切面應用到目標對象并導致代理對象創建的過程
編譯期:切面在目標類編譯時被織入。AspectJ的織入編譯器是以這種方式織入切面的;
類加載期:切面在目標類加載到JVM時被織入。需要特殊的類加載器,它可以在目標類被引入應用之前增強該目標類的字節碼。AspectJ5的加載時織入就支持以這種方式織入切面;
運行期:切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態地創建一個代理對象。SpringAOP就是以這種方式織入切面。
引入(introduction):在不修改代碼的前提下,引入可以在運行期為類動態地添加一些方法或字段
Spring 中的代理
將 Advice 應用于目標對象后創建的對象稱為代理。在客戶端對象的情況下,目標對象和代理對象是相同的。
Advice + Target Object = Proxy
AOP 實現方式
AOP實現的關鍵在于代理模式,AOP代理主要分為靜態代理和動態代理。
AspectJ 靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強,他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是增強之后的AOP對象。
Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,并且在特定的切點做了增強處理,并回調原對象的方法。
AOP 兩種代理方式
Spring 提供了兩種方式來生成代理對象: JDK Proxy 和 Cglib,具體使用哪種方式生成由AopProxyFactory 根據 AdvisedSupport 對象的配置來決定。默認的策略是如果目標類是接口,則使用 JDK 動態代理技術,否則使用 Cglib 來生成代理。
JDK 動態接口代理
JDK 動態代理主要涉及到 java.lang.reflect 包中的兩個類:Proxy 和 InvocationHandler。
InvocationHandler是一個接口,通過實現該接口定義橫切邏輯,并通過反射機制調用目標類的代碼,動態將橫切邏輯和業務邏輯編制在一起。
Proxy 利用 InvocationHandler 動態創建一個符合某一接口的實例,生成目標類的代理對象。
CGLib 動態代理
CGLib 全稱為 Code Generation Library,是一個強大的高性能,高質量的代碼生成類庫,可以在運行期擴展 Java 類與實現 Java 接口,CGLib 封裝了 asm,可以再運行期動態生成新的 class。和 JDK 動態代理相比較:JDK 創建代理有一個限制,就是只能為接口創建代理實例,而對于沒有通過接口定義業務方法的類,則可以通過 CGLib 創建動態代理。
實現原理
@Aspectpublic?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在運行時通知對象
通過在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。代理封裝了目標類,并攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法之前,會執行切面邏輯。
直到應用需要被代理的bean時,Spring才創建代理對象。如果使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載所有bean的時候,Spring才會創建被代理的對象。因為Spring運行時才創建代理對象,所以我們不需要特殊的編譯器來織入SpringAOP的切面。
Spring只支持方法級別的連接點
因為Spring基于動態代理,所以Spring只支持方法連接點。Spring缺少對字段連接點的支持,而且它不支持構造器連接點。方法之外的連接點攔截功能,我們可以利用Aspect來補充。
在Spring AOP 中,關注點和橫切關注的區別是什么?在 spring aop 中 concern 和 cross-cutting concern 的不同之處
關注點(concern)是應用中一個模塊的行為,一個關注點可能會被定義成一個我們想實現的一個功能。
橫切關注點(cross-cutting concern)是一個關注點,此關注點是整個應用都會使用的功能,并影響整個應用,比如日志,安全和數據傳輸,幾乎應用的每個模塊都需要的功能。因此這些都屬于橫切關注點。
Spring通知類型
在AOP術語中,切面的工作被稱為通知,實際上是程序執行時要通過SpringAOP框架觸發的代碼段。Spring切面可以應用5種類型的通知:
前置通知(Before):在目標方法被調用之前調用通知功能;
后置通知(After):在目標方法完成之后調用通知,此時不會關心方法的輸出是什么;
返回通知(After-returning ):在目標方法成功執行之后調用通知;
異常通知(After-throwing):在目標方法拋出異常后調用通知;
環繞通知(Around):通知包裹了被通知的方法,在被通知的方法調用之前和調用之后執行自定義的行為。
同一個aspect,不同advice的執行順序:
沒有異常情況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterReturning
有異常情況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterThrowing:異常發生
java.lang.RuntimeException: 異常發生
Spring MVC
Spring MVC 原理
Spring 的模型-視圖-控制器(MVC)框架是圍繞一個 DispatcherServlet 來設計的,這個 Servlet會把請求分發給各個處理器,并支持可配置的處理器映射、視圖渲染、本地化、時區與主題渲染等,甚至還能支持文件上傳。
Http 請求到 DispatcherServlet
(1) 客戶端請求提交到 DispatcherServlet。
HandlerMapping 尋找處理器
(2) 由 DispatcherServlet 控制器查詢一個或多個 HandlerMapping,找到處理請求的Controller。
調用處理器 Controller
(3) DispatcherServlet 將請求提交到 Controller。
Controller 調用業務邏輯處理后,返回 ModelAndView
(4)(5)調用業務處理和返回結果:Controller 調用業務邏輯處理后,返回 ModelAndView。
DispatcherServlet 查詢 ModelAndView
(6)(7)處理視圖映射并返回模型:DispatcherServlet 查詢一個或多個 ViewResoler 視圖解析器,找到 ModelAndView 指定的視圖。
ModelAndView 反饋瀏覽器 HTTP
(8) Http 響應:視圖負責將結果顯示到客戶端。
Spring DATA
Spring ORM理解
Spring 通過提供ORM模塊,支持我們在直接JDBC之上使用一個對象/關系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS,JPA,TopLink,JDO,OJB 。Spring的事務管理同樣支持以上所有ORM框架及JDBC。
解釋JDBC抽象和DAO模塊
通過使用JDBC抽象和DAO模塊,保證數據庫代碼的簡潔,并能避免數據庫資源錯誤關閉導致的問題,它在各種不同的數據庫的錯誤信息之上,提供了一個統一的異常訪問層。它還利用Spring的AOP 模塊給Spring應用中的對象提供事務管理服務。
Spring DAO 的支持
Spring DAO(數據訪問對象) 使得 JDBC,Hibernate 或 JDO 這樣的數據訪問技術更容易以一種統一的方式工作。這使得用戶容易在持久性技術之間切換。它還允許您在編寫代碼時,無需考慮捕獲每種技術不同的異常。
Spring JDBC API
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
JdbcTemplate是什么
JdbcTemplate 類提供了很多便利的方法解決諸如把數據庫數據轉變成基本數據類型或對象,執行寫好的或可調用的數據庫操作語句,提供自定義的數據錯誤處理。
使用Spring通過什么方式訪問Hibernate?
有兩種方式訪問Hibernate:
使用 Hibernate 模板和回調進行控制反轉
擴展 HibernateDAOSupport 并應用 AOP 攔截器節點
Spring 支持的 ORM
Spring 支持以下 ORM:
Hibernate
iBatis
JPA (Java Persistence API)
TopLink
JDO (Java Data Objects)
OJB
如何通過 HibernateDaoSupport 將 Spring 和 Hibernate 結合起來?
用 Spring 的 SessionFactory 調用 LocalSessionFactory。集成過程分三步:
配置 the Hibernate SessionFactory
繼承 HibernateDaoSupport
實現一個 DAO 在 AOP 支持的事務中裝配
Spring 支持的事務管理類型
Spring 支持兩種類型的事務管理:
編程式事務管理:這意味你通過編程的方式管理事務,給你帶來極大的靈活性,但是 難維護。
聲明式事務管理:這意味著你可以將業務代碼和事務管理分離,你只需用注解和 XML 配置來管理事務。
Spring 框架的事務管理有哪些優點?
它為不同的事務 API 如 JTA,JDBC,Hibernate,JPA 和 JDO,提供一個不變 的編程模式。
它為編程式事務管理提供了一套簡單的 API 而不是一些復雜的事務 API 如 它支持聲明式事務管理。它和 Spring 各種數據訪問抽象層很好得集成。
你更傾向用那種事務管理類型?
大多數 Spring 框架的用戶選擇聲明式事務管理,因為它對應用代碼的影響最小,因 此更符合一個無侵入的輕量級容器的思想。聲明式事務管理要優于編程式事務管理, 雖然比編程式事務管理(這種方式允許你通過代碼控制事務)少了一點靈活性。
Spring常用注解
聲明bean的注解
@Component :組件,沒有明確的角色
@Service :在業務邏輯層使用
@Repository :在數據訪問層使用
@Controller :在展現層使用,控制層的聲明
@RestController :@Controller和@ResponseBody組合,,控制層的聲明
注入bean的注解
@Autowired:
Spring自帶的注解,通過AutowiredAnnotationBeanPostProcessor 類實現的依賴注入,作用在CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE。默認是根據類型(byType )進行自動裝配的。如果有多個類型一樣的Bean候選者,需要指定按照名稱(byName )進行裝配,則需要配合@Qualifier。
指定名稱后,如果Spring IOC容器中沒有對應的組件bean拋出NoSuchBeanDefinitionException。也可以將@Autowired中required配置為false,如果配置為false之后,當沒有找到相應bean的時候,系統不會拋異常
@Inject:
JSR330 (Dependency Injection for Java)中的規范,需要導入javax.inject.Inject jar包 ,才能實現注入 作用CONSTRUCTOR、METHOD、FIELD上
根據類型進行自動裝配的,如果需要按名稱進行裝配,則需要配合@Named
@Resource:
JSR250規范的實現,在javax.annotation包下,作用TYPE、FIELD、METHOD上。
默認根據屬性名稱進行自動裝配的,如果有多個類型一樣的Bean候選者,則可以通過name進行指定進行注入
java配置類相關注解
@Configuration :聲明當前類為配置類,相當于xml形式的Spring配置(類上),聲明當前類為配置類,其中內部組合了@Component注解,表明這個類是一個bean(類上)
@Bean :注解在方法上,聲明當前方法的返回值為一個bean,替代xml中的方式(方法上)
@ComponentScan :用于對Component進行掃描,相當于xml中的(類上)
@WishlyConfiguration :為@Configuration與@ComponentScan的組合注解,可以替代這兩個注解
切面(AOP)相關注解
Spring支持AspectJ的注解式切面編程
@Aspect:聲明一個切面(類上),使用@After、@Before、@Around定義建言(advice),可直接將攔截規則(切點)作為參數。
@After :在方法執行之后執行(方法上)
@Before :在方法執行之前執行(方法上)
@Around :在方法執行之前與之后執行(方法上)
@PointCut :聲明切點在java配置類中使用@EnableAspectJAutoProxy注解開啟Spring對AspectJ代理的支持(類上)
@Bean的屬性支持
@Scope 設置Spring容器如何新建Bean實例(方法上,得有@Bean),其設置類型包括:
Singleton:單例,一個Spring容器中只有一個bean實例,默認模式
Protetype:每次調用新建一個bean
Request:web項目中,給每個http request新建一個bean
Session :web項目中,給每個http session新建一個bean
Global:Session給每一個 global http session新建一個Bean實例
@StepScope:在Spring Batch中還有涉及(Spring Batch 之 背景框架簡介_vincent-CSDN博客)
@PostConstruct :由JSR-250提供,在構造函數執行完之后執行,等價于xml配置文件中bean的initMethod
@PreDestory :由JSR-250提供,在Bean銷毀之前執行,等價于xml配置文件中bean的destroyMethod
@Value注解
為屬性注入值,支持如下方式的注入:
注入普通字符
注入操作系統屬性
注入表達式結果
注入其它bean屬性
注入文件資源
注入網站資源
注入配置文件
@PropertySource 加載配置文件(類上),還需配置一個PropertySourcesPlaceholderConfigurer的bean。
環境切換
@Profile :通過設定Environment的ActiveProfiles來設定當前context需要使用的配置環境。(類或方法上)
@Conditional:Spring4中可以使用此注解定義條件話的bean,通過實現Condition接口,并重寫matches方法,從而決定該bean是否被實例化。(方法上)
異步相關
@EnableAsync:配置類中,通過此注解開啟對異步任務的支持,敘事性AsyncConfigurer接口(類上)
@Async:在實際執行的bean方法使用該注解來申明其是一個異步任務(方法上或類上所有的方法都將異步,需要@EnableAsync開啟異步任務)
定時任務相關
@EnableScheduling :在配置類上使用,開啟計劃任務的支持(類上)
@Scheduled :來申明這是一個任務,包括cron,fixDelay,fixRate等類型(方法上,需先開啟計劃任務的支持)
@Enable 注解說明
這些注解主要用來開啟對xxx的支持。
@EnableAspectJAutoProxy :開啟對AspectJ自動代理的支持
@EnableAsync :開啟異步方法的支持
@EnableScheduling :開啟計劃任務的支持
@EnableWebMvc :開啟Web MVC的配置支持
@EnableConfigurationProperties :開啟對@ConfigurationProperties注解配置Bean的支持
@EnableJpaRepositories :開啟對SpringData JPA Repository的支持
@EnableTransactionManagement :開啟注解式事務的支持
@EnableCaching :開啟注解式的緩存支持
測試相關注解
@RunWith :運行器,Spring中通常用于對JUnit的支持
@ContextConfiguration:用來加載配置ApplicationContext,其中classes屬性用來加載配置類
SpringMVC部分
@EnableWebMvc :在配置類中開啟Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若無此句,重寫WebMvcConfigurerAdapter方法(用于對SpringMVC的配置)。
@Controller :聲明該類為SpringMVC中的Controller
@RequestMapping :用于映射Web請求,包括訪問路徑和參數(類或方法上)
@ResponseBody :支持將返回值放在response內,而不是一個頁面,通常用戶返回json數據(返回值旁或方法上)
@RequestBody :允許request的參數在request體中,而不是在直接連接在地址后面。(放在參數前)
@PathVariable :用于接收路徑參數,比如@RequestMapping(“/hello/{name}”)申明的路徑,將注解放在參數中前,即可獲取該值,通常作為Restful的接口實現方法。
@RestController :該注解為一個組合注解,相當于@Controller和@ResponseBody的組合,注解在類上,意味著,該Controller的所有方法都默認加上了@ResponseBody。
@ControllerAdvice :通過該注解,我們可以將對于控制器的全局配置放置在同一個位置,注解了@Controller的類的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,這對所有注解了 @RequestMapping的控制器內的方法有效。
@ExceptionHandler :用于全局處理控制器里的異常
@InitBinder :用來設置WebDataBinder,WebDataBinder用來自動綁定前臺請求參數到Model中。
@ModelAttribute :本來的作用是綁定鍵值對到Model里,在@ControllerAdvice中是讓全局的@RequestMapping:都能獲得在此處設置的鍵值對。
Spring Cloud Alibaba Nacos 服務注冊與發現功能實現!
2022-02-07
Nacos服務注冊與發現的2種實現方法!
2022-02-09
Spring Boot Admin,賊好使!
2022-01-14
求點贊、在看、分享三連
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的面试必备:Spring 面试 63 问!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot 中 4 大核心组件
- 下一篇: java 根据类名示例化类_Java L