【Spring系列】- Bean生命周期底層原理
Bean生命周期底層原理
😄生命不息,寫作不止
🔥 繼續踏上學習之路,學之分享筆記
👊 總有一天我也能像各位大佬一樣
🏆 一個有夢有戲的人 @怒放吧德德
🌝分享學習心得,歡迎指正,大家一起學習成長!
前言
上次學到動手模擬Spring底層實現,簡單學習了一下Spring,對spring有所了解,接著就來分析spring中bean的生命周期的步步流程。
流程
接下來會根據Bean生命周期一步一步去學習,spring在創建bean對象的過程中,還是做了許多的操作,從依賴注入,通過初始化以及前後操作,最後創建了bean對象放入Map單例池,對於多例是不放進去的。
本次實驗使用的pom依賴坐標如下
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.15</version>
</dependency>
依賴注入
首先是根據無參構造方法去獲取對象,通過這個類獲取所有欄位,在來判斷是否有Autowired註解,在給這個屬性去賦值。
UserService userService1 = new UserService();
for (Field field : userService1.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.set(userService1, ???);
}
}
初始化前執行方法
通過對象獲取所有方法,我們在需要執行的方法上使用PostConstruct註解,然後就只需要遍歷這些方法,去判斷是否含有這個註解,在使用invoke去執行方法。
for (Method method : userService1.getClass().getMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
method.invoke(userService1, null);
}
}
初始化
除了使用PostConstruct註解去執行方法,還有一種方法是通過去實現InitializingBean介面,並且需要實現其未實現的方法afterPropertiesSet。
那麼對象是如何知道在spring中會有afterPropertiesSet這個方法呢?可以通過反射判斷是否有這個方法,有的話就直接執行。在spring中,他是採用去判斷對象是否有實現InitializingBean這個類,有的話會強轉成這個類,再去執行這個類的方法
推斷構造方法底層原理
如果有多個構造方法,回去尋找是否有無參的,找到了,就直接使用,沒找到就會報錯。如果是使用了多個構造方法,可以使用Autowired去告訴spring需要使用那個構造方法。如果在構造方法里需要一個bean對象,那麼spring會去map單例池中去查找相應的bean對象,如果沒找到,就會去創建bean對象,但如果是多例bean的話,就不需要查找,直接創建一個對象。
當我們使用構造方法獲取bean對象時,一般是通過類上使用Component註解去定義一個首位字母小寫的bean對象,也可以是通過Bean註解,去創建不同bean名的相同類型的bean對象。
如下程式碼,在配置中添加兩個bean對象,包括類上自己生成的一共三個bean對象。分別為{roleService、roleService1、roleService2}。這三個的類型一樣,但是對象是不同的,名字不同,bean對象就不同。
@ComponentScan("com.lyd")
public class ApplicationConfig {
@Bean
public RoleService roleService1() {
return new RoleService();
}
@Bean
public RoleService roleService2() {
return new RoleService();
}
}
當使用其中一個beanName都是可以的
@Component
public class UserService {
private RoleService roleService;
public UserService(RoleService roleService1) {
this.roleService = roleService1;
}
public void test(){
System.out.println(roleService);
}
}
但是如果使用的不是上面三個其中之一,就會報錯。但是能看到他找到了三個。
AOP – 動態代理
使用AOP就是需要使用代理對象,然而代理對象與第一次的對象是不一樣的。
首先定義一個aop切面
@Aspect
@Component
public class AopAspect {
@Before("execution(public void com.lyd.service.UserService.test())")
public void beanBefore(JoinPoint joinPoint) {
System.out.println("before");
}
}
在配置類中標上註解 @EnableAspectJAutoProxy 開啟切面,這樣切面就會實現了。再來debug調用userService的test方法,可以觀察到,獲得的對象是CGLIB代理的對象
並且能看到裡面的roleService是沒有值的。但是從運行結果來看,先走了切面,最後的roleService是有值的。
然而這都是因為代理類是父子級關係來實現的。接下來一步一步分析。
spring通過代理對象,就是為了能夠先執行切面方法,在來執行原本對象的方法。首先,spring會生成一個對象:UserServiceProxy,這個就是UserService對象的代理對象。我們用java面向對象思想來思考,代理對象會繼承UserService類,他內部重寫了父類的test方法,在裡面去執行切面的邏輯,接著通過super.test調用父類方法。這個方法雖然是可以實現,但是在spring中卻不是這樣的。
在Spring中,代理對象裡面還會定義一個父類對象UserService target,這個對象最終會賦值這個類生成的對象,也就是bean生命周期最開始遇到的那個對象。Spring通過調用target.test()實現。說白了還是使用了最原來的那個對象去執行的方法。
👍創作不易,如有錯誤請指正,感謝觀看!記得點贊哦!👍