IOC的原理及手动实现
我们都知道IOC是使用工厂模式和反射技术来实现的,本文来说下IOC的原理及手动实现一个简易的IOC容器,来深入理解spring IOC的实现原理。
文章目录
- 概述
- IOC(Inversion of Control)
- IOC的好处
- IOC中设计的设计模式
- IOC的手动实现流程
- Bean定义
- 如何创建Bean
- 为了创建Bean我们需要提供什么
- 除了创建bean还需要做些什么
- Bean工厂
- 注册Bean定义
- 代码实现
- 基本代码实现
- 本文小结
概述
Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。也是几乎所有Java工作者必须要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是我们需要掌握的。
要学习Spring,除了在我们的项目中使用之外,也需要对它的源码进行研读,但是Spring的实现涵盖的知识很多,在加上其中的类的数量也是非常的多,在我们阅读源码时可能会在几十个类之间穿插阅读,很有可能一不小心就导致思维混乱。
有鉴于此,我这里先对Spring中的几个重要的模块进行一个手动的简易实现,一是熟悉这些模块的原理,同时也是仿造Spring中的结构来对后面阅读源码打下基础。
IOC(Inversion of Control)
Inversion of Control即控制反转,其意思是将我们之前由客户端代码来创建的对象交由IOC容器来进行控制,对象的创建,初始化以及后面的管理都由IOC完成。
IOC的好处
解耦: IOC的出现解决了类与类之间的耦合,我们在Web开发的Servlet时代,如果一个Servlet需要依赖另一个类的某些实现,那么我们需要在当前类对依赖的类进行创建和初始化,如果其他类也依赖了这个类,那也需要进行创建和初始化,而交给了IOC来管理的话,那么在需要的时候只需向IOC进行申请,而不需要重复的创建和初始化。当然,IOC也允许每次都重新创建一个新的对象。
方便与AOP进行配合: AOP也是一个使用十分频繁的功能,通过IOC可以十分方便的与AOP进行配合。
IOC中设计的设计模式
工厂模式。IOC容器来负责创建管理类实例对象,在需要时向IOC进行申请,从IOC中获取。所以IOC容器也称为bean工厂。
工厂模式是一种比较简单易懂的设计模式,这里就不在介绍了,如果有需要的可以看看工厂模式。
IOC的手动实现流程
Bean定义
IOC的主要的功能便是对Bean进行管理,包括创建、初始化、管理以及销毁的工作。首先我们面对的问题就是我们怎么让IOC能够创建一个Bean?为了创建Bean我们需要提供一些什么?
如何创建Bean
在不手动通过new关键字创建的情况下创建类实例的对象方法有两种:
反射:通过反射的方法可以创建类的实例:clazz.getClass().newInstance();。
工厂模式:工厂模式可以让我们在不接触实例类的情况下创建出实例。
public class PersonFactory{public Person getPerson(){return new Person();}
}
为了创建Bean我们需要提供什么
通过分析上面的两种方法可以轻松得出答案。
对于反射的方式我们仅需提供实例的Class对象。
对于工厂方法我们需要提供的就是创建该类的工厂名(factoryName)和方法名(methodName);
除了创建bean还需要做些什么
IOC容器是对bean的整个生命周期进行管理,除了创建之外还需要对bean进行初始化,以及不需要时对bean进行销毁的工作(如释放资源等)。所以我们还需要提供初始化和销毁等操作。
BeanDefinition接口源代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory.config;import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";int ROLE_APPLICATION = 0;int ROLE_SUPPORT = 1;int ROLE_INFRASTRUCTURE = 2;void setParentName(@Nullable String var1);@NullableString getParentName();void setBeanClassName(@Nullable String var1);@NullableString getBeanClassName();void setScope(@Nullable String var1);@NullableString getScope();void setLazyInit(boolean var1);boolean isLazyInit();void setDependsOn(@Nullable String... var1);@NullableString[] getDependsOn();void setAutowireCandidate(boolean var1);boolean isAutowireCandidate();void setPrimary(boolean var1);boolean isPrimary();void setFactoryBeanName(@Nullable String var1);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String var1);@NullableString getFactoryMethodName();ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !this.getConstructorArgumentValues().isEmpty();}MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !this.getPropertyValues().isEmpty();}void setInitMethodName(@Nullable String var1);@NullableString getInitMethodName();void setDestroyMethodName(@Nullable String var1);@NullableString getDestroyMethodName();void setRole(int var1);int getRole();void setDescription(@Nullable String var1);@NullableString getDescription();ResolvableType getResolvableType();boolean isSingleton();boolean isPrototype();boolean isAbstract();@NullableString getResourceDescription();@NullableBeanDefinition getOriginatingBeanDefinition();
}
到这里创建bean需要的基本分析完了,看方法:
Bean工厂
Bean的定义解决了,但是这个bean定义以及创建好的Bean实例放在哪里呢,我们需要一个统一的地方来存放这些东西以方便我们要用的时候方便取。
我们定义一个Bean工厂来存放bean,在需要的时候从bean工厂中取即可,bean工厂对外提供的也仅仅是一个获取bean的方法即可,由于bean的类型不定,所以返回值定位Object。
beanFactory源代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory;import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;public interface BeanFactory {String FACTORY_BEAN_PREFIX = "&";Object getBean(String var1) throws BeansException;<T> T getBean(String var1, Class<T> var2) throws BeansException;Object getBean(String var1, Object... var2) throws BeansException;<T> T getBean(Class<T> var1) throws BeansException;<T> T getBean(Class<T> var1, Object... var2) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> var1);<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);boolean containsBean(String var1);boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;String[] getAliases(String var1);
}
我们可以看到BeanFactory接口中最重要的就是这个getBean方法了。
注册Bean定义
到了现在我们有了创建bean的Bean定义,有了存放和管理bean的Bean工厂,现在需要考虑的是怎么来联系这两个类,我们还需要另外一个接口,接口的功能是让我们能注册和获取bean定义,这里我们通过beanName来区分不同的bean。
BeanDefinitionRegistry接口源代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.beans.factory.support;import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.AliasRegistry;public interface BeanDefinitionRegistry extends AliasRegistry {void registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;boolean containsBeanDefinition(String var1);String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String var1);
}
代码实现
到这里我们实现一个简易的IOC容器的需要的东西基本准备完成了。
基本代码实现
DefaultBeanDefinition:
public class DefaultBeanDefinition implements BeanDefinition{private Class<?> clazz;private String beanFactoryName;private String createBeanMethodName;private String staticCreateBeanMethodName;private String beanInitMethodName;private String beanDestoryMethodName;private boolean isSingleton;// setterpublic void setSingleton(boolean singleton) {isSingleton = singleton;}@Overridepublic Class<?> getBeanClass() {return this.clazz;}@Overridepublic String getBeanFactory() {return this.beanFactoryName;}@Overridepublic String getCreateBeanMethod() {return this.createBeanMethodName;}@Overridepublic String getStaticCreateBeanMethod() {return this.staticCreateBeanMethodName;}@Overridepublic String getBeanInitMethodName() {return this.beanInitMethodName;}@Overridepublic String getBeanDestoryMethodName() {return this.beanDestoryMethodName;}@Overridepublic String getScope() {return this.isSingleton?BeanDefinition.SINGLETION :BeanDefinition.PROTOTYPE;}@Overridepublic boolean isSingleton() {return this.isSingleton;}@Overridepublic boolean isPrototype() {return !this.isSingleton;}
}
DefaultBeanFactory
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {private Log log = LogFactory.getLog(this.getClass());//ConcurrentHashMap应对并发环境private Map<String, BeanDefinition> bdMap = new ConcurrentHashMap<>();private Map<String, Object> beanMap = new ConcurrentHashMap<>();@Overridepublic void register(BeanDefinition bd, String beanName) {Assert.assertNotNull("beanName不能为空 beanName", beanName);Assert.assertNotNull("BeanDefinition不能为空", bd);if(bdMap.containsKey(beanName)){log.info("[" + beanName + "]已经存在");}if(!bd.validate()){log.info("BeanDefinition不合法");}if(!bdMap.containsKey(beanName)){bdMap.put(beanName, bd);}}@Overridepublic boolean containsBeanDefinition(String beanName) {return bdMap.containsKey(beanName);}@Overridepublic BeanDefinition getBeanDefinition(String beanName) {if(!bdMap.containsKey(beanName)){log.info("[" + beanName + "]不存在");}return bdMap.get(beanName);}public Object doGetBean(String beanName) throws InstantiationException, IllegalAccessException {if(!beanMap.containsKey(beanName)){log.info("[" + beanName + "]不存在");}Object instance = beanMap.get(beanName);if(instance != null){return instance;}//不存在则进行创建if(!this.bdMap.containsKey(beanName)){log.info("不存在名为:[" + beanName + "]的bean定义");}BeanDefinition bd = this.bdMap.get(beanName);Class<?> beanClass = bd.getBeanClass();if(beanClass != null){instance = createBeanByConstruct(beanClass);if(instance == null){instance = createBeanByStaticFactoryMethod(bd);}}else if(instance == null && StringUtils.isNotBlank(bd.getStaticCreateBeanMethod())){instance = createBeanByFactoryMethod(bd);}this.doInit(bd, instance);if(instance != null && bd.isSingleton()){beanMap.put(beanName, instance);}return instance;}private void doInit(BeanDefinition bd, Object instance) {Class<?> beanClass = instance.getClass();if(StringUtils.isNotBlank(bd.getBeanInitMethodName())){try {Method method = beanClass.getMethod(bd.getBeanInitMethodName(), null);method.invoke(instance, null);} catch (Exception e) {e.printStackTrace();}}}/*** 构造方法创建实例* @param beanClass* @return*/private Object createBeanByConstruct(Class<?> beanClass) {Object instance = null;try {instance = beanClass.newInstance();} catch (Exception e) {e.printStackTrace();}return instance;}/*** 普通工厂方法创建实例* @param bd* @return*/private Object createBeanByFactoryMethod(BeanDefinition bd) {Object instance = null;try {//获取工厂类Object factory = doGetBean(bd.getBeanFactory());//获取创建实例的方法Method method = factory.getClass().getMethod(bd.getCreateBeanMethod());//执行方法instance = method.invoke(factory, null);} catch (Exception e) {e.printStackTrace();}return instance;}/*** 静态方法创建实例* @param bd* @return*/private Object createBeanByStaticFactoryMethod(BeanDefinition bd) {Object instance = null;try {Class<?> beanClass = bd.getBeanClass();//获取创建实例的方法Method method = beanClass.getMethod(bd.getStaticCreateBeanMethod());instance = method.invoke(beanClass, null);} catch (Exception e) {e.printStackTrace();}return instance;}@Overridepublic Object getBean(String beanName) {if(!beanMap.containsKey(beanName)){log.info("[" + beanName + "]不存在");}return beanMap.get(beanName);}@Overridepublic void close() throws IOException {Set<Map.Entry<String, BeanDefinition>> entries = bdMap.entrySet();for(Map.Entry<String, BeanDefinition> entry: entries){BeanDefinition value = entry.getValue();String destoryMethodName = value.getBeanDestoryMethodName();try {Method method = value.getBeanClass().getMethod(destoryMethodName, null);method.invoke(value.getBeanClass(), null);} catch (Exception e) {e.printStackTrace();}}}
}
简单测试一下:实例bean:
public class User {private String name;private int age;//getter setterpublic void init(){System.out.println("init...");}public void destory(){System.out.println("destory...");}}
工厂类:
public class TestFactory {public Object createMethod(){return new User();}public static Object staticCreateMethod(){return new User();}
}
测试类:
public class MySpringTest {static DefaultBeanFactory factory = new DefaultBeanFactory();@Testpublic void test() throws IllegalAccessException, InstantiationException {DefaultBeanDefinition bd = new DefaultBeanDefinition();bd.setClazz(User.class);bd.setSingleton(true);bd.setBeanFactoryName("TestFactory");bd.setCreateBeanMethodName("createMethod");bd.setStaticCreateBeanMethodName("staticCreateMethod");bd.setBeanInitMethodName("init");factory.register(bd, "user");System.out.println(factory.doGetBean("user"));}
}
本文小结
一个简易的容器就这样实现了,当然我们这里只是具备了基本的功能,实际上还差的远,比如带参数的bean的实例化等功能。但是IOC的基本原理已经表达出来了,后面我们只需在这个基础上添加新的功能即可。
IOC的原理及手动实现相关推荐
- Spring IOC核心原理分析
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,本文系统分 ...
- 转 Spring源码剖析——核心IOC容器原理
Spring源码剖析--核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring 源码 ioc 编程 bean 更多 个人分类: Java https:// ...
- spring 学习—spring 的ioc底层原理(02)
IOC的底层原理 1.ioc底层原理使用技术 (1) xml配置文件 (2) dom4j 解决xml (3)工厂设计模式 (4)反射 什么叫做耦合度太高了:就是关联度太紧密了 高内聚与低耦合 高内聚: ...
- Spring 概念及特点 Spring下载地址 控制反转IoC实现原理
Spring下载地址 http://repo.springsource.org/libs-release-local/org/springframework/spring/ Spring是开源full ...
- 手撸spring源码分析IOC实现原理
手撸spring源码分析IOC实现原理 文章出处:https://github.com/fuzhengwei/small-spring 根据小付哥的手撸spring核心源码一步步学习出来的结果收货总结 ...
- Spring——IOC底层原理
目录 一.IOC底层原理 1.什么是IOC 2.IOC底层原理 二.IOC接口(BeanFanctory) 三.IOC操作Bean管理(基于XML) 1.创建对象 2.注入属性 (1)DI:依赖注入 ...
- 10. Spring IOC 底层原理
Spring IOC 底层原理 如何通过 IOC 容器来创建对象: 创建 Maven 工程,在 pom.xml 中添加 Spring 框架相关的依赖: 新建实体类: 在 resources 目录下创建 ...
- Spring原理/SpringMVC原理/IOC/AOP原理
Spring原理/SpringMVC原理/IOC/AOP原理 我的微型IOC框架实现 我的微型IOC框架实现 当你打开这本书的时候我要告诉你的第一句话就是认真把前言读完,因为前言概括的本书的大纲以及思 ...
- 面试必会系列 - 1.8 Spring IOC / AOP原理
本文已收录至 Github(MD-Notes),若博客中图片模糊或打不开,可以来我的 Github 仓库,包含了完整图文:https://github.com/HanquanHq/MD-Notes,涵 ...
最新文章
- NHibernate之旅(10):探索父子(一对多)关联查询
- dede:arclist 不能调用文章的副栏目或多个副栏目的解决方法
- python --- 使用conda配置pytorch
- Mybatis-Plus批量插入数据太慢,使用rewriteBatchedStatements属性优化,堪称速度与激情!
- 32-bit ARM的 word halfword byte
- android 录屏工具,安卓手机上最好的录屏软件在这里
- PHP实现Restful风格的API(转)
- 跨域问题及jQuery中Ajax传参的讲解
- 军团的崛起:利用多态指挥多兵种作战
- android exo解码问题,android – exoplayer-自动更改质量不起作用(hls)
- CSS 实现文字渐变色
- 如何在linux上的上修改配置ip地址
- 计算机三级在线题库,计算机三级网络技术题库(附答案)
- Web-网上在线支付
- 【幻灯片分享】iOS平台上开发音视频处理 | 盛大微酷 赵志猛 | iOS DevCamp
- dax和m的区别_一分钟格式化所有DAX及M语句
- java连接SQL Sever数据库(超详细!)
- 我在Salira的800天(2009.5.20~2011.7.29)-三.研究与学习篇
- 2022年无线麦克风品牌排行榜前十是哪些?哪个品牌值得购买?选购全指南在此,请查收。
- jmeter_extra_tool v1.1
热门文章
- 2.请求安全-- MD5的必要性以及实际应用场景
- is_file()和file_exists()
- 样条表示---插值和逼近样条
- 社交媒体广告看不出来?Instagram加标签让你一目了然
- 德国软件巨头SAP旗下风投基金募集10亿美元 专门投资科技初创公司
- node.js JavaScript 严格模式
- 服务器内存类型UDIMM、RDIMM和LRDIMM比较
- PostgreSQL连接问题(Net LO problem)
- OpenSSL在Windows下使用vs2010的编译安装
- 使用SharePoint 2010 母版页