【Spring系列】- Bean生命週期底層原理

語言: CN / TW / HK

Bean生命週期底層原理

😄生命不息,寫作不止

🔥 繼續踏上學習之路,學之分享筆記

👊 總有一天我也能像各位大佬一樣

🏆 一個有夢有戲的人 @怒放吧德德

🌝分享學習心得,歡迎指正,大家一起學習成長!

bean.jpg

前言

上次學到動手模擬Spring底層實現,簡單學習了一下Spring,對spring有所瞭解,接着就來分析spring中bean的生命週期的步步流程。

流程

接下來會根據Bean生命週期一步一步去學習,spring在創建bean對象的過程中,還是做了許多的操作,從依賴注入,通過初始化以及前後操作,最後創建了bean對象放入Map單例池,對於多例是不放進去的。

image.png

本次實驗使用的pom依賴座標如下

xml <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註解,在給這個屬性去賦值。

java UserService userService1 = new UserService(); for (Field field : userService1.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { field.set(userService1, ???); } }

初始化前執行方法

通過對象獲取所有方法,我們在需要執行的方法上使用PostConstruct註解,然後就只需要遍歷這些方法,去判斷是否含有這個註解,在使用invoke去執行方法。

java 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對象。分別為{roleServiceroleService1roleService2}。這三個的類型一樣,但是對象是不同的,名字不同,bean對象就不同。

```java @ComponentScan("com.lyd") public class ApplicationConfig {

@Bean
public RoleService roleService1() {
    return new RoleService();
}

@Bean
public RoleService roleService2() {
    return new RoleService();
}

} ``` 當使用其中一個beanName都是可以的

java @Component public class UserService { private RoleService roleService; public UserService(RoleService roleService1) { this.roleService = roleService1; } public void test(){ System.out.println(roleService); } } 但是如果使用的不是上面三個其中之一,就會報錯。但是能看到他找到了三個。 image.png

AOP - 動態代理

使用AOP就是需要使用代理對象,然而代理對象與第一次的對象是不一樣的。 首先定義一個aop切面

java @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代理的對象 image.png 並且能看到裏面的roleService是沒有值的。但是從運行結果來看,先走了切面,最後的roleService是有值的。 image.png 然而這都是因為代理類是父子級關係來實現的。接下來一步一步分析。 image.png        spring通過代理對象,就是為了能夠先執行切面方法,在來執行原本對象的方法。首先,spring會生成一個對象:UserServiceProxy,這個就是UserService對象的代理對象。我們用java面向對象思想來思考,代理對象會繼承UserService類,他內部重寫了父類的test方法,在裏面去執行切面的邏輯,接着通過super.test調用父類方法。這個方法雖然是可以實現,但是在spring中卻不是這樣的。 image.png

在Spring中,代理對象裏面還會定義一個父類對象UserService  target,這個對象最終會賦值這個類生成的對象,也就是bean生命週期最開始遇到的那個對象。Spring通過調用target.test()實現。説白了還是使用了最原來的那個對象去執行的方法。

image.png

本文正在參加「金石計劃 . 瓜分6萬現金大獎」

👍創作不易,如有錯誤請指正,感謝觀看!記得點贊哦!👍