共计 3138 个字符,预计需要花费 8 分钟才能阅读完成。
本文节选自《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 的外围局部。“小伙伴们”是不是发现其实还是很简略的?
正文完