自己实现springioc源码(2)-解决循环依赖问题

解决循环依赖问题思路是使用二级缓存,创建了实例后先放入earlySingletonObjects中,加载所有属性成为成功实例后再放入singletonObjects中并从earlySingletonObjects中删除:

public static Map earlySingletonObjects = new HashMap<>();//单例对象,就存放半成品类型public static Map singletonObjects = new HashMap<>();//存放成品类型 

其实使用一级缓存也可以搞定,但是可是放到多线程的环境中,可能就会出现空指针问题。 线程1刚把半成品a放入到缓存中,还未来得及将b注入进去。此时线程2直接在缓存中获取到了a,在尝试调用其所依赖的b的任何方法时,就会出现空指针异常。 

代码如下:

public class Main3 {

    public static Map earlySingletonObjects = new HashMap<>();//存放成品类型
    public static Map singletonObjects = new HashMap<>();//单例对象,就存放半成品类型

    private static Object getSingleton(String className)
    {
        Object singletonObject = singletonObjects.get(className);
        if(singletonObject==null)
        {
            singletonObject = earlySingletonObjects.get(className);
        }
        return singletonObject;
    }

    private static <T> T getBean(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        //优先从缓存中获取
        Object object =  getSingleton(clazz.getName());//
        if(object!=null)
        {
            return (T)object;
        }

        synchronized (singletonObjects)
        {
            object = singletonObjects.get(clazz.getName());
            if(object!=null)
            {
                return (T)object;
            }
                    //实例化对象
            T instance = clazz.newInstance();
            earlySingletonObjects.put(clazz.getName(),instance);//实例化后就放入缓存

            //获取当前类中的所有字段
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                //允许访问私有变量
                field.setAccessible(true);
                //判断字段是否被@Load注解修饰
                boolean isUseLoad = field.isAnnotationPresent(Load.class);
                if (!isUseLoad) {
                    continue;
                }
                //获取需要被注入的字段的class
                Class<?> fieldType = field.getType();
                //递归获取字段的实例对象
                Object fieldBean = getBean(fieldType);
                //将实例对象注入到该字段中
                field.set(instance, fieldBean);
            }
            earlySingletonObjects.remove(clazz.getName());
            singletonObjects.put(clazz.getName(),instance);
            return instance;
        }

    }


    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
/*        A a = getBean(A.class);
        System.out.println(a.getB().getClass());*/
        new Thread(() -> {
            try {
                A a1 = getBean(A.class);
                System.out.println("t1.a:" + a1.hashCode());
                System.out.println("t1.b:" + a1.getB().hashCode());
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                A a1 = getBean(A.class);
                System.out.println("t2.a:" + a1.hashCode());
                System.out.println("t2.b:" + a1.getB().hashCode());
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                B b = getBean(B.class);
                System.out.println("t3.b:" + b.hashCode());
                System.out.println("t3.a:" + b.getA().hashCode());
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }).start();

    }

}
public class A {
    @Load
    private B b;
 
    public B getB() {
        return b;
    }

}
 
 

public class B {
    @Load
    private A a;

    public A getA() {
        return a;
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值