深入探究Spring底層核心原理
Spring底層核心原理
下面這幾行代碼是一個Spring的入門代碼,第一行是通過java配置類 注解的方式創(chuàng)建一個Spring容器,第二行是通過XML配置文件的方式創(chuàng)建一個Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (UserService) context.getBean("userService"); userService.test();
最后兩行代碼就是從Spring容器中拿一個Bean對象并執(zhí)行方法。那么Spring是如何創(chuàng)建一個Bean對象的嘞?
Bean的生命周期
- 推斷構(gòu)造方法,并執(zhí)行得到普通對象
- 依賴注入
- aware回調(diào)
- 初始化前
執(zhí)行BeanPostProcessor
接口中的postProcessBeforeInitialization()
方法
- 初始化
執(zhí)行有@PostConstruct
注解的方法執(zhí)行
InitializingBean
接口中的afterPropertiesSet()
方法
執(zhí)行XML配置文件中init-method
屬性指定的方法
- 初始化后
執(zhí)行BeanPostProcessor
接口中的postProcessAfterInitialization()
方法
- 普通對象/代理對象 存入容器中
- 使用
- 銷毀
執(zhí)行DisposableBean
接口的destroy()
方法
有@PreDestroy
注解的方法
XML 配置文件中destroy-method
屬性指定的方法
推斷構(gòu)造方法
如果沒有寫構(gòu)造方法,那么Spring會執(zhí)行默認空參的構(gòu)造方法
如果顯示寫了一個構(gòu)造方法,那么Spring就會使用這個構(gòu)造方法,構(gòu)造方法中如果有參數(shù)那么會進行依賴注入
如果顯示寫了多個構(gòu)造方法并有空參的構(gòu)造方法時,會執(zhí)行空參的構(gòu)造方法
如果顯示寫了多個構(gòu)造方法沒有空參的構(gòu)造方法時,運行時會報錯。解決方法是在要執(zhí)行的構(gòu)造方法上加@Autowired
注解
AOP原理
cjlib和jdk兩種動態(tài)代理的實現(xiàn)都是有一個target屬性來存儲普通對象,代理對象中重寫要執(zhí)行的方法,首先執(zhí)行增強邏輯,然后通過target屬性去執(zhí)行目標(biāo)方法。偽代碼如下:
public class UserServiceProxy extends UserService{ private UserService target; public void test(){ // TODO 增強業(yè)務(wù) target.test(); // TODO 增強業(yè)務(wù) } }
那么如何判斷一個Bean是否需要進行AOP創(chuàng)建一個普通對象嘞?
- 遍歷所有有
@Aspect
注解的切面Bean - 遍歷所有的方法
- 判斷方法上的切點表達式是否和當(dāng)前正在創(chuàng)建的Bean匹配
- 如果匹配則把這個切面中增強方法存入一個Map緩存中
真正要執(zhí)行代理對象的方法時會從緩存中取出相應(yīng)的增強邏輯來執(zhí)行,再去執(zhí)行目標(biāo)方法。
Spring事務(wù)
Spring中如果要使用事務(wù)需要配置一個JdbcTemplate和一個事務(wù)管理器,它們倆都需要配置DataSource。
@ComponentScan("com.hs") @Configuration public class AppConfig { @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } @Bean public PlatformTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/hs?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"); dataSource.setUsername("root"); dataSource.setPassword("123456"); return dataSource; } }
Spring事務(wù)大致執(zhí)行流程如下:
- 判斷要執(zhí)行的方法上是否存在
@Transcational
注解 - 如果存在則通過事務(wù)管理器創(chuàng)建一個connection連接對象
- autoCommit設(shè)置為false
- 去執(zhí)行目標(biāo)方法target.method()
- 如果出現(xiàn)了異常則回滾rollback(),沒有異常則提交commit()
如果上面的配置類中不加@Configuration
注解,那么Spring的事務(wù)會失效。原因如下:
JdbcTemplate和事務(wù)管理器都需要DataSource,都會調(diào)用dataSource()
獲取。如果不加@Configuration
注解,那么他們倆獲取的DataSource就不是同一個。
代理對象中操作的是事務(wù)管理器的連接對象,而業(yè)務(wù)方法卻是使用的JdbcTemplate,所以就導(dǎo)致了Spring事務(wù)失效。
而如果加上了@Configuration
注解,在調(diào)用dataSource()
時會先去Spring容器中找DataSource,如果沒找到才回去調(diào)用方法創(chuàng)建一個。
到此這篇關(guān)于深入探究Spring底層核心原理的文章就介紹到這了,更多相關(guān)Spring底層原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中如何解決讀取properties文件讀取問題
這篇文章主要介紹了SpringBoot中如何解決讀取properties文件讀取問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Java數(shù)據(jù)結(jié)構(gòu)之樹和二叉樹的相關(guān)資料
這篇文章主要介紹了Java?數(shù)據(jù)結(jié)構(gòu)之樹和二叉樹相關(guān)資料,文中通過示例代碼和一些相關(guān)題目來做介紹,非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下!2023-01-01Java數(shù)據(jù)結(jié)構(gòu)之LinkedList的用法詳解
鏈表(Linked?list)是一種常見的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),是一種線性表。Java的LinkedList(鏈表)?類似于?ArrayList,是一種常用的數(shù)據(jù)容器,本文就來簡單講講它的使用吧2023-05-05Java中final關(guān)鍵字的使用與注意總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中final關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08