IOC:Inversion of Control 控制反转,也称依赖倒置(本来由自己创建,反转为从IOC容器中获),IOC容器负责来创建类实例对象,需要就从IOC容器中get。也称IOC容器为Bean工厂,负责创建、管理类实例,向使用者提供实例

  • 代码更简洁,不需要去new要使用的对象了。
  • 面向接口编程,使用者与具体类解耦,易扩展、替换实现者。
  • 可以方便进行AOP增强。

如果我们自己要实现Bean工厂需要实现三个元素:

  1. Bean工厂接口 (ioc实现抽象接口,向用户提供获取bean的入口)
  2. Bean定义接口 (ioc容器创建对象,得向容器告知创建的信息,所以需要定义创建接口)
  3. Bean定义的注册接口(二者桥梁,需要将Bean工厂按照Bean定义接口生产出来的对象实现注入)

    创建三个Bean接口

    创建BeanFactory工厂接口

    功能:通过唯一的beanName从ioc容器(Map)中获取实例化的bean

    1. /**
    2. * @author heian
    3. * @date 2021/2/15 2:38 下午
    4. * @description bean工厂接口
    5. */
    6. public interface BeanFactory {
    7. Object getBean(String beanName) throws Exception;
    8. }

    创建BeanDefinition定义接口

    功能:首先我们思考怎样,如果你要去创建一个bean,一般的我们无非就是通过工厂(静态方法或者成员方法)或者构造方法去创建我们所需的bean。

  • 构造方法一般是直接拿到对应的beanClass反射newInstance即可。
  • 静态工厂同理拿到对应的beanClass和对应的工厂静态方法,然后通过下面代码得到对应实例化的bean

    Method method = beanClass.getMethod(beanDefinition.getFactoryMethodName(), null);
    Object bean = method.invoke(beanClass,null);//静态方法无需实例化对应的bean
    
  • 成员工厂则稍微有点不一样,显然你要通过成员工厂的方法来实例化一个bean,必须要有一个实例化的工厂bean,获取这个bean则必须要有对应的工厂beanClass(直接newInstance拿到factoryBean),有了class在加上你的工厂方法名就能通过method.invoke来实例化你所需的bean,所以第一步需要生产出一个factoryBean,生产此bean则需要定义BeanDefinition,然后再定义另外一个BeanDefinition来拿到对应的实例化所需bean。注意:第一个BeanDefinition是为了获取factoryBean(类newInstance),第二个BeanDefinition定义factoryMethodName和facooryBeanName,因为通过可以通过facooryBeanName可以拿到对应的facotryBean(因为有了第一个BeanDefinition就可以生成一个facotryBean),再通过method.invoke(factoryBean,null) 就能实例化对应的工厂所产生的具体类

讲了这么对重点来了,要想创建一个类,无非就是通过三种方式创建(new 普通工厂和静态工厂),所以此类必须具备以下属性:

  1. 要知道你产生bean是否是单例,防止重复创建
  2. beanClass,这个有两个含义:第一个是普通构造方法的beanClass,第二个是静态工厂对应的class
  3. factoryMethodName静态工厂或者普通工厂的生产对象的方法名
  4. factoryBeanName 普通工厂的实例化后的factoryBean的名字
  5. 还有就是一些校验的方法和初始化以及销毁的方法 ```java import org.apache.commons.lang.StringUtils;

/**

  • @author heian
  • @date 2021/2/15 2:43 下午
  • @description Bean定义接口,告诉工厂如何创建某类bean */ public interface BeanDefinition {

    String SCOPE_SINGLETON = “singleton”; String SCOPE_PROTOTYPE = “prototype”;

/**
 * 获取bean的类名 构造函数和静态工厂创建对象所需
 */
Class<?> getBeanClass();
void setBeanClass(Class<?> beanClass);

String getScope();
void setScope(String scope);
boolean isSingleton();
boolean isPrototype();

String getFactoryMethodName();//获取个工厂(静态和动态)方法的名字
//工厂bean的名字 成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
void setFactoryMethodName(String factoryMethodName);


String getFactoryBeanName();
void setFactoryBeanName(String factoryBeanName);


default boolean validate(){
    //没有对应bean的class信息,意味着只能提供成员工厂构建
    if (getBeanClass() == null){
        if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())){
            return false;
        }
    }
    //class存在情况,还指定FactoryBeanName构建对象方式冲突
    if (getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())){
        return false;
    }
    return true;
}

/**
 * 类对,对象交给IOC容器管理,类对象的生命周期还有事情要做
 * 1.创建对象后可能需要进行一些初始化
 * 2.对象在销毁时肯需要进行一定的特定销毁的逻辑(如资源释放)
 * 3.bean定义中提供让用户指定初始化、销毁的方法
 * 4.对bean工厂提供getInitMethodName() getDestroyMethodName()
 */
void setInitMethod(String initMethod);
String getInitMethod();

void setDestroyMethod(String destroyMethod);
String getDestroyMethod();

}

<a name="7W2Tp"></a>
### 创建BeanDefinitionRegistry定义注册接口
```java
/**
 * @author heian
 * @date 2021/2/15 2:44 下午
 * @description Bean定义的注册接口,完成bean工厂和bean定义之间的桥梁
 */
public interface BeanDefinitionRegistry {

    /**
     * 向工厂注册定义的bean
     * @param beanDefinition 你想要的注册的bean的信息
     */
    void registerBeanDefinition(String beanName,BeanDefinition beanDefinition);

    /**
     * 获取已经注册的bean
     */
    BeanDefinition getBeanDefinition(String beanName);

    /**
     * 是否包含了已经定义的bean
     */
    boolean containsBeanDefinition(String beanName);
}

因为你要创建实例化bean,就必须知道你要怎样创建,所以需要一个类来按照你的意思来创建所需的bean,就需要一个一个通用的BeanDefition的实现。

创建GenericBeanDefinition定义实现

package com.dongnaoedu.network.spring.bean;

/**
 * @author heian
 * @date 2021/2/15 3:32 下午
 * @description 通用的定义注册的实现
 */
public class GenericBeanDefinition implements BeanDefinition{

    private Class<?> beanClass;
    private String factoryMethodName;//静态或者成员的工厂方法名
    private String factoryBeanName;//成员工厂需要用到,因为通过此name获取factoryBean 来invoke对应bean
    private String scope = BeanDefinition.SCOPE_SINGLETON;
    private String initMethod;
    private String destroyMethod;


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

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

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

    @Override
    public void setScope(String scope) {
        this.scope = scope;
    }

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

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

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

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

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

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

    @Override
    public void setInitMethod(String initMethod) {
        this.initMethod = initMethod;
    }

    @Override
    public String getInitMethod() {
        return this.initMethod;
    }

    @Override
    public void setDestroyMethod(String destroyMethod) {
        this.destroyMethod = destroyMethod;
    }

    @Override
    public String getDestroyMethod() {
        return this.destroyMethod;
    }
}

创建基础的默认工厂DefaultBeanFactory实现

这个类主要是对工厂接口以及对定义注册接口的基础实现,对工厂接口实现主要是为了生产实例化的bean,对定义注册接口实现主要是将定义的GenericBeanDefinition放入到缓存中,下次就可以直接通过名字拿到对应的BeanDefinition
image.png

import org.apache.commons.lang.StringUtils;

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.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author heian
 * @date 2021/2/15 3:37 下午
 * @description 通过反射机制实现工厂生产实例化bean
 */
public class DefaultBeanFactory implements BeanFactory,BeanDefinitionRegistry, Closeable {

    private Map<String,BeanDefinition> map = new ConcurrentHashMap<>();

    private Map<String,Object> beanMap = new ConcurrentHashMap<>();

    @Override
    public Object getBean(String beanName) throws Exception{
        Objects.requireNonNull(beanName,"beanName 不为空");
        //先去缓存中判断对象是否已经创建完成
        Object bean = beanMap.get(beanName);
        if (bean != null){
            return bean;
        }
        //创建对象的方式有三种:构造函数、静态工厂、成员工厂
        BeanDefinition beanDefinition = map.get(beanName);
        Objects.requireNonNull(beanDefinition,"beanDefinition 不存在");
        Class<?> beanClass = beanDefinition.getBeanClass();
        if (beanClass != null){
            //构造函数
            if (StringUtils.isBlank(beanDefinition.getFactoryMethodName())){
                bean = beanDefinition.getBeanClass().newInstance();
            }else {
                //提供静态工厂创建对象  (知道工厂类名和方法名即可创建对象)
                Method method = beanClass.getMethod(beanDefinition.getFactoryMethodName(), null);
                bean = method.invoke(beanClass,null);//静态方法无需实例化对应的bean
            }
        }else {
            //成员工厂构建对象 (不是工厂类  应该是工厂bean名FactoryBean + 工厂方法名)
            String factoryBeanName = beanDefinition.getFactoryBeanName();
            Object factoryBean = getBean(factoryBeanName);//静态工厂产生的FactoryBean
            if (factoryBean != null){
                Method method = factoryBean.getClass().getMethod(beanDefinition.getFactoryMethodName(), null);
                bean = method.invoke(factoryBean,null);
            }
        }
        //开始bean的生命周期
        if (StringUtils.isNotBlank(beanDefinition.getInitMethod())){
            Method method = bean.getClass().getMethod(beanDefinition.getInitMethod(), null);
            method.invoke(bean,null);
        }

        if (beanDefinition.isSingleton()){
            beanMap.put(beanName,bean);
        }
        return bean;
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        Objects.requireNonNull(beanName,"注册的bean需要指定 beanName");
        Objects.requireNonNull(beanDefinition,"注册的bean需要指定 beanDefinition");
        if(!beanDefinition.validate()) {
            throw new RuntimeException("名字为["+beanName+"]的bean定义不合法:"+beanDefinition);
        }
        if(containsBeanDefinition(beanName)) {
            throw new RuntimeException("名字为["+beanName+"]已存在:"+getBeanDefinition(beanName));
        }
        map.put(beanName,beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return null;
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return map.containsKey(beanName);
    }

    @Override
    public void close() throws IOException {
        //针对单例bean进行的销毁方法
        map.forEach((s, beanDefinition) -> {
            if (beanDefinition.isSingleton() && StringUtils.isNotBlank(beanDefinition.getDestroyMethod())){
                try {
                    Object bean = beanMap.get(s);
                    if (bean == null){
                        return;//不会终止循环
                    }
                    Method method = bean.getClass().getMethod(beanDefinition.getDestroyMethod(), null);
                    method.invoke(bean,null);
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //JVM关闭后会执行所有实现了Closeable接口的方法,也就是我们这个实现的close方法 此处不会用到
    public void destroy(){
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            //把所有实现closeable接口的参数都加上此代码
            try {
                close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }));
    }

}

image.png
值得一提的就是,因为在我们ioc容器中,大部分的bean实际上还是单例的,那既然是单例的我们就可以将其提前实例化,就是讲Map中所有的单例bean提前实例化而不是等到用到的时候再去实例化。其实也很简单,只要将我们map中存储的提前实例化即可。

提前实例化单例bean的SingletonBeanPreBuildFactory默认工厂实现

import java.util.ArrayList;
import java.util.List;

/**
 * @author heian
 * @date 2021/2/17 11:56 上午
 * @description 对于单例bean实行预先加载策略
 */
public class SingletonBeanPreBuildFactory extends DefaultBeanFactory{

    //存放那些beanNames
    private List<String> beanNames = new ArrayList<>();

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

    public void preInstantiateSingletons() throws Exception {
        synchronized (beanNames){
            //将存放在单例集合中的bean预先加载好
            for (String beanName : beanNames) {
                BeanDefinition definition = this.getBeanDefinition(beanName);
                if (definition.isSingleton()){
                    this.getBean(beanName);
                    System.out.println("preInstantiate: name=" + beanName + " " + definition);
                }
            }

        }
    }
}

测试成果

定义一个Boy接口,其中

  1. Lad类实现Boy接口并且外加init和destroy方法
  2. StaticBoyFactory静态工厂是对就是直接生产Lad类
  3. BoyFactory实现对Boy接口的实例化(匿名内部类) ```java public interface Boy { void sayLove(); }

public class Lad implements Boy { @Override public void sayLove() { System.out.println(“I love you, my dear!”+hashCode()); }

public void init() {
    System.out.println("我还没谈过恋爱,初始化一个对象吧");
}

public void destroy(){
    System.out.println("七夕到底是牵手还是分手?");
}

}

public class StaticBoyFactory {

public static Boy getBean() {
    return new Lad();
}

}

public class BoyFactory {

public Boy buildBoy() {
    return new Boy() {
        @Override
        public void sayLove() {
            System.out.println("I love you, my girl!" +hashCode());
        }
    };
}

}

<a name="ab3mq"></a>
### 测试类
```java
package bean;
import com.dongnaoedu.network.spring.bean.BeanDefinition;
import com.dongnaoedu.network.spring.bean.DefaultBeanFactory;
import com.dongnaoedu.network.spring.bean.GenericBeanDefinition;
import org.junit.Test;

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

    @Test
    public void testRegist() throws Exception {
        //普通的构造方法
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(Lad.class);
        bd.setScope(BeanDefinition.SCOPE_SINGLETON);
        // bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        bd.setInitMethod("init");
        bd.setDestroyMethod("destroy");
        bf.registerBeanDefinition("lad", bd);
        System.out.println("构造方法方式------------");
        for (int i = 0; i < 3; i++) {
            Boy boy = (Boy) bf.getBean("lad");
            boy.sayLove();
        }
    }
--运行结果    
构造方法方式------------
我还没谈过恋爱,初始化一个对象吧
I love you, my dear!1330106945
I love you, my dear!1330106945
I love you, my dear!1330106945


    @Test
    public void testRegistStaticFactoryMethod() throws Exception {
        //静态工厂
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(StaticBoyFactory.class);
        bd.setFactoryMethodName("getBean");
        bf.registerBeanDefinition("staticBoyFactory", bd);
        System.out.println("静态工厂方法方式------------");
        for (int i = 0; i < 3; i++) {
            Boy ab = (Boy) bf.getBean("staticBoyFactory");
            ab.sayLove();
        }
    }
--运行结果 
静态工厂方法方式------------
I love you, my dear!1330106945
I love you, my dear!1330106945
I love you, my dear!1330106945

    @Test
    public void testRegistFactoryMethod() throws Exception {
        //普通工厂
        String beanName1 = "factoryBean";//工厂bean
        String beanName2 = "factoryBoy";//你想要生成的实例bean

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(BoyFactory.class);
        bf.registerBeanDefinition(beanName1, bd);

        bd = new GenericBeanDefinition();
        bd.setFactoryBeanName(beanName1);
        bd.setFactoryMethodName("buildBoy");
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);

        bf.registerBeanDefinition(beanName2, bd);
        System.out.println("工厂方法方式------------");
        for (int i = 0; i < 3; i++) {
            Boy ab = (Boy) bf.getBean("factoryBoy");
            ab.sayLove();
        }
    }
 --运行结果
工厂方法方式------------
I love you, my girl!1330106945
I love you, my girl!1279149968
I love you, my girl!59559151

}