Spring 是一種輕量級IoC和AOP容器框架,旨在提高開發人員的開發效率以及系統的可維護性。
我們一般說Spring框架指的是Spring Framework,它是很多模塊的集合,比如核心容器,數據訪問/繼承,web,AOP,工具,消息和測試模塊。Core Container中的Core組件是Spring所有組件的核心,Beans組件和Context組件是實現IOC和DI的基礎,AOP組件用來實現切面編程。
- Spring Core: 核心組件,Spring其他所有功能都需要依賴該類庫,主要提供IOC功能
- Spring Context: 提供框架式的Bean訪問方式
- Spring Aspects:該模塊爲AspectJ的集成提供支持
- Spring AOP:提供面向切面的編程實現
- Spring JDBC:JAVA數據庫連接支持
- Spring JMS:JAVA消息服務
- Spring ORM:用於支持Hibernate等ORM工具
- Spring Web:爲創建Web應用程序提供支持
- Spring Test:提供了對JUnit和TestNG測試的支持
Spring優點
- Spring屬於低侵入式設計,代碼的污染極低
- Spring的依賴注入機制將對象之間的依賴關係交由框架處理,減低組件耦合性
- Spring提供了AOP技術,支持將一些通用任務,如安全、事務、日誌、權限等進行集中式管理,從而提供更好的複用。
- spring對於主流的應用框架提供了集成支持。
AOP(Aspect-Oriented Programming): 面向切面編程
作爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲“切面”,便於減少系統的重複代碼,降低模塊間的耦合。
AOP就是基於動態代理實現的,如果要代理的對象實現了某個接口,那麼Spring AOP會使用JDK 動態代理,去創建代理對象,對於沒有實現接口的目標對象,無法使用JDK代理,會用Cglib代理,這時候會生成一個被代理對象的子類來作爲代理
IOC(Inverse of Control: 控制反轉):
是一種設計思想,利用反射原理,將原本在程序中手動創建對象的控制權轉交給Spring容器管理。IOC容器是Spring用來實現IOC的載體,IOC容器實際上就是個Map(key, value),map中存放的是各種對象。
將對象之間的相互依賴關係交給IOC容器來管理,並由IOC容器完成對象的注入,這樣可以簡化引用的開發,把應用從複雜的依賴關係中解放出來。IOC容器就像一個工廠一樣,當我們需要創建一個對象的時候,只需要配置好配置文件或註解,不用考慮對象如何被創建的。
Spring IOC初始化過程
XML配置文件----讀取—>Resource----解析—>BeanDefinition ----註冊---->BeanFactory
IOC的三種注入方式:構造器注入,setter方法注入,註解注入
spring IOC和DI有什麼區別?
IoC Inverse of Control 反轉控制的概念,就是將原本在程序中手動創建對象的控制權,交由Spring框架管理
DI:Dependency Injection 依賴注入,在Spring框架負責創建Bean對象時,動態的將依賴對象注入到Bean組件
AspectJ
AspectJ是AOP思想的具體實現,但AspectJ相比AOP功能更加強大,AOP只能在由 Spring 容器管理的 bean 上實現而AspectJ可以在所有域對象上實現,AOP僅支持方法執行切入點 AspectJ支持所有切入點。
AOP屬於運行時增強,AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱爲編譯時增強,AOP基於代理,AspectJ基於字節碼操作,如果我們的切面比較少,那麼兩者性能差異不大,但是切面太多的話,最好選擇AspectJ,他比AOP快很多。原因是AspectJ在編譯時增強,AOP運行時增強。
BeanFactory和ApplicationContext有什麼區別
BeanFactory和ApplicationContext是Spring兩大核心接口,都可以當作Spring的容器,其中ApplicationContext是BeanFactory的子接口
- BeanFactory:是Spring裏面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命週期,維護bean之間的依賴關係
- 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的作用域
- Spring的作用域有singleton、prototype、request、session和global session
- singleton:默認,每一個Spring容器只有一個對象實例
- prototype:每次請求都會創建一個新的實例
- request:每一個http請求都會產生一個新的bean實例,該bean僅在當前http request內有效
- session:每一個HTTP請求都會創建一個新的bean對象,且該對象僅在當前session中有效
- global session:在一個全局的session中,容器會返回該bean的同一個實例,僅僅在基於portlet容器的web應用中才有意義,spring 5中已經沒有了
Spring中單例bean的線程安全問題
單例bean存在線程安全問題,主要是多線程操作同一個對象的時候,對這個對象的非靜態成員變量的寫操作會存在線程安全問題
解決方式:可以在類中定義一個ThreadLocal成員變量,將需要的可變成員變量保存在ThreadLocal中
Spring中Bean的生命週期
-
實例化Bean:
對於BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要注入另一個尚未初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啓動結束後,通過獲取BeanDefinition對象中的信息,實例化所有的bean。
-
設置對象屬性(依賴注入)
實例化後的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 通過BeanWrapper提供的設置屬性的接口完成依賴注入。
-
處理Aware接口
Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:
①如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;
②如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。
③如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;
-
BeanPostProcessor
如果想對Bean進行一些自定義的處理,那麼可以讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。
-
InitializingBean與init-method
如果Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法
-
如果這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;由於這個方法是在Bean初始化結束時調用的,所以可以被應用於內存或緩存技術;
-
以上幾個步驟完成後,Bean就已經被正確創建了,之後就可以使用這個Bean了
-
DisposableBean
當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法
-
destroy-method
最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法
Spring框架中用到了那些設計模式
- 工廠設計模式:Spring使用工廠模式通過BeanFactory,ApplicationContext創建bean對象
- 代理設計模式:AOP功能的實現
- 單例設計模式:Spring中Bean默認都是單例的
- 模板方法模式:Spring中jdbcTemplate, hibernateTemplate等以Template結尾的對數據庫操作的類,他們就使用到了模板模式
- 包裝器設計模式:我們項目需要連接多個數據庫,而且不同的客戶在每次訪問中根據需要去訪問不同的數據庫,這種模式能夠讓我們根據客戶的需要動態切換數據源。
- 觀察者模式:Spring事件驅動模型就是觀察者模式很經典的一個應用
- 適配器模式:Spring AOP 的增強或通知使用到了適配器模式,SpringMVC中也用到了適配器模式適配Controller
Spring管理事務的方式
Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是無法提供事務功能的。真正的數據庫層的事務提交和回滾是通過binlog或者redo log實現的。
- 編程式事務使用TransactionTemplate,在代碼中硬編程,不推薦使用
- 聲明式事務,在配置文件中配置,推薦
- 基於xml的聲明式事務
- 基於註解的聲明式事務
Spring中事務的隔離級別
TransactionDefinition接口中定義了5個表示隔離級別的常量
- TransactionDefinition.ISOLATION_DEFAULT: 默認使用數據庫的隔離級別,Mysql 默認採用的 REPEATABLE_READ隔離級別 Oracle 默認採用的 READ_COMMITTED隔離級別.
- TransactionDefinition.ISOLATION_READ_UNCOMMITED: 最低的隔離級別,允許讀取未提交的數據變更,會導致髒讀,不可重複讀,幻讀。
- TransactionDefinition.ISOLATION_READ_COMMITED: 允許讀取併發事務已經提交的數據,會導致,不可重複讀,幻讀。
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一字段的多次讀取結果都是一致的,除非被本身事務自己所修改,會導致,幻讀。
- TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別,所有事務依次執行,這樣事務之間就不會產生干擾,但是會嚴重影響程序性能。
Spring事務中的七個傳播機制
- 支持當前事務的情況:
- TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,加入該事務;如果當前沒有事務,創建一個新的事務
- TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,加入該事務,如果沒有存在事務,則以非事務的方式繼續允許
- TransactionDefinition.PROPAGATION_MANDATORY(mandatory:強制的):如果當前存在事務,則加入該事務,如果當前沒有事務則拋出異常。
- 不支持當前事務的情況:
- TransactionDefinition.PROPAGATION_REQUIRYES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,如果當前存在事務則把當前事務掛起
- TransactionDefinition.PROPAGATION_NEVER: 以非事務方式運行,如果當前存在事務則拋出異常
- 其他情況:
- TransactionDefinition.PROPAGATION_NESTED(nested: 嵌套):如果當前存在事務,則創建 一個事務作爲當前事務的嵌套事務來運行,如果當前沒有事務,則該取值等價於:TransactionDefinition.PROPAGATION_REQUIRED
@Transactional(rollbackFor = Exception.class)註解
我們知道:Exception分爲運行時異常RuntimeException和非運行時異常。事務管理對於企業應用來說是至關重要的,即使出現異常情況,它也可以保證數據的一致性。
當@Transactional
註解作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標註來覆蓋類級別的定義。如果類或者方法加了這個註解,那麼這個類裏面的方法拋出異常,就會回滾,數據庫裏面的數據也會回滾。
在@Transactional
註解中如果不配置rollbackFor
屬性,那麼事物只會在遇到RuntimeException
的時候纔會回滾,加上rollbackFor=Exception.class
,可以讓事物在遇到非運行時異常時也回滾。
Spring框架中有哪些不同類型的事件?
Spring 提供了以下5種標準的事件:
(1)上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
(2)上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件。
(3)上下文停止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件。
(4)上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷燬。
(5)請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。
如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被髮布以後,bean會自動被通知。