狐言不胡言

导航

手写Spring DI依赖注入,嘿,你的益达!


在这里插入图片描述

上一篇文章中说到,如何手写Spring IOC容器,有了IOC,下面就是手写DI了,根据上一篇文章中的代码继续往下进行,手写Spring IOC入口:点击链接

提前实例化单例Bean

对于单例Bean,可以使用下面的方法进行提前实例化

/**
 * 提前构建单例bean的工程
 */
public class PreBuildBeanFactory extends DefaultBeanFactory {

	private final Logger logger = LoggerFactory.getLogger(getClass());

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

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionRegisterException {
		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);
					}
				}
			}
		}
	}
}

DI分析

哪些地方会有依赖呢,都知道DI依赖注入有setter注入,构造器注入等,那么就可以知道,有下面两种依赖:

  1. 构造参数依赖
  2. 属性依赖

依赖注入的本质就是给值,给入构造参数的值,给属性赋值

参数值和属性值是不是可以是基本的一些值,也有可能是bean依赖,比如会有基本数据类型值、String、数组、集合、map、properties等

不论是参数值还是属性值,这些都是值,bean工厂在进行依赖注入的时候就是给入值

DI的实现

构造参数依赖

一:定义分析

看下面一段代码:

public class Girl {
    public Girl(String name, int age, Boy boy) {
        //.......
    }
}

上面代码就是简单的一个类,构造方法里面有一些参数,那么平时创建Girl的时候就是通过new的方式,即:

 Boy boy = new Boy("小明");
 Girl girl = new Girl("小芳", 18, boy);

把值直接给Girl,就可以创建一个Girl了,就是这么的简单

那定义构造参数依赖的话,完全可以按照下面这样:

  • 第一个参数值是:"小芳"
  • 第二个参数值是:18
  • 第三个参数值是:Boy,是一个bean依赖

构造参数值可以有多个,而且是有顺序的,如果顺序错了,那么参数的类型可能就对应不上,就会出错,java中的list可以用来存储构造参数,它是有序的对吧;因为参数值可以是直接的值,比如基本类型、string、map等,也可以是一个bean依赖,那么只能用Object来表示

用Object来表示的话,还会有一个问题,就是bean依赖怎么去区分它呢

可以自己定义一种数据类型来表示bean依赖,当bean工厂在构造Bean实例的时候,遍历参数,判断参数是不是自己定义的数据类型,如果是的话,就替换成依赖的bean实例

如果说参数值是集合、数组,它们中也有bean依赖的话,同样的,需要对它们进行遍历,然后替换

二:定义一个类BeanReference

BeanReference这个类就是用来说明Bean依赖的,依赖的是哪一个bean
在这里插入图片描述

/**
 * @className: BeanReference
 * @description: 在依赖注入中描述bean依赖的
 * @date: 2021/4/6 13:25
 * @author: jinpeng.sun
 */
public class BeanReference {

    /** beanName */
    private String beanName;

    public BeanReference(String beanName) {
        super();
        this.beanName = beanName;
    }

    /** 获取beanName */
    public String getBeanName() {
        return this.beanName;
    }
}

三:BeanDefinition接口及其实现类

定义好了构造参数后,就需要在bean工厂中进行注入,首先要在BeanDefinition接口中增加获取构造参数的接口,然后在实现类中实现它

image.png
BeanDefinition增加下面两个接口:

   /** 获取构造函数的参数 */
    List<?> getConstructorArgumentValues();

    /** 设置构造函数的参数 */
    void setConstructorArgumentValues(List<?> constructorArgumentValues);

GeneralBeanDefinition实现类中增加如下实现代码:

    //构造参数集合
    private List<?> constructorArgumentValues;

    @Override
    public List<?> getConstructorArgumentValues() {
        return constructorArgumentValues;
    }

    @Override
    public void setConstructorArgumentValues(List<?> constructorArgumentValues) {
        this.constructorArgumentValues = constructorArgumentValues;
    }

到此,我们就可以获取到构造参数依赖了,下面就是实现构造参数依赖的注入了

四:DefaultBeanFactory类增加方法

根据上面的内容可以知道,构造参数中会存在bean依赖,那么首先就是需要把bean定义中的构造参数引用转为真实的值,在DefaultBeanFactory类中增加一个方法来做这件事情
在这里插入图片描述

    /** 获取构造参数值 */
    private Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {
        return this.getRealValues(bd.getConstructorArgumentValues());
    }

    /** 获取真实的参数值 */
    private Object[] getRealValues(List<?> args) throws Exception {
        //参数为空,直接返回null
        if (CollectionUtils.isEmpty(args)) {
            return null;
        }
        //定义一个数组,长度和传过来的参数值集合大小一致
        Object[] values = new Object[args.size()];
        int i = 0;
        Object v = null;
        //遍历参数值,替换bean依赖的实例
        for (Object rv : args) {
            if (rv == null) {
                v = null;
            } else if (rv instanceof BeanReference) {
                //TODO 获取引用的bean依赖的实例
                v = doGetBean(((BeanReference) rv).getBeanName());
            } else  if (rv instanceof Object[]) {
               //TODO 处理数组中的bean引用
            } else  if (rv instanceof Collection) {
               //TODO 处理集合中的bean引用
            } else  if (rv instanceof Properties) {
               //TODO 处理Properties中的bean引用
            } else  if (rv instanceof Map) {
               //TODO 处理Map中的bean引用
            } else {
                //TODO 基本类型
                v = rv;
            }
            values[i++] = v;
        }
        return values;
    }

五:构造参数注入实现

参数有了后,又怎么知道哪个是构造方法,哪个是工厂方法呢?

方法是可以重载的;而且形参定义的可能是接口和父类,实参则是具体的子类实现的

反射提供的获取构造方法和基本方法的API如下:
在这里插入图片描述
判断逻辑:

  • 先使用第一个方法,根据参数的类型进行精确的匹配查找,如果没有找到就使用下一步
  • 获得所有的构造方法,进行遍历,先通过参数数量过滤,再对比形参类型和实参类型

当判断出构造方法或者工厂方法后,对于原型bean,即多例的bean,可以缓存下这个构造方法或者工厂方法,当下一次获取的时候,可以直接从缓存中获取

在BeanDefinition接口中增加如下接口:

   /** 获取构造方法 */
    Constructor<?> getConstructor();

    /** 设置构造方法 */
    void setConstructor(Constructor<?> constructor);

    /** 获取工厂方法 */
    Method getFactoryMethod();

    /** 设置工厂方法 */
    void setFactoryMethod(Method factoryMethod);

GeneralBeanDefinition实现类中进行实现:

    //构造方法
    private Constructor<?> constructor;
    //工厂方法
    private Method factoryMethod;
    
    @Override
    public Constructor<?> getConstructor() {
        return constructor;
    }

    @Override
    public void setConstructor(Constructor<?> constructor) {
        this.constructor = constructor;
    }

    @Override
    public Method getFactoryMethod() {
        return factoryMethod;
    }

    @Override
    public void setFactoryMethod(Method factoryMethod) {
        this.factoryMethod = factoryMethod;
    }

下面就是实现寻找构造方法或者工厂方法了

    /** 查找构造方法 */
    private Constructor determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
        Constructor ct = null;
        //参数为空的情况
        if (args == null) {
            return bd.getBeanClass().getConstructor(null);
        }
        //定义一个参数数组,长度为传过来的构造参数集合大小
        Class<?>[] paramTypes = new Class[args.length];

        //对于原型bean,从第二次开始获取Bean实例开始,可以从缓存中获取
        ct = bd.getConstructor();
        if (ct != null) {
            return ct;
        }

        //1.根据构造参数类型获取构造方法
        int i = 0;
        for (Object p : args) {
            paramTypes[i++] = p.getClass();
        }
        ct = bd.getBeanClass().getConstructor(paramTypes);
        //2.获取所有的构造方法,遍历
        if (ct == null) {
            Constructor<?>[] cts = bd.getBeanClass().getConstructors();
            //先判断参数数量,然后依次判断形参和实参
            outer: for (Constructor c : cts) {
                //获取构造方法中的参数
                Class<?>[] parameterTypes = c.getParameterTypes();
                if (parameterTypes.length == args.length) {
                    for (int j =0; i< parameterTypes.length; j++) {
                        if (!parameterTypes[i].isAssignableFrom(args[j].getClass())) {
                            continue outer;
                        }
                    }
                    ct = c;
                    break outer;
                }
            }
        }
        if (ct != null) {
            //对于原型bean,缓存起来
            if (bd.isProtoType()) {
                bd.setConstructor(ct);
            }
        } else {
            throw new Exception("找不到对应的构造方法:" + bd);
        }
        return ct;
    }

修改通过构造函数构建bean实例的方法:

    /** 通过构造函数构建bean */
    private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
        Object object = null;
        if (CollectionUtils.isEmpty(bd.getConstructorArgumentValues())) {
            //获得的构造参数值是空的,就不传参
            object = bd.getBeanClass().newInstance();
        } else {
            //获得的参数值是空的,就不传参
            Object[] args = getConstructorArgumentValues(bd);
            if (args == null) {
                object = bd.getBeanClass().newInstance();
            } else {
                //调用方法,实现构造参数依赖注入
                return determineConstructor(bd, args).newInstance(args);
            }
        }
        return object;
    }

构造方法的方式写好后,按照上面的逻辑来实现静态工厂和工厂方法获取bean实例的方法

private Method determineFactoryMethod(BeanDefinition bd, Object[] realArgs,
                                      Class<?> type) throws Exception {
        if (type == null) {
            type = bd.getBeanClass();
        }
        //获取工厂方法名
        String factoryMethodName = bd.getFactoryMethodName();

        if (realArgs == null) {
            return type.getMethod(factoryMethodName, null);
        }
        Method m = null;

        //对于原型bean,从第二次开始获取Bean实例开始,可以从缓存中获取
        m = bd.getFactoryMethod();
        if (m != null) {
            return m;
        }

        //1.根据参数类型精确匹配方法
        Class[] paramTypes = new Class[realArgs.length];
        int i = 0;
        for (Object p : realArgs) {
            paramTypes[i++] = p.getClass();
        }

        try {
            m = type.getMethod(factoryMethodName, paramTypes);
        } catch (Exception e) {
            //不做任何处理
            m = null;
        }
        //2.获取所有的方法,然后遍历
        if (m == null) {
            //先判断参数数量,然后依次判断形参和实参
            outer: for (Method m0 : type.getMethods()) {
                //方法名称不一样,直接继续遍历
                if (!m0.getName().equals(factoryMethodName)) {
                    continue ;
                }
                //获取找到方法的所有参数
                Class<?>[] parameterTypes = m0.getParameterTypes();
                if (parameterTypes.length == realArgs.length) {
                    for (int j =0; j< parameterTypes.length; j++) {
                        if (!parameterTypes[j].isAssignableFrom(realArgs[j].getClass())) {
                            continue outer;
                        }
                    }
                    m = m0;
                    break outer;
                }
            }
        }
        if (m != null) {
            //对于原型bean,缓存下方法
            if (bd.isProtoType()) {
                bd.setFactoryMethod(m);
            }
        } else {
            throw new Exception("找不到对应的方法:" + bd);
        }
        return m;
    }

然后下面修改通过静态工厂获取Bean和成员工厂获取Bean的方法

    /** 通过静态工厂构建bean */
    private Object createBeanByStaticFactoryMethod(BeanDefinition bd) throws Exception {
        Class<?> type = bd.getBeanClass();
        Object[] realArgs = getRealValues(bd.getConstructorArgumentValues());
        Method method = determineFactoryMethod(bd, realArgs, type);
        Object object = method.invoke(type, realArgs);
        return object;
    }
    /** 通过成员工厂构建bean */
    private Object createBeanByFactoryBean(BeanDefinition bd) throws Exception {
        String factoryBeanName = bd.getFactoryBeanName();
        Object factoryBean = getBean(factoryBeanName);
        Object[] realArgs = getRealValues(bd.getConstructorArgumentValues());
        Method method = determineFactoryMethod(bd, realArgs, factoryBean.getClass());
        Object object = method.invoke(factoryBean, realArgs);
        return object;
    }

六:构造参数依赖测试

测试使用的几个类:

public interface Boy {
    void sayLove();
    void play();
}
public class Lad implements Boy {

    private String name;

    private Girl girl;

    private Money money;

    public Lad(String name) {
        this.name = name;
    }
    public Lad(String name, Girl gf) {
        this.name = name;
        this.girl = gf;
        System.out.println("调用了含有Girl参数的构造方法");
    }
    public Lad(String name, MagicGirl gf) {
        this.name = name;
        this.girl = gf;
        System.out.println("调用了含有MMagicGirll参数的构造方法");
    }
    public Lad(String name, Money m) {
        this.name = name;
        this.money = m;
        System.out.println("调用了含有Money参数的构造方法");
    }

    public Girl getFriend() {
        return girl;
    }

    public void setFriend(Girl girl) {
        this.girl = girl;
    }

    @Override
    public void sayLove() {
        if (girl == null) {
            System.out.println("没有对象好难过!" + hashCode());
        } else {
            System.out.println("我爱你,亲爱的!" + girl);
        }
    }

    @Override
    public void play() {
        if (money == null) {
            System.out.println("没有钱怎么玩!" + hashCode());
        } else {
            System.out.println("有了钱开心的玩耍!" + money);
        }
    }

    public void init() {
        System.out.println("老天赐予我一个对象吧!");
    }

    public void destroy() {
        System.out.println("自古多情空余恨,此恨绵绵无绝期!");
    }
}
public interface Girl {

}
public class MagicGirl implements Girl {
    private String name;
    private Boy friend;
    public MagicGirl(){}
    public MagicGirl(String name) {
        this.name = name;
    }

    public Boy getFriend() {
        return friend;
    }
    public void setFriend(Boy friend) {
        this.friend = friend;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "MagicGril{" +
                "name='" + name + '\'' +
                '}';
    }
}
public interface Money {
    void pay();
}
public class Renminbi implements Money {

    @Override
    public void pay() {
        System.out.println("使用人民币成功进行了支付");
    }
}
public class BoyFactory {

    public static Boy getBean(String name, Money money) {
        return new Lad(name, money);
    }
}
public class BoyFactoryBean {

    public Boy buildBoy(String name, Girl girl) {
        return new Lad(name, girl);
    }
}

构造函数注入测试:

   static PreBuildBeanFactory bf = new PreBuildBeanFactory();

    /** 构造函数注入测试 */
    @Test
    public void testConstructorDI() throws Exception {
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(Lad.class);
        //设置构造函数的参数
        List<Object> args = new ArrayList<>();
        args.add("孙悟空");
        args.add(new BeanReference("magicGirl"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("swk", definition);

        definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(MagicGirl.class);
        //设置构造函数的参数
        args = new ArrayList<>();
        args.add("白骨精");
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("magicGirl", definition);

        bf.preInstantiateSingletons();

        Lad lad = (Lad) bf.getBean("swk");
        lad.sayLove();
    }

执行结果:
在这里插入图片描述
静态工厂注入测试:

    /** 静态工厂注入测试 */
    @Test
    public void testStaticFactoryDI() throws Exception {
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(BoyFactory.class);
        //设置方法名
        definition.setFactoryMethodName("getBean");
        //设置构造函数的参数
        List<Object> args = new ArrayList<>();
        args.add("牛郎");
        args.add(new BeanReference("rmb"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("nl", definition);

        definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(Renminbi.class);
        bf.registerBeanDefinition("rmb", definition);

        bf.preInstantiateSingletons();

        Boy boy = (Boy) bf.getBean("nl");
        boy.play();
    }

执行结果:
在这里插入图片描述
成员工厂注入测试:

/** 成员工厂注入测试 */
    @Test
    public void testFactoryMethodDI() throws Exception {
        GenericBeanDefinition definition = new GenericBeanDefinition();

        String fBeanName = "boyFactoryBean";
        //设置工厂bean
        definition.setFactoryBeanName(fBeanName);
        //设置方法名
        definition.setFactoryMethodName("buildBoy");
        //设置构造函数的参数
        List<Object> args = new ArrayList<>();
        args.add("猪八戒");
        args.add(new BeanReference("xlv"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("zbj", definition);

        definition = new GenericBeanDefinition();
        definition.setBeanClass(BoyFactoryBean.class);
        bf.registerBeanDefinition("boyFactoryBean", definition);

        definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(MagicGirl.class);
        bf.registerBeanDefinition("xlv", definition);

        bf.preInstantiateSingletons();

        Boy boy = (Boy) bf.getBean("zbj");
        boy.sayLove();
    }

执行结果:
在这里插入图片描述

循环依赖的处理

当我们构建对象的时候,可以循环依赖吗?

写个例子测试一下:

public class NiuLang {

    private ZhiNv zhiNv;

    public NiuLang(ZhiNv zhiNv) {
        this.zhiNv = zhiNv;
    }
}
public class ZhiNv {

    private NiuLang niuLang;

    public ZhiNv(NiuLang niuLang) {
        this.niuLang = niuLang;
    }
}

测试类:

    @Test
    public void testCycleDI() throws Exception {
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(NiuLang.class);
        //设置构造函数的参数
        List<Object> args = new ArrayList<>();
        args.add(new BeanReference("zv"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("nl", definition);


        definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(Renminbi.class);
        //设置构造函数的参数
        args = new ArrayList<>();
        args.add(new BeanReference("nl"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("zv", definition);

        bf.preInstantiateSingletons();
    }

运行结果:
在这里插入图片描述
可以看到,出现了错误

如果构建实例对象时循环依赖了,就会陷入僵死的局面,所以这个是不允许的

那么,可以在工厂的实现类中,加入一个正在构建的Bean的记录,当这个Bean正在构建的时候,就加入到这个记录中,构建完成就删除这个记录;如果有依赖,就看这个依赖是否在构建中,如果是的话就构成了循环依赖,就抛出异常就可以了

   /** 正在创建的bean */
    private Set<String> buildingBeans = Collections.newSetFromMap(new ConcurrentHashMap());

在doGetBean方法中加入如下代码:

       Set<String> beans = buildingBeans;

        //检测循环依赖
        if (beans.contains(beanName)) {
            throw new Exception(beanName + "循环依赖" + beans);
        }

        beans.add(beanName);
        //bean实例创建完后删除
        beans.remove(beanName);

        //对单例bean的处理
        if (bd.isSingleton()) {
            beanMap.put(beanName, bean);
        }

再次运行结果:
在这里插入图片描述

属性依赖

属性依赖即是某个属性依赖于某个值

如果需要描述一个属性依赖,就是属性名+值,那么可以定义一个类来表示属性依赖

如果有多个属性,也是使用List进行存储,属性依赖的处理情况和构造参数值基本上是一样的

public class Girl {
    
    private String name;

    private Integer age;

    private Boy boy;
}

一:属性依赖的定义

定义类PropertyValue用来表示属性依赖
在这里插入图片描述

**
 * @className: PropertyValue
 * @description: 属性值类型,用做属性依赖注入
 * @date: 2021/4/7 09:11
 * @author: jinpeng.sun
 */
public class PropertyValue {

    private String name;

    private Object value;

    public PropertyValue(String name, Object value) {
        super();
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}

二:BeanDefinition接口及其实现类

BeanDefinition类增加下面两个接口:

    /** 获取属性值 */
    List<PropertyValue> getPropertyValues();

    /** 设置属性值 */
    void setPropertyValues(List<PropertyValue> propertyValues);

GeneralBeanDefinition实现类中增加相应的实现代码:

    //属性值
    private List<PropertyValue> propertyValues;

    @Override
    public List<PropertyValue> getPropertyValues() {
        return propertyValues;
    }

    @Override
    public void setPropertyValues(List<PropertyValue> propertyValues) {
        this.propertyValues = propertyValues;
    }

三:DefaultBeanFactory类中实现属性依赖

    /** 属性依赖 */
    private void setPropertyDIValues(BeanDefinition bd, Object bean) throws Exception {
        //获取不到属性值,直接返回
        if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
            return;
        }

        //遍历所有属性值
        for (PropertyValue pv : bd.getPropertyValues()) {
            String name = pv.getName();
            if (StringUtils.isBlank(name)) {
                continue;
            }
            Class<?> classz = bean.getClass();
            //获取属性
            Field p = classz.getDeclaredField(name);

            p.setAccessible(true);

            Object rv = pv.getValue();
            Object v = null;
            if (rv == null) {
                v = null;
            } else if (rv instanceof BeanReference) {
                v = doGetBean(((BeanReference) rv).getBeanName());
            } else  if (rv instanceof Object[]) {
                //TODO 处理数组中的bean引用
            } else  if (rv instanceof Collection) {
                //TODO 处理集合中的bean引用
            } else  if (rv instanceof Properties) {
                //TODO 处理Properties中的bean引用
            } else  if (rv instanceof Map) {
                //TODO 处理Map中的bean引用
            } else {
                //基本类型
                v = rv;
            }
            p.set(bean, v);
        }
    }

属性依赖是在bean实例创建完成之后,bean初始化之前调用的,所以需要改下doGetBean方法

    @Override
    public Object getBean(String beanName) throws Exception {
        //获取bean定义
        BeanDefinition bd = beanDefinitionMap.get(beanName);
        Object bean = doGetBean(beanName);

        //属性注入
        setPropertyDIValues(bd, bean);

        //bean的生命周期
        if (StringUtils.isNotBlank(bd.getInitMethodName())) {
            doInitMethod(bean,bd);
        }
        return doGetBean(beanName);
    }

    public Object doGetBean(String beanName) throws Exception {

        Object bean = beanMap.get(beanName);
        if (bean != null) {
            return bean;
        }

        //获取bean定义
        BeanDefinition bd = beanDefinitionMap.get(beanName);
        Objects.requireNonNull(bd, "找不到["+beanName+"]的bean定义信息");
        Class<?> type = bd.getBeanClass();

        //检测循环依赖
        Set<String> beans = this.buildingBeans;
        if (beans.contains(beanName)) {
            throw new Exception(beanName + "循环依赖" + beans);
        }
        beans.add(beanName);

        if (type != null) {
            if (StringUtils.isBlank(bd.getFactoryMethodName())) {
                //通过构造函数构建bean
                bean = createBeanByConstructor(bd);
            } else {
                //通过静态工厂构建bean
                bean = createBeanByStaticFactoryMethod(bd);
            }
        } else {
            //通过成员工厂构建bean
            bean = createBeanByFactoryBean(bd);
        }

        //实例创建完成后进行删除
        beans.remove(beanName);

        //对单例bean处理
        if (bd.isSingleton()) {
            beanMap.put(beanName, bean);
        }
        return bean;
    }

四:属性依赖测试

    /** 属性注入测试 */
    @Test
    public void testPropertyDI() throws Exception {
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(Lad.class);
        //设置构造函数的参数
        List<Object> args = new ArrayList<>();
        args.add("孙悟空");
        args.add(new BeanReference("bgj"));
        definition.setConstructorArgumentValues(args);
        bf.registerBeanDefinition("swk", definition);

        definition = new GenericBeanDefinition();
        //设置beanClass
        definition.setBeanClass(MagicGirl.class);
        //设置属性注入的参数值
        List<PropertyValue> propertyValues = new ArrayList<>();
        propertyValues.add(new PropertyValue("name", "白骨精"));
        propertyValues.add(new PropertyValue("friend", new BeanReference("swk")));
        definition.setPropertyValues(propertyValues);
        bf.registerBeanDefinition("bgj", definition);

        bf.preInstantiateSingletons();

        MagicGirl magicGirl = (MagicGirl) bf.getBean("bgj");
        System.out.println(magicGirl.getName() + ":" + magicGirl.getFriend());
        magicGirl.getFriend().sayLove();
    }

执行结果:
在这里插入图片描述
到此,手写Spring DI就结束了,希望本文对您有所帮助!

posted on 2021-04-17 11:29  狐言不胡言  阅读(212)  评论(0编辑  收藏  举报