写点什么

30 个类手写 Spring 核心原理之依赖注入功能(3)

作者:Tom弹架构
  • 2021 年 12 月 12 日
  • 本文字数:2454 字

    阅读完需:约 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 的核心部分。“小伙伴们”是不是发现其实还是很简单的?


关注微信公众号『 Tom 弹架构 』回复“Spring”可获取完整源码。


本文为“Tom 弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom 弹架构 』可获取更多技术干货!


原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!

发布于: 1 小时前阅读数: 5
用户头像

Tom弹架构

关注

不只做一个技术者,更要做一个思考者 2021.10.22 加入

畅销书作者,代表作品:《Spring 5核心原理》、《Netty 4核心原理》、《设计模式就该这样学》

评论

发布
暂无评论
30个类手写Spring核心原理之依赖注入功能(3)