本文節選自《Spring 5核心原理》
在之前的原始碼分析中我們已經瞭解到,依賴注入(DI)的入口是getBean()方法,前面的IoC手寫部分基本流程已通。先在GPApplicationContext中定義好IoC容器,然後將GPBeanWrapper物件儲存到Map中。在GPApplicationContext中設計兩個Map:factoryBeanObjectCache儲存單例物件的快取,factoryBeanInstanceCache儲存GPBeanWrapper的快取,變數命名也和原生Spring一致,這兩個物件的設計其實就是註冊式單例模式的經典應用。
public class GPApplicationContext extends GPDefaultListableBeanFactory implements GPBeanFactory {
private String [] configLocations;
private GPBeanDefinitionReader reader;
//用來保證註冊式單例的容器
private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();
//用來儲存所有的被代理過的物件
private Map<String,GPBeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<String, GPBeanWrapper>();
...
}
1 從getBean()方法開始
下面我們從完善getBean()方法開始:
@Override
public Object getBean(String beanName) {
GPBeanDefinition beanDefinition = super.beanDefinitionMap.get(beanName);
try{
//生成通知事件
GPBeanPostProcessor beanPostProcessor = new GPBeanPostProcessor();
Object instance = instantiateBean(beanDefinition);
if(null == instance){ return null;}
//在例項初始化以前呼叫一次
beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
GPBeanWrapper beanWrapper = new GPBeanWrapper(instance);
this.factoryBeanInstanceCache.put(beanName,beanWrapper);
//在例項初始化以後呼叫一次
beanPostProcessor.postProcessAfterInitialization(instance,beanName);
populateBean(beanName,instance);
//通過這樣呼叫,相當於給我們自己留有了可操作的空間
return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance();
}catch (Exception e){
// e.printStackTrace();
return null;
}
}
2 instantiateBean()方法反射建立例項
//傳一個BeanDefinition,就返回一個例項Bean
private Object instantiateBean(GPBeanDefinition beanDefinition){
Object instance = null;
String className = beanDefinition.getBeanClassName();
try{
//因為根據Class才能確定一個類是否有例項
if(this.factoryBeanObjectCache.containsKey(className)){
instance = this.factoryBeanObjectCache.get(className);
}else{
Class<?> clazz = Class.forName(className);
instance = clazz.newInstance();
this.factoryBeanObjectCache.put(beanDefinition.getFactoryBeanName(),instance);
}
return instance;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
3 populateBean()方法完成依賴注入
private void populateBean(String beanName,Object instance){
Class clazz = instance.getClass();
if(!(clazz.isAnnotationPresent(GPController.class) ||
clazz.isAnnotationPresent(GPService.class))){
return;
}
Field [] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(GPAutowired.class)){ continue; }
GPAutowired autowired = field.getAnnotation(GPAutowired.class);
String autowiredBeanName = autowired.value().trim();
if("".equals(autowiredBeanName)){
autowiredBeanName = field.getType().getName();
}
field.setAccessible(true);
try {
field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName). getWrappedInstance());
} catch (IllegalAccessException e) {
// e.printStackTrace();
}
}
}
4 GPBeanPostProcessor後置處理器
原生Spring中的BeanPostProcessor是為物件初始化事件設定的一種回撥機制。這個Mini版本中只做說明,不做具體實現,感興趣的“小夥伴”可以繼續深入研究Spring原始碼。
package com.tom.spring.formework.beans.config;
public class GPBeanPostProcessor {
//為在Bean的初始化之前提供回撥入口
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
//為在Bean的初始化之後提供回撥入口
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return bean;
}
}
至此,DI部分就手寫完成了,也就是說完成了Spring的核心部分。“小夥伴們”是不是發現其實還是很簡單的?
本文為“Tom彈架構”原創,轉載請註明出處。技術在於分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支援是我堅持創作的動力。
原創不易,堅持很酷,都看到這裡了,小夥伴記得點贊、收藏、在看,一鍵三連加關注!如果你覺得內容太乾,可以分享轉發給朋友滋潤滋潤!