为了方便理解项目中的实现,我们先对IOC与DI进行简单的介绍

控制反转

IoC(Inverse of Control:控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。所谓IOC一句话搞定:对象由Spring来创建、管理、装配。而DI(依赖注入)是实现IOC的一种方式。所谓的控制反转就是获取依赖对象的方式反转了。

Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。

控制翻转怎么理解:举个例子,"对象a 依赖了对象 b,当对象 a 需要使用 对象 b的时候必须自己去创建。但是当系统引入了 IOC 容器后, 对象a 和对象 b 之前就失去了直接的联系。这个时候,当对象 a 需要使用 对象 b的时候, 我们可以指定 IOC 容器去创建一个对象b注入到对象 a 中"。对象a获得依赖对象b的过程由主动行为变为了被动行为,控制权翻转,这就是控制反转名字的由来。

核心代码实现

在下面的代码中,createBeanDefinitionMap是为了创建Bean名与BeanDefinition相对应的映射关系,BeanDefinition将包含该Bean的相关信息,如bean的类、bean是单例还是原型、bean是否需要被代理。
BeanDefinition的存在将有助于我们实现bean的创建。

根据前文我们对于IOC的介绍,可以知道,IOC本质上是一个容器,项目在初始化后,这个容器将包含一些项目中需要的Bean,这些bean有的是单例,有的是原型。对于单例bean,我们需要时就直接从单例池中取出,对于原型bean,我们在需要使用时直接创建即可,这部分在下文代码的 getBean() 部分。在创建bean时,我们要对bean中被@Autowired的字段进行注入,这是依赖注入过程,这部分在下文代码的 doCreateBean() 部分。

public class BeanHelper {private static String aspectPath="com.luban.demo.controller";private static  Map<String,BeanDefinition> beanDefinitionMap=new HashMap<String, BeanDefinition>();//单例池public static  Map<String,Object> singletonObjects=new HashMap<String, Object>();private static Map<Class<?>,Object> aopMap;static {// 创建BeanDefinitionMapcreateBeanDefinitionMap();//初始化AopHelper aopHelper=new AopHelper();aopMap=aopHelper.getProxyMap();instanceSingletonBean();}public static void createBeanDefinitionMap(){Set<Class<?>> classSet=new ClassHelper().getAllClass();//将所有beanDefinition实例化并放入容器for (Class<?> beanClass:classSet) {if (beanClass.isAnnotationPresent(Component.class)) {Component componentAnnotation = beanClass.getAnnotation(Component.class);String beanName = componentAnnotation.value();BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanClass(beanClass);beanDefinition.setAspect(beanClass.getName().startsWith(aspectPath));//如果clazz是被Scope注解的类if (beanClass.isAnnotationPresent(Scope.class)) {//获取clazz上Scope的注解信息,获取bean的作用范围ScopeScope scopeAnnotation = beanClass.getAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotation.value());} else {//单例beanDefinition.setScope("singleton");}beanDefinitionMap.put(beanName, beanDefinition);}else if (beanClass.isAnnotationPresent(Service.class)){Service componentAnnotation = beanClass.getAnnotation(Service.class);String beanName = componentAnnotation.value();BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanClass(beanClass);beanDefinition.setAspect(beanClass.getName().startsWith(aspectPath));//如果clazz是被Scope注解的类if (beanClass.isAnnotationPresent(Scope.class)) {//获取clazz上Scope的注解信息,获取bean的作用范围ScopeScope scopeAnnotation = beanClass.getAnnotation(Scope.class);beanDefinition.setScope(scopeAnnotation.value());} else {//单例beanDefinition.setScope("singleton");}beanDefinitionMap.put(beanName, beanDefinition);}}}public static void instanceSingletonBean() {for (String beanName:beanDefinitionMap.keySet()){BeanDefinition beanDefinition= (BeanDefinition) beanDefinitionMap.get(beanName);//如果是单例bean,需要存入单例池if (beanDefinition.getScope().equals("singleton")){//创建bean,对于被AOP的类,直接加强放入到singletonObjects的map中if (!singletonObjects.containsKey(beanName)){Object bean=doCreateBean(beanName,beanDefinition);singletonObjects.put(beanName,bean);}}}}private static Object doCreateBean(String beanName, BeanDefinition beanDefinition) {//实例化,利用java的反射机制完成try {//1.实例化Class<?> beanClass=beanDefinition.getBeanClass();Object instance;//实例化beaninstance=beanClass.getDeclaredConstructor().newInstance();//2.属性填充/依赖注入//Field即字段即类中的成员变量//getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。//getDeclaredFields()获得某个类的所有声明的字段,即包括public、private和protecedField[] fields=beanClass.getDeclaredFields();for (Field field:fields){//如果该字段采用Autowired注入if (field.isAnnotationPresent(AutoWired.class)){String fieldName=field.getName();Object o=getBean(fieldName);//开启field的set模式field.setAccessible(true);//将bean的field字段设置为ofield.set(instance,o);}}//3.回调,设置beanNameif (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;}public static Object getBean(String beanName){// beanName 单例的,原型的BeanDefinition beanDefinition= beanDefinitionMap.get(beanName);Object bean=null;if (beanDefinition.getScope().equals("prototype")){//如果是原型bean,创建一个新的bean=doCreateBean(beanName,beanDefinition);}else if (beanDefinition.getScope().equals("singleton")){//否则,从单例池中加载bean=singletonObjects.get(beanName);if (bean==null){Object bean1=doCreateBean(beanName,beanDefinition);singletonObjects.put(beanName,bean1);return bean1;}}return bean;}public static void setBeanPraoxy(Class<?> targetClass, Object proxy) {String name = null;for (Map.Entry<String,BeanDefinition> entry:beanDefinitionMap.entrySet()){BeanDefinition beanDefinition=entry.getValue();if (beanDefinition.getBeanClass().equals(targetClass)){name=entry.getKey();break;}}singletonObjects.put(name,proxy);}
}

手写Sping(2) :手写IOP与DI(依赖注入)相关推荐

  1. 手写Spring DI依赖注入,嘿,你的益达!

    手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...

  2. 依赖注入和控制反转的理解,写的太好了。

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...

  3. 测试手机新机软件,玩机小技巧 篇一:手把手教你快速验新机——写给剁手节买了新手机的值友...

    玩机小技巧 篇一:手把手教你快速验新机--写给剁手节买了新手机的值友 2020-12-10 17:39:14 29点赞 97收藏 11评论 创作立场声明:本文旨在分享购入新机器后如何检验手机完好的小技 ...

  4. 冯杰的手写艺术签名怎么写好看

    导读:今天来给大家分享[冯杰的手写艺术签名怎么写好看]有叫这个名字的人可以来看看了! 一.学习签名首先是要决定是写在哪些地方; (1)用在普通的场合,想要一个比较独特的签名; 在这种时候,想要一个与众 ...

  5. 手写 springIoc 注解版 ,实现@Service (beng),@Resource (依赖注入)

    手写springIoc 注解版 代码demo https://pan.baidu.com/s/1jyvLMDrg_bfpKmhtrTTZSQ 提取码:5ju1 代码目录结构 1.pom.xml < ...

  6. 现在论文用手写还是用计算机写,调查显示近半人基本全用电脑写字 八成受访者提笔忘字...

    电脑已经成为大多数人的写字工具.(资料图片) 大部分现代人,只有在签名的时候才会拿起笔.(资料图片) "罄竹难书"."鳞次栉比"."沆瀣一气" ...

  7. vue 手写签名_手写Promise/Promise.all/Promise.race(手写系列一)

    背景 几个月没写文章了,愧对关注本专栏的小伙伴.最近有同学提议我出一个手写系列的文章对常见对前端工具.框架.设计模式做一个覆盖.同时有个要求:代码要尽量短小易懂,并且体现原理,让学习者学习过后能在未来 ...

  8. html5实现安卓的手写功能,html5 canvas手写字代码(兼容手机端)(示例代码)

    html5 canvas手写字代码(兼容手机端) 画板实验 清 空 生成图片 var canvas,board,img; canvas = document.getElementById('myCan ...

  9. Go工程化 - 手摸手带你理解依赖注入

    转载地址:https://mp.weixin.qq.com/s/c7JtKKCGSD5x9c4TxqzghQ 我们在微服务框架 kratos v2[1] 的默认项目模板中 kratos-layout[ ...

最新文章

  1. 编程之美-求数组中最长递增子序列(LIS)方法整理
  2. 建信金融科技春季全国笔试卷B编程题
  3. 由浅入深剖析go channel
  4. 工程中选择数据结构和算法的依据
  5. MySQL (9)---数据类型
  6. 光影之路 GPU架构发展史(3/4)
  7. python字典占内存_Python:减少字典的内存使用
  8. jq取第一个子元素为select_Python爬取博客的所有文章并存为带目录的word文档(实例67)...
  9. 棋牌游戏定时器模块设计
  10. 音视频编辑软件哪个好
  11. 彪悍晨读 | 每天价值投资常识
  12. 使用vue全家桶开发音乐App
  13. 交付管理——怎样与客户打交道
  14. ERP的灵魂是管理思想
  15. 绕口令:《舌头是怎样练成的》
  16. 艾永亮:耐克阿迪都慌了,成功逆袭的李宁,产品创新战略是什么
  17. 成为一名高级软件工程师
  18. 2023 与佛论禅翻译系统重制v2源码 升级版
  19. 766.托普利茨矩阵
  20. 中标麒麟安装达梦数据库DM8

热门文章

  1. 和菜鸟一起学算法之三分法求极值问题
  2. 【vue系列-04】vue的表单数据收集,基本指令和自定义指令
  3. 智能硬件产品经理需要哪些技术基础?
  4. Oracle 的表以及表基本操作
  5. Redis内存空间简单分析
  6. 【C基础练习题】第一章:输入和输出 | 基础练习题 | 提供题解
  7. 【数据库MySQL】数据库网上书店管理系统
  8. C语言链表超简单教程
  9. python学习第八天
  10. 【算法】一文详解贪心法