Spring:現代Java開發的必備框架 Spring是一個輕量級的Java框架,它提供了各種企業級應用程式開發的工具和技術。Spring框架的核心是IoC容器和AOP框架。IoC容器使得Java應用程式的組件化變得更加容易,AOP框架使得Java應用程式的切麵編程變得更加容易。Spring框架還提 ...
目錄
Spring:現代Java開發的必備框架
Spring是一個輕量級的Java框架,它提供了各種企業級應用程式開發的工具和技術。Spring框架的核心是IoC容器和AOP框架。IoC容器使得Java應用程式的組件化變得更加容易,AOP框架使得Java應用程式的切麵編程變得更加容易。Spring框架還提供了許多其他的功能,例如數據訪問、Web開發、安全性、事務管理等。
Spring創建bean的生命周期以及對應的介面和註解
Spring創建bean的生命周期包含以下步驟:
- 實例化Bean:Spring通過構造器或工廠方法來創建Bean實例。
- 設置Bean屬性:Spring通過setter方法或直接訪問欄位來設置Bean的屬性值。
- BeanNameAware介面:如果Bean實現了BeanNameAware介面,Spring將Bean的ID傳遞給setBeanName()方法。
- BeanFactoryAware介面:如果Bean實現了BeanFactoryAware介面,Spring將BeanFactory實例傳遞給setBeanFactory()方法。
- ApplicationContextAware介面:如果Bean實現了ApplicationContextAware介面,Spring將ApplicationContext實例傳遞給setApplicationContext()方法。
- Pre-Initialization BeanPostProcessor:在Bean初始化之前,Spring通過調用PostProcessBeforeInitialization()方法提供了一個擴展點,可以在Bean初始化之前對Bean進行定製。
- InitializingBean介面:如果Bean實現了InitializingBean介面,Spring將調用afterPropertiesSet()方法。
- 自定義初始化方法:Bean可以自定義初始化方法,只需要在Bean定義中指定該方法的名稱。
- Post-Initialization BeanPostProcessor:在Bean初始化之後,Spring通過調用PostProcessAfterInitialization()方法提供了一個擴展點,可以在Bean初始化之後對Bean進行定製。
- DisposableBean介面:如果Bean實現了DisposableBean介面,Spring將調用destroy()方法。
- 自定義銷毀方法:Bean可以自定義銷毀方法,只需要在Bean定義中指定該方法的名稱。
在Spring中,可以使用以下註解來控制Bean的生命周期:
- @PostConstruct:指定初始化方法,相當於InitializingBean介面的afterPropertiesSet()方法。
- @PreDestroy:指定銷毀方法,相當於DisposableBean介面的destroy()方法。
- @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod"):指定初始化方法和銷毀方法。
Spring使用三級緩存解決迴圈依賴的原理
- singletonObjects:保存已經完全創建好的單例Bean。
- earlySingletonObjects:保存已經實例化、但是還未填充屬性的單例Bean。
- singletonFactories:保存Bean的工廠方法。
當兩個Bean相互依賴時,Spring會先使用工廠方法創建一個Bean的代理對象,然後將代理對象放入到singletonFactories緩存中。接著,Spring會繼續創建被依賴的Bean。如果創建被依賴的Bean時,需要引用到代理對象,Spring會先到singletonFactories緩存中查找代理對象,如果找到了,就使用代理對象,否則就繼續創建代理對象。當被依賴的Bean創建完成後,Spring會將被依賴的Bean放入到singletonObjects緩存中。接著,Spring會回到代理對象,填充代理對象的屬性,然後將代理對象放入到earlySingletonObjects緩存中。當代理對象的屬性填充完成後,Spring會將代理對象替換成真正的Bean對象,然後將真正的Bean對象放入到singletonObjects緩存中,並清除earlySingletonObjects緩存和singletonFactories緩存中的代理對象。
Spring使用三級緩存創建bean的過程
Spring使用三級緩存創建Bean的詳細過程如下:
- 首先,Spring會檢查該Bean是否已經創建並存儲在singletonObjects緩存中。如果Bean已經存在,則直接返回該Bean實例。這是最快的情況。
- 如果Bean不存在於singletonObjects緩存中,Spring會檢查該Bean是否正在創建中。如果正在創建中,則返回一個代理對象,該代理對象會在真正的Bean創建完成後被替換成真正的Bean對象。這是為了防止迴圈依賴的情況。
- 如果該Bean既不存在於singletonObjects緩存中,也沒有正在創建中,則Spring會創建一個ObjectFactory,該ObjectFactory負責創建該Bean實例。ObjectFactory是一個工廠方法,它負責創建和返回Bean實例。
- 然後,Spring會將該ObjectFactory存儲到singletonFactories緩存中,以便下次獲取該Bean實例時使用。這是為了提高創建Bean實例的效率。
- 接著,Spring會檢查該Bean是否依賴於其他Bean。如果依賴於其他Bean,則會先創建依賴的Bean實例。依賴項可以是其他Bean,也可以是基本類型或集合。
- 如果依賴的Bean實例還不存在,則Spring會遞歸地創建依賴的Bean實例,直到所有依賴的Bean實例都已經創建完成。這是為了保證依賴關係正確。
- 如果所有依賴的Bean實例都已經創建完成,則Spring會從singletonFactories緩存中獲取該Bean的ObjectFactory,並使用該ObjectFactory創建該Bean實例。這是Bean實例的創建過程。
- 創建該Bean實例後,Spring會將該Bean實例存儲到earlySingletonObjects緩存中,以便後續填充該Bean的屬性。earlySingletonObjects緩存包含已經創建的單例Bean實例,但是還沒有填充屬性。
- 接著,Spring會遞歸地填充該Bean的屬性。如果該Bean的屬性依賴於其他Bean,則會先創建依賴的Bean實例。填充屬性之前,Spring會調用所有實現了BeanPostProcessor介面的類的postProcessBeforeInitialization()方法做一些預處理工作。這是為了提供一個擴展點,可以在Bean初始化之前對Bean進行定製。
- 如果所有依賴的Bean實例都已經創建完成,則Spring會從singletonObjects緩存中獲取依賴的Bean實例,並將依賴的Bean實例填充到該Bean的屬性中。填充屬性之後,Spring會再次調用所有實現了BeanPostProcessor介面的類的postProcessAfterInitialization()方法做一些後處理工作。這是為了提供一個擴展點,可以在Bean初始化之後對Bean進行定製。
- 填充該Bean的屬性後,Spring會將該Bean實例存儲到singletonObjects緩存中,並從earlySingletonObjects緩存中移除該Bean實例。singletonObjects緩存包含已經創建的單例Bean實例,並已經填充了屬性。
- 最後,Spring會遞歸地處理該Bean的後置處理器,然後返回該Bean實例。如果Bean實現了InitializingBean介面,Spring會調用其afterPropertiesSet()方法,這是Bean初始化之後的最後一步。如果Bean實現了DisposableBean介面,Spring會在Bean銷毀之前調用其destroy()方法。
Spring使用AOP
基本過程如下:
- 在配置類上添加@EnableAspectJAutoProxy註解,啟用AspectJ自動代理。
- 創建一個切麵類,並且在該類上使用@Aspect註解來標識該類為切麵類。
- 在切麵類中定義一個或多個切點,用來匹配需要攔截的方法。
- 在切麵類中定義一個或多個通知,用來在方法執行前、執行後或拋出異常時執行一些額外的邏輯。
- 將切麵類添加到Spring的容器中。
以下是一個使用註解方式實現AOP的示例:
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.demo.service.*.*(..))")
public void serviceLayer(){}
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before " + joinPoint.getSignature().getName());
}
@After("serviceLayer()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After " + joinPoint.getSignature().getName());
}
}
@Service
public class DemoService {
public void doSomething() {
System.out.println("Doing something...");
}
}
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example.demo")
public class AppConfig {
}
在上面的示例中,LoggingAspect是一個切麵類,它定義了一個切點serviceLayer()和兩個通知logBefore()和logAfter()。serviceLayer()用來匹配com.example.demo.service包中所有方法,logBefore()和logAfter()分別在方法執行前和執行後輸出一條日誌。DemoService是一個普通的服務類,它的doSomething()方法會被LoggingAspect攔截。最後,AppConfig是一個配置類,它啟用了AspectJ自動代理,並將LoggingAspect和DemoService添加到Spring的容器中。
當調用DemoService的doSomething()方法時,LoggingAspect會攔截該方法,併在方法執行前輸出一條日誌,同時在方法執行後輸出一條日誌。
SpringAOP的實現原理
Spring AOP的實現原理是使用動態代理技術。動態代理是在運行時創建代理對象,代理對象實現了目標對象的介面,並且攔截所有方法調用。Spring AOP使用了兩種類型的代理:JDK動態代理和CGLIB動態代理。如果目標對象實現了介面,則使用JDK動態代理;否則,使用CGLIB動態代理。
Spring使用事務管理
Spring的事務管理可以通過如下方式來使用:
- 配置事務管理器:Spring提供了多種事務管理器,如DataSourceTransactionManager、HibernateTransactionManager等。可以通過配置事務管理器來選擇適合的事務管理器。
- 配置事務屬性:可以通過配置事務屬性來指定事務的傳播行為、隔離級別、超時時間、只讀等特性。
- 使用@Transactional註解:可以在需要事務管理的方法上添加@Transactional註解,Spring會自動管理該方法的事務。@Transactional註解可以指定事務的傳播行為、隔離級別、超時時間、只讀等特性。
Spring事務的傳播行為指的是當一個事務方法調用另外一個事務方法時,如何管理事務。Spring定義了七種傳播行為,包括:
- REQUIRED:如果當前存在事務,則加入該事務,否則創建一個新的事務。
- SUPPORTS:如果當前存在事務,則加入該事務,否則以非事務的方式執行。
- MANDATORY:必須在一個已有的事務中執行,否則拋出異常。
- REQUIRES_NEW:創建一個新的事務,並且暫停當前事務(如果存在)。
- NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,則暫停該事務。
- NEVER:以非事務方式執行操作,如果當前存在事務,則拋出異常。
- NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行REQUIRED類似的操作。
Spring事務的隔離級別指的是多個事務之間的隔離程度。Spring定義了五種隔離級別,包括:
- DEFAULT:使用底層資料庫的預設隔離級別。
- READ_UNCOMMITTED:允許臟讀、不可重覆讀和幻讀。
- READ_COMMITTED:禁止臟讀,但允許不可重覆讀和幻讀。
- REPEATABLE_READ:禁止臟讀和不可重覆讀,但允許幻讀。
- SERIALIZABLE:禁止臟讀、不可重覆讀和幻讀,最嚴格的隔離級別。
Spring事務的超時時間指的是事務的執行時間超過該時間時,事務將被回滾。Spring預設的事務超時時間為-1,表示事務沒有超時限制。只讀事務指的是事務中只讀取數據,不修改數據。只讀事務可以提高資料庫的併發性能。
可以使用@Transactional註解來指定事務的傳播行為、隔離級別、超時時間、只讀等特性。例如:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 3600, readOnly = false)
public void doSomething() {
// some code
}
在這個例子中,@Transactional註解指定了事務的傳播行為為REQUIRED、隔離級別為DEFAULT、超時時間為3600秒、只讀為false。
使用Spring事務管理可以提高應用程式的性能和可靠性。它可以確保在事務範圍內的所有操作要麼全部成功,要麼全部失敗,從而保持數據的完整性和一致性。
Spring事務的原理
Spring事務的實現原理是使用AOP技術。在Spring中,事務管理是通過將事務管理器和事務通知應用到目標方法上來實現的。事務管理器是負責管理事務的對象,事務通知是負責在目標方法執行前後開啟、提交或回滾事務的對象。在Spring中,事務通知是使用AspectJ的@Aspect註解來實現的。
當一個方法被標記為@Transactional時,Spring會創建一個代理對象來代理該方法。該代理對象會將目標方法的調用轉發給事務通知。在事務通知中,會根據事務管理器的配置來開啟、提交或回滾事務。如果方法執行過程中發生了異常,則會回滾事務。如果方法執行成功,則會提交事務。事務管理器會將事務的狀態存儲在ThreadLocal中,以便在同一線程中的其他方法也可以訪問該事務。
Spring事務的實現依賴於底層的資料庫事務。Spring提供了多種事務管理器,如DataSourceTransactionManager、HibernateTransactionManager等。事務管理器可以配置事務的傳播行為、隔離級別、超時時間、只讀等特性。
DataSourceTransactionManager的實現
DataSourceTransactionManager的實現主要包括以下內容:
- 實現了PlatformTransactionManager介面,用於管理事務的生命周期。PlatformTransactionManager介面是Spring事務管理器的核心介面,它定義了事務的生命周期和狀態轉換規則。DataSourceTransactionManager實現了PlatformTransactionManager介面,用於管理基於DataSource的事務。PlatformTransactionManager介面包括以下方法:
- getTransaction(TransactionDefinition definition):獲取一個新的事務或將當前線程中的事務加入到當前方法的事務中。
- commit(TransactionStatus status):提交當前事務。
- rollback(TransactionStatus status):回滾當前事務。
- 實現了TransactionDefinition介面,用於定義事務的傳播行為、隔離級別、超時時間、只讀等特性。TransactionDefinition介面定義了事務的屬性,包括傳播行為、隔離級別、超時時間、只讀等。DataSourceTransactionManager實現了TransactionDefinition介面,用於指定基於DataSource的事務的屬性。
- 實現了TransactionStatus介面,用於跟蹤事務的狀態。TransactionStatus介面定義了事務的狀態,包括未提交、已提交和已回滾。DataSourceTransactionManager實現了TransactionStatus介面,用於跟蹤基於DataSource的事務的狀態。
- 實現了TransactionSynchronizationManager類,用於管理事務的同步狀態。TransactionSynchronizationManager類用於管理事務的同步狀態,包括事務的開始、結束和回滾等操作。DataSourceTransactionManager使用TransactionSynchronizationManager類來管理基於DataSource的事務的同步狀態。
- 實現了TransactionAspectSupport類,用於支持基於AspectJ的事務通知。TransactionAspectSupport類是Spring事務管理的核心類,它實現了基於AspectJ的事務通知邏輯。DataSourceTransactionManager使用TransactionAspectSupport類來支持基於AspectJ的事務通知。
DataSourceTransactionManager的工作流程
- 當一個方法被標記為@Transactional時,Spring會創建一個代理對象來代理該方法。
- 代理對象會調用TransactionAspectSupport類的invokeWithinTransaction()方法,該方法會在事務的上下文中執行目標方法。
- 在invokeWithinTransaction()方法中,會調用DataSourceTransactionManager的doBegin()方法來開啟事務。
- 在doBegin()方法中,會獲取當前線程中的Connection對象,並將其設置為事務的連接。
- 如果當前線程中沒有Connection對象,則會從DataSource中獲取一個新的Connection對象,並將其設置為事務的連接。
- 如果事務的隔離級別不是預設值,則會將事務的隔離級別設置到Connection對象上。
- 如果事務的超時時間不是預設值,則會將事務的超時時間設置到Connection對象上。
- 在目標方法執行完畢後,會調用TransactionAspectSupport類的invokeWithinTransaction()方法的afterCompletion()方法來提交或回滾事務。
- 在afterCompletion()方法中,會調用DataSourceTransactionManager的doCleanupAfterCompletion()方法來清理事務狀態。
- 在doCleanupAfterCompletion()方法中,會將事務的連接關閉,並將其從當前線程中移除。
Spring不太常用的註解
- @Lazy:指定Bean是否延遲初始化。預設情況下,Spring會在容器啟動時創建所有的單例Bean,通過設置@Lazy註解可以將Bean的創建推遲到第一次使用時。這對於那些啟動時間較長的應用程式來說非常有用,可以提高應用程式的啟動速度。
- @DependsOn:指定Bean依賴的其他Bean。如果被依賴的Bean未被創建,則會先創建該Bean。@DependsOn註解可以用來控制Bean的創建順序,確保依賴的Bean在當前Bean之前被創建。
- @Primary:在多個Bean實現某個介面時,指定預設使用哪個Bean。當一個介面有多個實現類時,可以使用@Primary註解來指定預設使用哪個實現類。如果沒有指定@Primary註解,則需要使用@Qualifier註解來指定使用哪個實現類。
- @Qualifier:指定使用哪個Bean實現某個介面。當有多個Bean實現同一個介面時,可以使用@Qualifier註解來指定使用哪個Bean。@Qualifier註解需要與@Autowired註解一起使用,在註入Bean時指定使用哪個實現類。
- @Profile:指定Bean在特定的環境中才會被創建。可以使用@Profile註解來指定Bean在哪些環境下被創建,例如開發環境、測試環境或生產環境。
- @Value:從屬性文件中獲取Bean的屬性值。可以使用@Value註解來指定Bean的屬性值。@Value註解可以用來註入簡單類型的值,例如字元串、數字或布爾值。
- @RestController:將一個類聲明為RESTful Web服務的控制器。可以使用@RestController註解來將一個類聲明為RESTful Web服務的控制器,使其能夠處理HTTP請求並返回JSON或XML格式的數據。
- @ExceptionHandler:處理異常。可以使用@ExceptionHandler註解來處理Controller中的異常,當Controller中拋出異常時,會自動調用@ExceptionHandler註解中指定的方法來處理異常。
成功是一個長期的過程,需要不斷地努力和堅持。
- “成功的秘訣在於堅持,堅持,再堅持。”——張德芬
- “成功不是將來才有的,而是從決定去做的那一刻起,持續累積而成。”——阿斯頓·馬丁
- “只有在經歷了漫長跋涉之後,才能登上理想的山巔。”——菲茨傑拉德
- “成功的關鍵在於我們是否真正熱愛我們所做的事情,是否做到了最好。”——賀綠汀
- “成功者不是從不失敗,而是能夠從失敗中振作起來。”——喬治·愛德華·伯納德·肖
- “不要害怕失敗,失敗是通向成功的必經之路。”——邁克爾·喬丹
成功不是一蹴而就的,它需要我們一步一個腳印地向前走,不斷地嘗試和學習,不斷地改進和完善。在這個過程中,我們可能會遇到挫折和困難,但是只要我們保持信心和勇氣,堅持不懈地努力,最終我們一定會迎來成功的喜悅。