30个类手写Spring核心原理之依赖注入功能(3)
本文节选自《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弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!
30个类手写Spring核心原理之依赖注入功能(3)的更多相关文章
- 30个类手写Spring核心原理之MVC映射功能(4)
本文节选自<Spring 5核心原理> 接下来我们来完成MVC模块的功能,应该不需要再做说明.Spring MVC的入口就是从DispatcherServlet开始的,而前面的章节中已完成 ...
- 30个类手写Spring核心原理之动态数据源切换(8)
本文节选自<Spring 5核心原理> 阅读本文之前,请先阅读以下内容: 30个类手写Spring核心原理之自定义ORM(上)(6) 30个类手写Spring核心原理之自定义ORM(下)( ...
- 30个类手写Spring核心原理之环境准备(1)
本文节选自<Spring 5核心原理> 1 IDEA集成Lombok插件 1.1 安装插件 IntelliJ IDEA是一款非常优秀的集成开发工具,功能强大,而且插件众多.Lombok是开 ...
- 30个类手写Spring核心原理之AOP代码织入(5)
本文节选自<Spring 5核心原理> 前面我们已经完成了Spring IoC.DI.MVC三大核心模块的功能,并保证了功能可用.接下来要完成Spring的另一个核心模块-AOP,这也是最 ...
- 30个类手写Spring核心原理之自定义ORM(上)(6)
本文节选自<Spring 5核心原理> 1 实现思路概述 1.1 从ResultSet说起 说到ResultSet,有Java开发经验的"小伙伴"自然最熟悉不过了,不过 ...
- 30个类手写Spring核心原理之Ioc顶层架构设计(2)
本文节选自<Spring 5核心原理> 1 Annotation(自定义配置)模块 Annotation的代码实现我们还是沿用Mini版本的,保持不变,复制过来便可. 1.1 @GPSer ...
- 手写web框架之实现依赖注入功能
我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...
- 手写webpack核心原理,再也不怕面试官问我webpack原理
手写webpack核心原理 目录 手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6 ...
- Spring读书笔记-----Spring核心机制:依赖注入
spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入.今天就和大家一起来学习一下 依赖注入的基本概念 依赖注入(Dependecy Injection),也称为IoC(I ...
随机推荐
- feignclient各种使用技巧说明
FeignClient常见用法 常规的FeignClient的创建与使用我相信只要使用过spring cloud全家桶的套件的基本上都是非常熟悉了,我们只需定义一个interface,然后定义相关的远 ...
- 容器安全产品Aqua调研
前言 近年来,随着云计算的发展,企业数字化的进程不断加快,业务纷纷开始上云,云原生的概念最近两年也是十分火热,在新业务场景下也随之产生了新的安全问题,如k8s安全.devsecops.微服务安全.Se ...
- 《手把手教你》系列技巧篇(四十四)-java+ selenium自动化测试-处理https 安全问题或者非信任站点-下篇(详解教程)
1.简介 这一篇宏哥主要介绍webdriver在IE.Chrome和Firefox三个浏览器上处理不信任证书的情况,我们知道,有些网站打开是弹窗,SSL证书不可信任,但是你可以点击高级选项,继续打 ...
- Ubuntu文件系统结构
/bin: bin是Binary的缩写.存放系统中最常用的可执行文件(二进制). /boot: 这里存放的是linux内核和系统启动文件,包括Grub.lilo启动器程序. /dev: dev是Dev ...
- spring boot 动态生成接口实现类
目录 一: 定义注解 二: 建立动态代理类 三: 注入spring容器 四: 编写拦截器 五: 新建测试类 在某些业务场景中,我们只需要业务代码中定义相应的接口或者相应的注解,并不需要实现对应的逻辑. ...
- Linux——基础命令用法(上)
一.Linux基础命令 1.Linux命令行的格式 命令行的格式为:用户名+主机名+当前工作目录 输入内容的命令格式为:命令 [-短选项/--长选项] [参数] [root@localhost ~]# ...
- Navicat 激活教程2021(Linux)
Navicat 激活教程2021(Linux) 目录 背景 环境 激活 清理 使用 背景 Navicat 是香港卓软数字科技有限公司生产的一系列 MySQL.MariaDB.MongoDB.Oracl ...
- 学习资源 Docker从入门到实践 pdf ,docker基础总结导图
学习资源 Docker从入门到实践 pdf ,docker基础总结导图 Docker从入门到实践 pdf 云盘地址:https://pan.baidu.com/s/1vYyxlW8SSFSsMuKaI ...
- 39-Remove Duplicates from Sorted Array
Remove Duplicates from Sorted Array My Submissions QuestionEditorial Solution Total Accepted: 127836 ...
- 【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!
技术格言 世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程. 什么是脑裂 字面含义 首先,脑裂从字面上理解就是脑袋裂开了,就是思想分家了,就是有了两个山头,就是有了 ...