Spring系列之IOC的原理及手动实现

目录

导语

Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。也是几乎全部Java工做者必需要掌握的框架之一,其优秀的设计思想以及其代码实现上的艺术也是咱们须要掌握的。要学习Spring,除了在咱们的项目中使用以外,也须要对它的源码进行研读,可是Spring的实现涵盖的知识不少,在加上其中的类的数量也是很是的多,在咱们阅读源码时可能会在几十个类之间穿插阅读,颇有可能一不当心就致使思惟混乱。有鉴于此,我这里先对Spring中的几个重要的模块进行一个手动的简易实现,一是熟悉这些模块的原理,同时也是仿造Spring中的结构来对后面阅读源码打下基础。html

IOC(Inversion of Control)

Inversion of Control即控制反转,其意思是将咱们以前由客户端代码来建立的对象交由IOC容器来进行控制,对象的建立,初始化以及后面的管理都由IOC完成。设计模式

IOC的好处

  1. 解耦:IOC的出现解决了类于类之间的耦合,咱们在Web开发的Servlet时代,若是一个Servlet须要依赖另外一个类的某些实现,那么咱们须要在当前类对依赖的类进行建立和初始化,若是其余类也依赖了这个类,那也须要进行建立和初始化,而交给了IOC来管理的话,那么在须要的时候只需向IOC进行申请,而不须要重复的建立和初始化。固然,IOC也容许每次都从新建立一个新的对象。
  2. 方便与AOP进行配合:AOP也是一个使用十分频繁的功能,经过IOC能够十分方便的与AOP进行配合。

IOC中设计的设计模式

工厂模式。IOC容器来负责建立管理类实例对象,在须要时向IOC进行申请,从IOC中获取。因此IOC容器也称为bean工厂。bash

工厂模式是一种比较简单易懂的设计模式,这里就不在介绍了,若是有须要的能够看看这个:工厂模式并发

IOC的手动实现

Bean定义

IOC的主要的功能即是对Bean进行管理,包括建立、初始化、管理以及销魂的工做。首先咱们面对的问题就是咱们怎么让IOC可以建立一个Bean?为了建立Bean咱们须要提供一些什么?框架

如何建立Bean

在不手动经过new关键字建立的状况下建立类实例的对象方法有两种:ide

  1. 反射:经过反射的方法能够建立类的实例:clazz.getClass().newInstance();
  2. 工厂模式:工厂模式可让咱们在不接触实例类的状况下建立出实例。
public class PersonFactory{
    public Person getPerson(){
        return new Person();
    }
}
复制代码
为了建立Bean咱们须要提供什么

经过分析上面的两种方法能够轻松得出答案。post

对于反射的方式咱们仅需提供实例的Class对象。学习

对于工厂方法咱们须要提供的就是建立该类的工厂名(factoryName)和方法名(methodName);测试

除了建立bean还须要作些什么

IOC容器是对bean的整个生命周期进行管理,除了建立以外还须要对bean进行初始化,以及不须要时对bean进行销毁的工做(如释放资源等)。因此咱们还须要提供初始化和销毁等操做。ui

到这里建立bean须要的基本分析完了,看类图:

BeanDefinition

Bean工厂

Bean的定义解决了,可是这个bean定义以及建立好的Bean实例放在哪里呢,咱们须要一个统一的地方来存放这些东西以方便咱们要用的时候方便取。

咱们定义一个Bean工厂来存放bean,在须要的时候懂bean工厂中取便可,bean工厂对外提供的也仅仅是一个获取bean的方法便可,因为bean的类型不定,因此返回值定位Object。

BeanFactory

注册Bean定义

到了如今咱们有了建立bean的Bean定义,有了存放和管理bean的Bean工厂,如今须要考虑的事怎么来联系这两个类,咱们还须要另一个接口,接口的功能是让咱们能注册和获取bean定义,这里咱们经过beanName来区分不一样的bean。

BeanDefinitionRegistry

代码实现

到这里咱们实现一个简易的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的基本原理已经表达出来了,后面咱们只需在这个基础上添加新的功能便可。