Spring原始碼簡易手寫實現(學習過程記錄)(四)
阿新 • • 發佈:2021-10-27
4.1Aware回撥模擬實現
在createBean的時候,我們想在加了Component註解的類裡面加一個欄位beanName,該欄位儲存bean物件的name屬性
spring會提供一個介面BeanNameAware來實現
package com.rainwood.spring;
public interface BeanNameAware {
void setBeanName(String name);
}
我們在UserService類裡可以繼承該介面重寫setBeanName方法
package com.rainwood.liming.service; import com.rainwood.spring.*; @Component("userService") //@Scope("prototype") public class UserService implements BeanNameAware{ @Autowired private OrderService orderService; private String beanName; public void test() { System.out.println(orderService); System.out.println(beanName); } @Override public void setBeanName(String name) { beanName = name; } }
設想如果沒有setBeanName方法的話,在自動注入時候,僅有一個beanName欄位是無法將Bean的name屬性傳進來賦給beanName
我們這裡利用set方法,在spring容器createBean方法中呼叫setBean方法就可以實現將beanName傳入。
public Object createBean(String beanName, BeanDefination beanDefination) { Class clazz = beanDefination.getClazz(); try { //首先看getDeclaredConstructor(Class<?>... parameterTypes) //這個方法會返回制定引數型別的所有構造器,包括public的和非public的,當然也包括private的。 //getDeclaredConstructors()的返回結果就沒有引數型別的過濾了。 Object instance = clazz.getDeclaredConstructor().newInstance(); //依賴注入 //getDeclaredFields():獲得某個類的所有宣告的欄位,即包括public、private和proteced,但是不包括父類的申明欄位。 for (Field declaredField : clazz.getDeclaredFields()) { if(declaredField.isAnnotationPresent(Autowired.class)) { //spring在依賴注入時候會去是spring容器池裡去根據型別和名字來找對應的bean //這裡我們簡化用名字來找 Object bean = getBean(declaredField.getName()); declaredField.setAccessible(true);//功能是啟用或禁用安全檢查 declaredField.set(instance, bean); } } //Aware回撥 //判斷instance是否實現了BeanNameAware介面,如果實現了就呼叫setBeanName將當前bean的名字beanName傳進去 if(instance instanceof BeanNameAware) { ((BeanNameAware)instance).setBeanName(beanName); } return instance; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return null; }
我們和之前不同,我們在createBean時候,再加一個引數beanName傳入createBean方法,
//Aware回撥
//判斷instance是否實現了BeanNameAware介面,如果實現了就呼叫setBeanName將當前bean的名字beanName傳進去
if(instance instanceof BeanNameAware) {
((BeanNameAware)instance).setBeanName(beanName);
}
檢驗instance物件是否是繼承了BeanNameAware介面,如果繼承了,就可以利用重寫的setBeanName方法將beanName注入進去
4.2初始化模擬實現
和Aware回撥類似,我們需要一個InitializingBean介面,該介面有afterPropertiesSet方法
package com.rainwood.spring;
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
讓UserService繼承InitializingBean
package com.rainwood.liming.service;
import com.rainwood.spring.*;
@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware, InitializingBean {
@Autowired
private OrderService orderService;
private String beanName;
public void test() {
System.out.println(orderService);
System.out.println(beanName);
}
@Override
public void setBeanName(String name) {
beanName = name;
}
//初始化時候呼叫這個方法想做啥就做啥
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化");
}
}
同樣的在createBean的時候
//初始化
if(instance instanceof InitializingBean) {
try {
((InitializingBean)instance).afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
}
繼續判斷instance是否繼承了InitializingBean介面
繼承了的話就呼叫afterPropertiesSet方法進行各種初始化操作