点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试资料

作者:不学无数的程序员

juejin.im/post/5c4ac4256fb9a049af6da128

Spring框架中最经典的两个就是IOC和AOP,其中IOC(Inversion of Control)是什么呢?控制反转,简单来说就是将控制实体Bean的动作交给了Spring容器进行管理。

再简单点来说就是例如之前想用一个类,必须new一个,但是使用了Spring那么直接用@Autowired注解或者用xml配置的方式就能直接获得此对象,而且你也不用管它的生命周期啊等等之类的。就不用自己new一个对象了。

如果是之前没有使用IOC的话,那么这些对象的创建以及赋值都是由我们自己创建了,下面简单的演示了如果有上面四个对象依赖的话,那么没有IOC我们必须要创建对象并且赋值。仅仅四个对象就这么多,那么一旦项目大了,对象成百上千,如果还这样写的话,那么绝对是一场灾难。

对象A a = new 对象A();
对象B b = new 对象B();
对象C c = new 对象C();
对象D d = new 对象D();
a.setB(b);
a.setC(c);
b.setD(d);
c.setD(d);

因此在Spring中通过IOC将所有的对象统一放到Spring的容器中进行管理,所以就简单了很多。上面的实例化对象的代码也不需要我们写了。

上面说了那么多,其实就是一句话IOC非常重要,但是如果直接看Spring源码的话会非常懵逼,所以就简单的写一个IOC的小例子来理解这种思想。

分析并编写代码

还是编写代码前的分析阶段,Spring的IOC其实就是将所有的Bean放在统一容器中进行管理起来,然后在在获取的时候进行初始化,所以需要我们在程序启动的时候将被标记的类进行存储在自定义的容器中管理。

  • 初始化阶段:将被@MyIoc类似于Spring中@Service标记的类放入到自定义的容器中。

  • 使用:通过自定义的获取Bean的类进行统一获取。

现在我们就以上面两个步骤进行详细点的分析

数据准备阶段

首先初始化阶段我们要先建立两个注解类用于类的发现(@MyIoc类似于@Service)。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyIoc {}

然后要初始化信息进自定义容器的话用什么类型的容器去存储这些信息呢?这里可以想到是用Map来存,用key为类名,value用什么呢?value就是要放在容器中进行管理的类的信息了,那么一个类有什么信息呢即类是由什么组成呢?有以下几个信息

  • 类名

  • 构造函数

  • 属性值

  • 父类

所以根据上面的分析我们可以建立一个实体类来存储这些信息,此时我们就不考虑复杂的构造函数了,就都是初始化的无参构造函数。然后父类的属性就不进行分析注入了。所以此时类实体类就简单了。

@Data
public class BeanDefinition {private String className;private String alias;private String superNames;
}

初始化阶段

有了存储类信息的类了,那么我们在程序启动的时候就应该将这些信息给加载到Map中,此时建立一个启动类用于初始化被@MyIoc标记的类的信息。

@Component
@Order(value = 1)
public class IoCInitConifg implements CommandLineRunner{@Overridepublic void run(String... args){ConcurrentHashMap<String,BeanDefinition> concurrentHashMap = new ConcurrentHashMap<>();Reflections reflections = new Reflections();//获得项目中所有被MyIoc标记得类Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyIoc.class);//将其信息初始进自定义容器MyBeanFactory中for (Class clazz : typesAnnotatedWith){BeanDefinition beanDefinition = new BeanDefinition();String className = clazz.getName();String superclassName = clazz.getSuperclass().getName();beanDefinition.setClassName(className);beanDefinition.setSuperNames(superclassName);beanDefinition.setAlias(getClassName(className));concurrentHashMap.put(className,beanDefinition);}MyBeanFactoryImpl.setBeanDineMap(concurrentHashMap);}private String getClassName(String beanClassName) {String className = beanClassName.substring(beanClassName.lastIndexOf(".") + 1);className = className.substring(0, 1).toLowerCase() + className.substring(1);return className;}
}

此时得说一下自定义的统一容器管理的类MyBeanFactory此类用作统一获得类的途径

public interface MyBeanFactory {Object getBeanByName(String name) throws Exception;
}

此时还有其实现类

@Log4j
public class MyBeanFactoryImpl implements MyBeanFactory{//存储对象名称和已经实例化的对象映射private static ConcurrentHashMap<String,Object> beanMap = new ConcurrentHashMap<>();//存储对象名称和对应对象信息的映射private static ConcurrentHashMap<String,BeanDefinition> beanDefineMap= new ConcurrentHashMap<>();//存储存储在容器中对象的名称private static Set<String> beanNameSet = Collections.synchronizedSet(new HashSet<>());@Overridepublic Object getBeanByName(String name) throws Exception {//看有没有已经实例化的对象,有的话就直接返回Object object = beanMap.get(name);if (object != null){return object;}//没有的话就实例化一个对象object = getObject(beanDefineMap.get(name));if (object != null){//对实例化中对象的注入需要的参数setFild(object);//将实例化的对象放入Map中,便于下次使用beanMap.put(name,object);}return object;}public void setFild(Object bean) throws Exception {Field[] declaredFields = bean.getClass().getDeclaredFields();for (Field field: declaredFields){String filedAllName = field.getType().getName();if (beanNameSet.contains(filedAllName)){Object findBean = getBeanByName(filedAllName);//为对象中的属性赋值field.setAccessible(true);field.set(bean,findBean);}}}public Object getObject(BeanDefinition beanDefinition) throws Exception {String className = beanDefinition.getClassName();Class<?> clazz = null;try {clazz = Class.forName(className);} catch (ClassNotFoundException e) {log.info("can not find bean by beanName: "+className);throw new Exception("can not find bean by beanName: "+className);}return clazz;}public static void setBeanDineMap(ConcurrentHashMap<String,BeanDefinition> beanDefineMap){MyBeanFactoryImpl.beanDefineMap = beanDefineMap;}public static void setBeanNameSet(Set<String> beanNameSet){MyBeanFactoryImpl.beanNameSet = beanNameSet;}}

此时初始化的阶段已经完成了,即已经将所有被@MyIoc标记的类已经被全部存放在了自定义的容器中了。其实在这里我们已经能使用自己的自定义的容器进行获得Bean了。

@MyIoc
@Data
public class User {private Student student;
}
@MyIoc
public class Student {public String play(){return "student"+ this.toString();}
}

此时我们在启动类中写如下

        User user1 = (User)beanFactory.getBeanByName("com.example.ioc.domain.User");User user2 = (User)beanFactory.getBeanByName("com.example.ioc.domain.User");Student student1 = user1.getStudent();Student student2 = user1.getStudent();Student student3 = (Student)beanFactory.getBeanByName("com.example.ioc.domain.Student");System.out.println(user1);System.out.println(user2);System.out.println(student1);System.out.println(student2);System.out.println(student3);

发现控制台中输出的对象都是同一个对象,并且在User中也自动注入了Student对象。此时一个简单的IOC就完成了。

User(student=com.example.ioc.domain.Student@705e7b93)
User(student=com.example.ioc.domain.Student@705e7b93)
com.example.ioc.domain.Student@705e7b93
com.example.ioc.domain.Student@705e7b93
com.example.ioc.domain.Student@705e7b93

项目地址

https://github.com/modouxiansheng/Doraemon

参考

https://juejin.im/post/5a5875a4518825733a30a463
https://juejin.im/entry/599f8ba6518825241f788ad1

热门内容:   

    

  • 微服务架构的四大金刚利器

  • “12306”的架构到底有多牛逼?

  • 别在 Java 代码里乱打日志了,这才是正确的打日志姿势

  • 假如有人把支付宝存储服务器炸了

  • SpringBoot微信点餐开源系统

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡ 

徒手撸一个简单的IOC相关推荐

  1. 徒手撸一个简单的 IOC

    Spring框架中最经典的两个就是IOC和AOP,其中IOC(Inversion of Control)是什么呢?控制反转,简单来说就是将控制实体Bean的动作交给了Spring容器进行管理.再简单点 ...

  2. 从0到1徒手撸一个简单的glup插件

    参考http://www.alloyteam.com/2016/01/9918/#comments 但这位大兄弟的代码跑不起呀.自己简单修改了下 http://nodejs.cn/api/fs.htm ...

  3. spring boot 自动跳转登录页面_徒手撸一个扫码登录示例工程

    徒手撸一个扫码登录示例工程 不知道是不是微信的原因,现在出现扫码登录的场景越来越多了,作为一个有追求.有理想新四好码农,当然得紧跟时代的潮流,得徒手撸一个以儆效尤 本篇示例工程,主要用到以下技术栈 q ...

  4. 手写一个简单的IOC容器

    手写一个简单的IOC容器 原文 http://localhost:4000/2020/02/25/SSM/spring/%E6%89%8B%E5%86%99%E4%B8%80%E4%B8%AA%E5% ...

  5. 小司机带你撸一个简单的RPC框架

    随着业务的增长,有时候普通的单一型架构不再能满足我们的需求,这就诞生了RPC框架,经过多年的发展,我们可以看到市面上可用性高的开源RPC框架还是比较多的,比如说:Hessian,Dubbo等,这些框架 ...

  6. js websocket同步等待_WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器...

    本文原题"Node.js - 200 多行代码实现 Websocket 协议",为了提升内容品质,有较大修订. 1.引言 最近正在研究 WebSocket 相关的知识,想着如何能自 ...

  7. json解析对应的value为null_徒手撸一个JSON解析器

      Java大联盟 致力于最高效的Java学习 关注 作者 | 田小波 cnblogs.com/nullllun/p/8358146.html1.背景JSON(JavaScript Object No ...

  8. android组合控件的焦点,撸一个简单的TV版焦点控制的日历控件

    1.效果 最近需求要一个遥控控制的日历控件,找了半天没找到轮子,就自己撸一个,先看效果图: 效果图.gif 2.XML属性,所有属性默认为效果图 calender_textSize:星期和日期的字体大 ...

  9. Spring入门之一-------实现一个简单的IoC

    一.场景模拟 public interface Human {public void goHome();} Human:人类,下班了该回家啦 public interface Car {void st ...

最新文章

  1. LVS DR模式 负载均衡服务搭建
  2. 集群、分布式、负载均衡区别与联系
  3. RxSwift之深入解析特殊序列deallocating与deallocated的源码实现
  4. (11) ejb学习: Jpa事务管理类型 container 和 bean
  5. 全国计算机等级考试题库二级C操作题100套(第100套)
  6. Android为TV端助力 post带数据请求方式,传递的数据格式包括json和map
  7. 剪辑内核linux,Linux01-Linux编辑内核定制属于自己的内核49
  8. 大学计算机试卷分析报告,(最新整理)大学试卷分析报告
  9. VMware VCSA6.0的部署及升级到6.5
  10. Qt6程序打包(如何解决Qt程序在其他电脑上无法运行的问题)
  11. HUT-XXXX The window of the dazzling 模拟
  12. Python大数据分析(一):认识大数据
  13. html5 json.stringify,JSON.stringify()妙用
  14. 读《Ideal MHD》(1)-磁流体力学方程组推导
  15. SSH基础----【超级干货】Spring常用注解用法汇总(附DEMO)
  16. 第四周项目3---单链表的应用之连接
  17. 0205函数的微分-导数与微分-高等数学
  18. 项目部署三---linux下Nginx安装
  19. 思科华为H3C锐捷交换机路由器AP等console线
  20. 一则帖子整理:30岁人生困惑,路在何方?

热门文章

  1. 机器学习 决策树 ID3
  2. [LeetCode] [C++] 第一轮刷题总结(持续更新~~~)
  3. openstack安装在虚拟机上重启之后无法启动问题
  4. [bbk4966]第70集 第8章 -性能维护 01
  5. Multithread 之 introduction
  6. 百度飞桨成为北京市首个AI产业方向创新应用平台
  7. CSDN插件限时内测,新用户抢永久免费去广告特权!
  8. 英特尔第11代酷睿处理器TigerLake发布,集成Xe GPU,采用10nm制程技术
  9. 机器学习中的线性回归,你理解多少?
  10. AI芯片行业发展的来龙去脉