简单的ioc容器

这几天重新温习了反射和注解的知识点,本文通过实现一个迷你的Ioc容器,增加对这两个知识点的记忆。

实现效果


BService和CService都是通过Ioc容器注入依赖的
可以看到,BService标记有单例的注解,而CService没有。在重新实例化AService之后,BService的引用是一样的而CService不一样。

实现注解

  • @AutoWrite实现依赖注入
  • @SingleBean实现单例模式

思路

Ⅰ.判断类是否有单例注解@SingleBean
Ⅱ. 如果是单例,直接从map中查找对象,并返回实例
Ⅲ. 如果不是单例,创建新对象
Ⅳ. 实例化对象时,通过递归,遍历所有的依赖对象

代码

public class IocAnnotations {
    static Map<String, Object> map = new ConcurrentHashMap<>();

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface AutoWrite {
        String value() default "";
    }


    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface SingleBean {

    }


    static class AService {
        @AutoWrite
        private BService bService;

        @AutoWrite
        private CService cService;


        public void say() {
            bService.say();
            System.out.println("BService :" + bService.toString());
        }


        public void speak() {
            cService.speak();
            System.out.println("CService :" + cService.toString());
        }
    }

    @SingleBean
    static class BService {
        public void say() {
            System.out.println("BService");
        }
    }

    static class CService {
        public void speak() {
            System.out.println("CService");
        }
    }

    private static Object container(Class cls) throws IllegalAccessException, InstantiationException {
        boolean singleton = cls.isAnnotationPresent(SingleBean.class);
        if (!singleton) {
            //如果不是单例,直接生成新的实例对象
            return createBean(cls);
        }

        Object obj = map.get(cls.getName());
        synchronized (cls) {
            if (obj != null) {
                //如果map中有对象引用,直接返回
                return obj;
            }
            obj = createBean(cls);
            map.put(cls.getName(), obj);
        }
        return obj;
    }


    private static Object createBean(Class cls) throws IllegalAccessException, InstantiationException {
        //通过默认构造函数实例化对象
        Object obj = cls.newInstance();
        Field[] field = cls.getDeclaredFields();
        //遍历属性
        for (Field f : field) {
            if (f.isAnnotationPresent(AutoWrite.class)) {
                f.setAccessible(true);
                Class<?> paramsCls = f.getType();
                //通过递归实例化属性对象
                f.set(obj, container(paramsCls));
            }
        }
        return obj;
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        AService a = (AService) container(AService.class);
        a.say();
        a.speak();

        System.out.println("============创建新AService=============");

        AService aa = (AService) container(AService.class);
        aa.say();
        aa.speak();

    }

}

小结

通过反射和注解的一些基本Api,实现了Ioc中的setter注入功能,只是一个很简单的实例。
但是这个实现并没有解决bean的依赖循环,之后会完善。

posted @ 2020-09-23 23:16  dxyoung  阅读(131)  评论(0)    收藏  举报