ioc容器的实现方法有哪些_Spring(一): IOC概念,手写IOC

IOC是什么:

inversion of control 控制反转

如何反转

依赖对象的获得被反转了,由自己创建,反转为从IOC容器中获取(和自动注入)

好处:

1.代码更简洁,不需要去new   
2. 面向接口变成,使用者与具体类解耦,易扩展,替换实现者
3.可以方便的进行aop增强,没有IOC就不可以进行aop

IOC容器做什么工作?

负责创建/管理类实例,向使用者提供实例

IOC容器是不是工厂模式的实例?

是的。IOC容器负责创建类实例对象,需要就从IOC容器中get,也称IOC容器为bean工厂

IOC容器的工作就是:创建、管理Bean,是一个工厂,负责对外提供bean实例,bean就是组件,也就是类的对象。

IOC应该具备什么行为呢(对外接口接口)?

对外提供bean实例,getBean()方法

这个getBean()方法是否需要参数?需要几个参数,什么样类型的参数?

在简单工厂模式中,当工厂能创建很多类产品的时候,如需要创建某类产品,需要告诉工厂

这个getBean()方法的返回值应该是什么类型的?

因为要返回各种类型的Bean,那就只能是Object了

Bean工厂的接口:

bean工厂创建bean需要有bean定义,后面说bean定义

66fe2af53bbcca7de811b2f56e1956ee.png

现在的问题是Bean工厂怎么知道该如何创建bean?

得把bean定义告诉bean工厂。这个bean是这么创建,那个bean是那么创建

那么如何告诉bean工厂bean定义呢?

因为有很多的bean定义,这个bean,那么bean,
所以就有一个定义注册,可以定义一个定义注册的接口,
把所有的bean定义都注册进来,那么就加一个注册接口

Bean定义注册接口

ae4afdb550fd2dc84ed688ab4607aa7b.png

这个bean定义注册接口中应该定义什么方法?

注册、获取bean定义

注册的bean定义信息如何区分?

每个bean定义有一个唯一的名称

1d418e7e337929d4b5af2fc6ec57da0a.png

上面是bean定义的注册接口,下来是bean定义

e13fcce8c5745e407398682fa9941c5e.png

bean定义的用途是什么?

告诉bean工厂该如何创建某类bean,这个bean这么创建,那个bean那么创建

获得类的实例的方式有哪些(常用的)

new 构造
工厂:静态和成员方法

bean工厂创建bean的时候,需要知道哪些信息?

假如是new 构造创建的话,需要知道类名
假如是静态工厂方法的话,需要知道工厂类名,工厂方法名
假如是成员工厂方法的话,工厂类名?-> 工厂bean名,工厂方法名

每次从bean工厂获取bean实例的时候,是否都需要创建一个新的bean呢?

不需要,因为有的bean只需单实例

bean定义是给bean工厂创建bean用的,那么bean定义接口应该向bean工厂提供哪些方法?

获取bean类名:getBeanClass() :Class
获取工厂方法名:getFactoryMethodName() :String
获取工厂bean名:getFactoryBeanName() :String
是否是单例等方法: getScope() :String   isSingleton()   isPrototype()

类对象交给IOC容器管理,类对象的生命周期中还可能有什么生命阶段事情要做?

比如创建对象后可能需要进行一些初始化
有的对象在销毁时可能要进行一些特定的销毁逻辑(比如释放资源)
那就再bean定义中提供让用户可指定初始化、销毁方法
对bean工厂就需要提供 getInitMethodName()  getDestroyMethodName()

那么就有了下图:

076a868a6742abc766ba4e77685338e1.png

92f2e1d5eda20d8f6a76229e6a1e5260.png

会看到StringUtils的 isBank 方法,来普及一下和 isEmpty() 的区别

StringUtils

想要用的话需要引入依赖:

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
</dependency>

BeanDefinition(bean定义)接口的java实现:

import org.apache.commons.lang3.StringUtils;

public interface BeanDefinition {
    String SCOPE_SINGLETON = "singleton";
    String SCOPE_PROTOTYPE = "prototype";
    /**
     * 类
     */
    Class<?> getBeanClass();
    /**
     * Scope
     */
    String getScope();
    /**
     * 是否单例
     */
    boolean isSingleton();
    /**
     * 是否原型
     */
    boolean isPrototype();
    /**
     * 工厂bean名
     */
    String getFactoryBeanName();
    /**
     * 工厂方法名
     */
    String getFactoryMethodName();
    /**
     * 初始化方法
     */
    String getInitMethodName();
    /**
     * 销毁方法
     */
    String getDestroyMethodName();
    /**
     * 校验bean定义的合法性
     */
    default boolean validate() {
        // 没定义class,工厂bean或工厂方法没指定,则不合法。
        if (this.getBeanClass() == null) {
            if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
                return false;
            }
        }
        // 定义了类,又定义工厂bean,不合法
        if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
            return false;
        }
        return true;
    }
}

BeanDefinition(bean定义)接口的实现类GenericBeanDefinition,通用的bean定义:

import org.apache.commons.lang3.StringUtils;

public class GenericBeanDefinition implements BeanDefinition {
    private Class<?> beanClass;

    private String scope = BeanDefinition.SCOPE_SINGLETON;

    private String factoryBeanName;

    private String factoryMethodName;

    private String initMethodName;

    private String destroyMethodName;

    public void setBeanClass(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public void setScope(String scope) {
        if (StringUtils.isNotBlank(scope)) {
            this.scope = scope;
        }
    }

    public void setFactoryBeanName(String factoryBeanName) {
        this.factoryBeanName = factoryBeanName;
    }

    public void setFactoryMethodName(String factoryMethodName) {
        this.factoryMethodName = factoryMethodName;
    }

    public void setInitMethodName(String initMethodName) {
        this.initMethodName = initMethodName;
    }

    public void setDestroyMethodName(String destroyMethodName) {
        this.destroyMethodName = destroyMethodName;
    }

    @Override
    public Class<?> getBeanClass() {
        return this.beanClass;
    }

    @Override
    public String getScope() {
        return this.scope;
    }

    @Override
    public boolean isSingleton() {
        return BeanDefinition.SCOPE_SINGLETON.equals(this.scope);
    }

    @Override
    public boolean isPrototype() {
        return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope);
    }

    @Override
    public String getFactoryBeanName() {
        return this.factoryBeanName;
    }

    @Override
    public String getFactoryMethodName() {
        return this.factoryMethodName;
    }

    @Override
    public String getInitMethodName() {
        return this.initMethodName;
    }

    @Override
    public String getDestroyMethodName() {
        return this.destroyMethodName;
    }

    @Override
    public String toString() {
        return "GenericBeanDefinition [beanClass=" + beanClass + ", scope=" + scope + ", factoryBeanName="
                + factoryBeanName + ", factoryMethodName=" + factoryMethodName + ", initMethodName=" + initMethodName
                + ", destroyMethodName=" + destroyMethodName + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode());
        result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode());
        result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode());
        result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());
        result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode());
        result = prime * result + ((scope == null) ? 0 : scope.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        GenericBeanDefinition other = (GenericBeanDefinition) obj;
        if (beanClass == null) {
            if (other.beanClass != null)
                return false;
        } else if (!beanClass.equals(other.beanClass))
            return false;
        if (destroyMethodName == null) {
            if (other.destroyMethodName != null)
                return false;
        } else if (!destroyMethodName.equals(other.destroyMethodName))
            return false;
        if (factoryBeanName == null) {
            if (other.factoryBeanName != null)
                return false;
        } else if (!factoryBeanName.equals(other.factoryBeanName))
            return false;
        if (factoryMethodName == null) {
            if (other.factoryMethodName != null)
                return false;
        } else if (!factoryMethodName.equals(other.factoryMethodName))
            return false;
        if (initMethodName == null) {
            if (other.initMethodName != null)
                return false;
        } else if (!initMethodName.equals(other.initMethodName))
            return false;
        if (scope == null) {
            if (other.scope != null)
                return false;
        } else if (!scope.equals(other.scope))
            return false;
        return true;
    }
}

看看现在都有什么了:下图是bean定义

a48c4d68b14354c8feac7f62c2f0bd54.png
下来需要实现 BeanFactory(bean工厂)了。

3949ca0e078a77f73c72b17ba9a76c3d.png
实现一个默认的bean工厂:DefaultBeanFactory

1bbb90371b199a6dcbda3065b545e092.png
思考一下:需要实现这两个接口的话,
1、实现BeanDefinitionRegistry(上图右边右边的Bean定义信息注册)
  1.1、bean定义信息如何存放?
        Map,concurrentHashMap
  1.2、bean定义是否可以重名?重名了怎么办?
        自定义吧,想怎么实现就怎么实现,抛异常等等。

2、实现beanFactory(bean工厂)(上图左边)
  2.1、创建bean用什么存放?
        Map、concurrentHashMap
  2.2、在getBean()中要做哪些事?
        创建bean实例,并进行初始化

现在把BeanFactory这个接口写出:

public interface BeanFactory {
    /**
     * 获取bean
     *
     * @param name
     *            bean的名字
     * @return bean 实例
     * @throws Exception
     */
    Object getBean(String name) throws Exception;

}

再把BeanDefinitionRegistry这个接口写出来:

public class BeanDefinitionRegistException extends Exception {
    private static final long serialVersionUID = 6056374114834139330L;

    public BeanDefinitionRegistException(String mess) {
        super(mess);
    }

    public BeanDefinitionRegistException(String mess, Throwable e) {
        super(mess, e);
    }
}
public interface BeanDefinitionRegistry {
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException;

    BeanDefinition getBeanDefinition(String beanName);

    boolean containsBeanDefinition(String beanName);

}

实现一个默认的bean工厂:DefaultBeanFactory:

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;



public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {

    private final Log logger = LogFactory.getLog(getClass());

    // map的key是String,value是BeanDefinition
    private Map<String, BeanDefinition> beanDefintionMap = new ConcurrentHashMap<>(256);
    // 单纯的一个ConcurrentHashMap
    private Map<String, Object> beanMap = new ConcurrentHashMap<>(256);

    // BeanDefinitionRegistry接口里的方法
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException {
        Objects.requireNonNull(beanName,"注册bean需要给入beanName");
        Objects.requireNonNull(beanDefinition,"注册bean需要给入beanDefinition(bean定义)");

        // 校验给入的bean是否合法,如果不合法就抛异常
        if(!beanDefinition.validate()){
            throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义不合法:" + beanDefinition);
        }
        //如果BeanDefinition中已经有了这个bean的定义,也抛异常
        if (this.containsBeanDefinition(beanName)) {
            throw new BeanDefinitionRegistException(
                    "名字为[" + beanName + "] 的bean定义已存在:" + this.getBeanDefinition(beanName));
        }
        //bean是合法的,且BeanDefinition中没有这个bean的定义,把这个beanName,beanDefinition存到Map里
        this.beanDefintionMap.put(beanName, beanDefinition);
    }

    // BeanDefinitionRegistry接口里的方法
    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        // 得到bean定义需要从map里去取,如果能取到那就返回BeanDefinition
        // 如果从map里取不到,则为null
        return this.beanDefintionMap.get(beanName);
    }

    // BeanDefinitionRegistry接口里的方法
    @Override
    public boolean containsBeanDefinition(String beanName) {
        return this.beanDefintionMap.containsKey(beanName);
    }


    // BeanFactory接口中的方法
    @Override
    public Object getBean(String name) throws Exception {
        // 调用doGetBean
        return this.doGetBean(name);
    }

    // 希望只有子类可以用,所以定义为protected,本类自定义的方法
    protected Object doGetBean(String beanName) throws Exception{
        // 如果 beanName 为null 那么抛异常
        Objects.requireNonNull(beanName, "beanName不能为空");
        // 从Map里获取,这个beanMap是一个单纯的map。
        Object instance = beanMap.get(beanName);

        if (instance != null) {
            // 如果 instance != null 就是获取到了instance ,那么就直接返回
            return instance;
        }
        // 如果没有 instance的话,就得取到bean定义,也就是从map里获取
        // 这个getBeanDefinition(beanName);方法返回的就是从map里获取的
        BeanDefinition bd = this.getBeanDefinition(beanName);

        // 如果bean定义为空 那么抛异常
        Objects.requireNonNull(bd, "beanDefinition不能为空");

        // 如果bean定义不为空 那么就获取调用getBeanClass
        // 这个getBeanClass是 接口BeanDefinition中的方法。
        // GenericBeanDefinition是BeanDefinition的实现类,实现类里
        // 这个getBeanClass()方法返回了一个实例字段
        // private Class<?> beanClass;
        Class<?> type = bd.getBeanClass();
        if (type != null) {
            if (StringUtils.isBlank(bd.getFactoryMethodName())) {
                // 构造方法来构造对象
                instance = this.createInstanceByConstructor(bd);
            } else {
                // 静态工厂方法
                instance = this.createInstanceByStaticFactoryMethod(bd);
            }
        } else {
            // 工厂bean方式来构造对象
            instance = this.createInstanceByFactoryBean(bd);
        }

        // 执行初始化方法
        this.doInit(bd, instance);

        if (bd.isSingleton()) {
            beanMap.put(beanName, instance);
        }

        return instance;



    }

    // 构造方法来构造对象
    private Object createInstanceByConstructor(BeanDefinition bd)
            throws InstantiationException, IllegalAccessException {
        try {
            return bd.getBeanClass().newInstance();
        } catch (SecurityException e1) {
            logger.error("创建bean的实例异常,beanDefinition:" + bd, e1);
            throw e1;
        }
    }

    // 静态工厂方法
    private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
        Class<?> type = bd.getBeanClass();
        Method m = type.getMethod(bd.getFactoryMethodName(), null);
        return m.invoke(type, null);
    }

    // 工厂bean方式来构造对象
    private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {

        Object factoryBean = this.doGetBean(bd.getFactoryBeanName());

        Method m = factoryBean.getClass().getMethod(bd.getFactoryMethodName(), null);

        return m.invoke(factoryBean, null);
    }

    /**
     * 执行初始化方法
     *
     * @param bd
     * @param instance
     * @throws Exception
     */
    private void doInit(BeanDefinition bd, Object instance) throws Exception {
        // 执行初始化方法
        if (StringUtils.isNotBlank(bd.getInitMethodName())) {
            Method m = instance.getClass().getMethod(bd.getInitMethodName(), null);
            m.invoke(instance, null);
        }
    }

    @Override
    public void close() throws IOException {
        // 执行单例实例的销毁方法
        for (Entry<String, BeanDefinition> e : this.beanDefintionMap.entrySet()) {
            String beanName = e.getKey();
            BeanDefinition bd = e.getValue();

            if (bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())) {
                Object instance = this.beanMap.get(beanName);
                try {
                    Method m = instance.getClass().getMethod(bd.getDestroyMethodName(), null);
                    m.invoke(instance, null);
                } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                        | InvocationTargetException e1) {
                    logger.error("执行bean[" + beanName + "] " + bd + " 的 销毁方法异常!", e1);
                }
            }
        }
    }

}

对于单例的bean,可否提前实例化?有什么好处?

可以,好处就是:使用的时候,会快一点,空间换时间,线程安全,

扩展DefaultBeanFactory增加提前实例化单例bean的功能。

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.List;

public class PreBuildBeanFactory extends DefaultBeanFactory {
    private final Log logger = LogFactory.getLog(getClass());

    private List<String> beanNames = new ArrayList<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionRegistException {
        super.registerBeanDefinition(beanName, beanDefinition);
        synchronized (beanNames) {
            beanNames.add(beanName);
        }
    }

    public void preInstantiateSingletons() throws Exception {
        synchronized (beanNames) {
            for (String name : beanNames) {
                BeanDefinition bd = this.getBeanDefinition(name);
                if (bd.isSingleton()) {
                    this.doGetBean(name);
                    if (logger.isDebugEnabled()) {
                        logger.debug("preInstantiate: name=" + name + " " + bd);
                    }
                }
            }
        }
    }
}

接下来就可以测试代码了:

测试准备

public class ABean {
    public void doSomthing() {
        System.out.println(System.currentTimeMillis() + " " + this);
    }

    public void init() {
        System.out.println("ABean.init() 执行了");
    }

    public void destroy() {
        System.out.println("ABean.destroy() 执行了");
    }

}
public class ABeanFactory {
    public static ABean getABean() {
        return new ABean();
    }

    public ABean getABean2() {
        return new ABean();
    }

}

DefaultBeanFactoryTest 测试:

import org.junit.Test;
import org.junit.AfterClass;

public class DefaultBeanFactoryTest {
    static DefaultBeanFactory bf = new DefaultBeanFactory();

    @Test
    public void testRegist() throws Exception {

        // 创建通用的bean定义
        GenericBeanDefinition bd = new GenericBeanDefinition();

        // 把 GenericBeanDefinition中 private Class<?> beanClass;
        // 给一个初始值为 ABean.class
        // private Class<?> beanClass = ABean.class
        bd.setBeanClass(ABean.class);
        bd.setScope(BeanDefinition.SCOPE_SINGLETON);
        // bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);

        bd.setInitMethodName("init");
        bd.setDestroyMethodName("destroy");

        // 把bd注册到bean工厂中
        // registerBeanDefinition 是BeanDefinitionRegistry接口里的方法
        // DefaultBeanFactory 实现了 BeanFactory, BeanDefinitionRegistry, Closeable 接口
        bf.registerBeanDefinition("aBean", bd);

    }

    @Test
    public void testRegistStaticFactoryMethod() throws Exception {
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(ABeanFactory.class);
        bd.setFactoryMethodName("getABean");
        bf.registerBeanDefinition("staticAbean", bd);
    }

    @Test
    public void testRegistFactoryMethod() throws Exception {
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(ABeanFactory.class);
        String fbname = "factory";
        bf.registerBeanDefinition(fbname, bd);

        bd = new GenericBeanDefinition();
        bd.setFactoryBeanName(fbname);
        bd.setFactoryMethodName("getABean2");
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);

        bf.registerBeanDefinition("factoryAbean", bd);
    }

    @AfterClass
    public static void testGetBean() throws Exception {
        System.out.println("构造方法方式------------");
        for (int i = 0; i < 3; i++) {
            ABean ab = (ABean) bf.getBean("aBean");
            ab.doSomthing();
        }

        System.out.println("静态工厂方法方式------------");
        for (int i = 0; i < 3; i++) {
            ABean ab = (ABean) bf.getBean("staticAbean");
            ab.doSomthing();
        }

        System.out.println("工厂方法方式------------");
        for (int i = 0; i < 3; i++) {
            ABean ab = (ABean) bf.getBean("factoryAbean");
            ab.doSomthing();
        }

        bf.close();
    }
}

运行结果:

构造方法方式------------
ABean.init() 执行了
1587625018827 com.spring.test.ABean@1eb44e46
1587625018827 com.spring.test.ABean@1eb44e46
1587625018827 com.spring.test.ABean@1eb44e46
静态工厂方法方式------------
1587625018827 com.spring.test.ABean@515f550a
1587625018827 com.spring.test.ABean@515f550a
1587625018827 com.spring.test.ABean@515f550a
工厂方法方式------------
1587625018827 com.spring.test.ABean@626b2d4a
1587625018827 com.spring.test.ABean@5e91993f
1587625018827 com.spring.test.ABean@1c4af82c
ABean.destroy() 执行了

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值