此文章來源于SnailClimb @https://mp.weixin.qq.com/s/yaY3gcP0aEp7w-mUwl1yCQ
IOC
IoC(Inverse of Control:控制反轉(zhuǎn))是一種設(shè)計思想活逆,就是 將原本在程序中手動創(chuàng)建對象的控制權(quán),交由Spring框架來管理。 IoC 在其他語言中也有應(yīng)用缩歪,并非 Spirng 特有。 IoC 容器是 Spring 用來實現(xiàn) IoC 的載體, IoC 容器實際上就是個Map(key,value),Map 中存放的是各種對象殴俱。
將對象之間的相互依賴關(guān)系交給 IoC 容器來管理,并由 IoC 容器完成對象的注入枚抵。這樣可以很大程度上簡化應(yīng)用的開發(fā)线欲,把應(yīng)用從復(fù)雜的依賴關(guān)系中解放出來。 IoC 容器就像是一個工廠一樣汽摹,當(dāng)我們需要創(chuàng)建一個對象的時候李丰,只需要配置好配置文件/注解即可,完全不用考慮對象是如何被創(chuàng)建出來的逼泣。 在實際項目中一個 Service 類可能有幾百甚至上千個類作為它的底層趴泌,假如我們需要實例化這個 Service舟舒,你可能要每次都要搞清這個 Service 所有底層類的構(gòu)造函數(shù),這可能會把人逼瘋嗜憔。如果利用 IoC 的話秃励,你只需要配置好,然后在需要的地方引用就行了吉捶,這大大增加了項目的可維護(hù)性且降低了開發(fā)難度夺鲜。
Spring 時代我們一般通過 XML 文件來配置 Bean,后來開發(fā)人員覺得 XML 文件來配置不太好呐舔,于是 SpringBoot 注解配置就慢慢開始流行起來币励。
推薦閱讀:https://www.zhihu.com/question/23277575/answer/169698662
IoC源碼閱讀 https://javadoop.com/post/spring-ioc
AOP
Spring AOP就是基于動態(tài)代理的,如果要代理的對象珊拼,實現(xiàn)了某個接口食呻,那么Spring AOP會使用JDK Proxy,去創(chuàng)建代理對象澎现,而對于沒有實現(xiàn)接口的對象仅胞,就無法使用 JDK Proxy 去進(jìn)行代理了,這時候Spring AOP會使用Cglib 昔头,這時候Spring AOP會使用 Cglib 生成一個被代理對象的子類來作為代理饼问,如下圖所示:
當(dāng)然你也可以使用 AspectJ ,Spring AOP 已經(jīng)集成了AspectJ 影兽,AspectJ 應(yīng)該算的上是 Java 生態(tài)系統(tǒng)中最完整的 AOP 框架了揭斧。
使用 AOP 之后我們可以把一些通用功能抽象出來,在需要用到的地方直接使用即可峻堰,這樣大大簡化了代碼量讹开。我們需要增加新功能時也方便,這樣也提高了系統(tǒng)擴(kuò)展性捐名。日志功能旦万、事務(wù)管理等等場景都用到了 AOP 。
Spring AOP 和 AspectJ AOP 有什么區(qū)別镶蹋?
Spring AOP 屬于運行時增強(qiáng)成艘,而 AspectJ 是編譯時增強(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 相對來說更簡單,
如果我們的切面比較少婶熬,那么兩者性能差異不大剑勾。但是埃撵,當(dāng)切面太多的話,最好選擇 AspectJ 虽另,它比Spring AOP 快很多暂刘。
Spring 中的 bean 生命周期
這部分網(wǎng)上有很多文章都講到了,下面的內(nèi)容整理自:https://yemengying.com/2016/07/14/spring-bean-life-cycle/ 洲赵,除了這篇文章鸳惯,再推薦一篇很不錯的文章 :https://www.cnblogs.com/zrtqsk/p/3735273.html 。
- Bean 容器找到配置文件中 Spring Bean 的定義叠萍。
- Bean 容器利用 Java Reflection API 創(chuàng)建一個Bean的實例芝发。
- 如果涉及到一些屬性值 利用 set()方法設(shè)置一些屬性值。
- 如果 Bean 實現(xiàn)了 BeanNameAware 接口苛谷,調(diào)用 setBeanName()方法辅鲸,傳入Bean的名字。
- 如果 Bean 實現(xiàn)了 BeanClassLoaderAware 接口腹殿,調(diào)用 setBeanClassLoader()方法独悴,傳入 ClassLoader對象的實例。
- 如果Bean實現(xiàn)了 BeanFactoryAware 接口锣尉,調(diào)用 setBeanClassLoader()方法刻炒,傳入 ClassLoade r對象的實例。
與上面的類似自沧,如果實現(xiàn)了其他 *.Aware接口坟奥,就調(diào)用相應(yīng)的方法。 - 如果有和加載這個 Bean 的 Spring 容器相關(guān)的 BeanPostProcessor 對象拇厢,執(zhí)行postProcessBeforeInitialization() 方法
- 如果Bean實現(xiàn)了InitializingBean接口爱谁,執(zhí)行afterPropertiesSet()方法。
- 如果 Bean 在配置文件中的定義包含 init-method 屬性孝偎,執(zhí)行指定的方法访敌。
- 如果有和加載這個 Bean的 Spring 容器相關(guān)的 BeanPostProcessor 對象,執(zhí)行postProcessAfterInitialization() 方法
- 當(dāng)要銷毀 Bean 的時候衣盾,如果 Bean 實現(xiàn)了 DisposableBean 接口寺旺,執(zhí)行 destroy() 方法。
-
當(dāng)要銷毀 Bean 的時候势决,如果 Bean 在配置文件中的定義包含 destroy-method 屬性阻塑,執(zhí)行指定的方法。
Spring 框架中用到了哪些設(shè)計模式
關(guān)于下面一些設(shè)計模式的詳細(xì)介紹徽龟,可以看筆主前段時間的原創(chuàng)文章《面試官:“談?wù)凷pring中都用到了那些設(shè)計模式?”叮姑。》 。
工廠設(shè)計模式 : Spring使用工廠模式通過
BeanFactory
传透、ApplicationContext
創(chuàng)建 bean 對象耘沼。代理設(shè)計模式 : Spring AOP 功能的實現(xiàn)。
單例設(shè)計模式 : Spring 中的 Bean 默認(rèn)都是單例的朱盐。
模板方法模式 : Spring 中
jdbcTemplate
群嗤、hibernateTemplate
等以 Template 結(jié)尾的對數(shù)據(jù)庫操作的類,它們就使用到了模板模式兵琳。包裝器設(shè)計模式 : 我們的項目需要連接多個數(shù)據(jù)庫狂秘,而且不同的客戶在每次訪問中根據(jù)需要會去訪問不同的數(shù)據(jù)庫。這種模式讓我們可以根據(jù)客戶的需求能夠動態(tài)切換不同的數(shù)據(jù)源躯肌。
觀察者模式: Spring 事件驅(qū)動模型就是觀察者模式很經(jīng)典的一個應(yīng)用者春。
適配器模式 :Spring AOP 的增強(qiáng)或通知(Advice)使用到了適配器模式、spring MVC 中也是用到了適配器模式適配
Controller
清女。
@Component 和 @Bean 的區(qū)別是什么钱烟?
- 作用對象不同: @Component 注解作用于類,而@Bean注解作用于方法嫡丙。
- @Component通常是通過類路徑掃描來自動偵測以及自動裝配到Spring容器中(我們可以使用 - - -- @ComponentScan 注解定義要掃描的路徑從中找出標(biāo)識了需要裝配的類自動裝配到 Spring 的 bean 容器中)拴袭。@Bean 注解通常是我們在標(biāo)有該注解的方法中定義產(chǎn)生這個 bean,@Bean告訴了Spring這是某個類的示例,當(dāng)我需要用它的時候還給我曙博。
- @Bean 注解比 Component 注解的自定義性更強(qiáng)拥刻,而且很多地方我們只能通過 @Bean 注解來注冊bean。比如當(dāng)我們引用第三方庫中的類需要裝配到 Spring容器時父泳,則只能通過 @Bean來實現(xiàn)般哼。
@Bean注解使用示例:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
上面的代碼相當(dāng)于下面的 xml 配置
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
下面這個例子是通過 @Component 無法實現(xiàn)的。
@Bean
public OneService getService(status) {
case (status) {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();
}
}
Spring 事務(wù)中的隔離級別有哪幾種
TransactionDefinition 接口中定義了五個表示隔離級別的常量:
- TransactionDefinition.ISOLATION_DEFAULT: 使用后端數(shù)據(jù)庫默認(rèn)的隔離級別尘吗,Mysql 默認(rèn)采用的 REPEATABLE_READ隔離級別 Oracle 默認(rèn)采用的 READ_COMMITTED隔離級別.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級別逝她,允許讀取尚未提交的數(shù)據(jù)變更浇坐,可能會導(dǎo)致臟讀睬捶、幻讀或不可重復(fù)讀
- TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀近刘,但是幻讀或不可重復(fù)讀仍有可能發(fā)生
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一字段的多次讀取結(jié)果都是一致的擒贸,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀觉渴,但幻讀仍有可能發(fā)生介劫。
- TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別案淋。所有的事務(wù)依次逐個執(zhí)行座韵,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級別可以防止臟讀誉碴、不可重復(fù)讀以及幻讀宦棺。但是這將嚴(yán)重影響程序的性能。通常情況下也不會用到該級別黔帕。
Spring 事務(wù)中哪幾種事務(wù)傳播行為?
支持當(dāng)前事務(wù)的情況:
TransactionDefinition.PROPAGATION_REQUIRED: 如果當(dāng)前存在事務(wù)代咸,則加入該事務(wù);如果當(dāng)前沒有事務(wù)成黄,則創(chuàng)建一個新的事務(wù)呐芥。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果當(dāng)前存在事務(wù),則加入該事務(wù)奋岁;如果當(dāng)前沒有事務(wù)思瘟,則以非事務(wù)的方式繼續(xù)運行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果當(dāng)前存在事務(wù)闻伶,則加入該事務(wù)潮太;如果當(dāng)前沒有事務(wù),則拋出異常虾攻。(mandatory:強(qiáng)制性)
不支持當(dāng)前事務(wù)的情況:TransactionDefinition.PROPAGATION_REQUIRES_NEW: 創(chuàng)建一個新的事務(wù)铡买,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起霎箍。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務(wù)方式運行奇钞,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起漂坏。
TransactionDefinition.PROPAGATION_NEVER: 以非事務(wù)方式運行景埃,如果當(dāng)前存在事務(wù),則拋出異常顶别。
其他情況:TransactionDefinition.PROPAGATION_NESTED: 如果當(dāng)前存在事務(wù)谷徙,則創(chuàng)建一個事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運行;如果當(dāng)前沒有事務(wù)驯绎,則該取值等價于TransactionDefinition.PROPAGATION_REQUIRED完慧。