【Spring系列】- Bean生命週期底層原理
Bean生命週期底層原理
😄生命不息,寫作不止
🔥 繼續踏上學習之路,學之分享筆記
👊 總有一天我也能像各位大佬一樣
🌝分享學習心得,歡迎指正,大家一起學習成長!
前言
上次學到動手模擬Spring底層實現,簡單學習了一下Spring,對spring有所瞭解,接著就來分析spring中bean的生命週期的步步流程。
流程
接下來會根據Bean生命週期一步一步去學習,spring在建立bean物件的過程中,還是做了許多的操作,從依賴注入,通過初始化以及前後操作,最後建立了bean物件放入Map單例池,對於多例是不放進去的。
本次實驗使用的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物件。分別為{roleService、roleService1、roleService2}。這三個的型別一樣,但是物件是不同的,名字不同,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);
}
}
但是如果使用的不是上面三個其中之一,就會報錯。但是能看到他找到了三個。
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代理的物件
並且能看到裡面的roleService是沒有值的。但是從執行結果來看,先走了切面,最後的roleService是有值的。
然而這都是因為代理類是父子級關係來實現的。接下來一步一步分析。
spring通過代理物件,就是為了能夠先執行切面方法,在來執行原本物件的方法。首先,spring會生成一個物件:UserServiceProxy,這個就是UserService物件的代理物件。我們用java面向物件思想來思考,代理物件會繼承UserService類,他內部重寫了父類的test方法,在裡面去執行切面的邏輯,接著通過super.test呼叫父類方法。這個方法雖然是可以實現,但是在spring中卻不是這樣的。
在Spring中,代理物件裡面還會定義一個父類物件UserService target,這個物件最終會賦值這個類生成的物件,也就是bean生命週期最開始遇到的那個物件。Spring通過呼叫target.test()實現。說白了還是使用了最原來的那個物件去執行的方法。
本文正在參加「金石計劃 . 瓜分6萬現金大獎」
👍創作不易,如有錯誤請指正,感謝觀看!記得點贊哦!👍