理解Spring:IOC的原理及手动实现
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进行销毁的工作(如释放资源等)。所以我们还需要提供初始化和销毁等操作。
到这里创建bean需要的基本分析完了,看类图:
Bean工厂
Bean的定义解决了,但是这个bean定义以及创建好的Bean实例放在哪里呢,我们需要一个统一的地方来存放这些东西以方便我们要用的时候方便取。
我们定义一个Bean工厂来存放bean,在需要的时候从bean工厂中取即可,bean工厂对外提供的也仅仅是一个获取bean的方法即可,由于bean的类型不定,所以返回值定位Object。
注册Bean定义
到了现在我们有了创建bean的Bean定义,有了存放和管理bean的Bean工厂,现在需要考虑的是怎么来联系这两个类,我们还需要另外一个接口,接口的功能是让我们能注册和获取bean定义,这里我们通过beanName来区分不同的bean。参考:深究Spring中Bean的生命周期
代码实现
到这里我们实现一个简易的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;
    // setter
    public void setSingleton(boolean singleton) {
        isSingleton = singleton;
    }
    @Override
    public Class<?> getBeanClass() {
        return this.clazz;
    }
    @Override
    public String getBeanFactory() {
        return this.beanFactoryName;
    }
    @Override
    public String getCreateBeanMethod() {
        return this.createBeanMethodName;
    }
    @Override
    public String getStaticCreateBeanMethod() {
        return this.staticCreateBeanMethodName;
    }
    @Override
    public String getBeanInitMethodName() {
        return this.beanInitMethodName;
    }
    @Override
    public String getBeanDestoryMethodName() {
        return this.beanDestoryMethodName;
    }
    @Override
    public String getScope() {
        return this.isSingleton?BeanDefinition.SINGLETION :BeanDefinition.PROTOTYPE;
    }
    @Override
    public boolean isSingleton() {
        return this.isSingleton;
    }
    @Override
    public 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<>();
    @Override
    public 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);
        }
    }
    @Override
    public boolean containsBeanDefinition(String beanName) {
        return bdMap.containsKey(beanName);
    }
    @Override
    public 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;
    }
    @Override
    public Object getBean(String beanName) {
        if(!beanMap.containsKey(beanName)){
            log.info("[" + beanName + "]不存在");
        }
        return beanMap.get(beanName);
    }
    @Override
    public 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 setter
    public 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();
    @Test
    public 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的基本原理已经表达出来了,后面我们只需在这个基础上添加新的功能即可。
理解Spring:IOC的原理及手动实现的更多相关文章
- 深入理解Spring IOC工作原理
		为什么会出现spring,spring出现解决了什么问题? 1.分析普通多层架构存在的问题 JSP->Servlet->Service->Dao 层与层之间的依赖很强,属于耦合而且是 ... 
- 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)
		♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ... 
- Spring系列之IOC的原理及手动实现
		目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 导语 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架.也是几乎所有J ... 
- Spring IOC设计原理解析:本文乃学习整理参考而来
		Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ... 
- Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计
		在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ... 
- Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程
		上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ... 
- Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)
		上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ... 
- spring ioc aop 原理
		spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ... 
- Spring IoC底层原理
		-------------------siwuxie095 Spring IoC 底层原理 1.IoC 即 Invers ... 
- Java工厂模式解耦 —— 理解Spring IOC
		Java工厂模式解耦 -- 理解Spring IOC 最近看到一个很好的思想来理解Spring IOC,故记录下来. 资源获取方式 主动式:(要什么资源都自己创建) 被动式:(资源的获取不是我们创建, ... 
随机推荐
- java之泛型的使用
			在java中,普通的类和方法只能用具体的类型,这对代码的限制很大,代码的可重用性大大降低. 那么如何才能让同一个类和方法使用不同类型的对象呢?在接触泛型之前我们可能会想到通过类型转换的方法来实现. p ... 
- 大学四年因为分享了这些软件测试常用软件,我成了别人眼中的(lei)大神(feng)!
			依稀记得,毕业那天,我们辅导员发给我毕业证的时候对我说"你可是咱们系的风云人物啊",哎呀,别提当时多开心啦????,嗯,我们辅导员是所有辅导员中最漂亮的一个,真的???? 不过,辅 ... 
- 一文弄懂pytorch搭建网络流程+多分类评价指标
			讲在前面,本来想通过一个简单的多层感知机实验一下不同的优化方法的,结果写着写着就先研究起评价指标来了,之前也写过一篇:https://www.cnblogs.com/xiximayou/p/13700 ... 
- MySQL8.0大表秒加字段,是真的吗?
			前言: 很早就听说 MySQL8.0 支持快速加列,可以实现大表秒级加字段.笔者自己本地也有8.0环境,但一直未进行测试.本篇文章我们就一起来看下 MySQL8.0 快速加列到底要如何操作. 1.了解 ... 
- SprintBoot使用Validation
			1.为什么要使用Validation 在开发过程中有没有使用一堆的if来判断字段是否为空.电话号码是否正确.某个输入是否符合长度等对字段的判断.这样的代码可读性差,而且还不美观,那么使用Validat ... 
- 白日梦的MySQL专题(第33篇):各种登陆MySQL的骚操作
			阅读原文 系列文章公众号首发,点击阅读原文 前置知识 我们想登陆到mysql中前提是肯定需要一个用户名和密码:比如 mysql -uroot -proot 在mysql中用户的信息会存放在 mysql ... 
- [bug] Python Anoconda3 安装完成后开始菜单不显示
			版本问题,需更新 win+R打开cmd,敲入命令: conda update menuinst conda install -f console_shortcut ipython ipython-no ... 
- Deepin深度应用商店和系统更新不正常的解决方法
			Deepin深度应用商店和系统更新不正常的解决方法 2020-02-04 10:25:09作者:i8520稿源:深度站 如果你的Deepin深度应用商店和系统更新不正常,可采用以下方法来解决问题. 解 ... 
- C++知识点案例 笔记-5
			1.关系运算符重载 2.类型转换函数重载 3.转换构造函数 4.函数模板 5.显式实例化 6.类模板外定义模板函数 1.关系运算符重载 ==关系运算符重载== //直接(按分数)比较两个对象 #inc ... 
- 拉勾、Boss直聘、内推、100offer
			BOSS直聘 拉勾.Boss直聘.内推.100offer 
