自己实现一个简单的ioc容器

2017-11-26  本文已影响0人  xmfaly

某节实验课的任务是练习使用spring的ioc,因为之前用过,感觉也没啥意思,就想了以下他的实现原理,然后自己使用java反射机制实现了一个简单的ioc容器。以下对原理进行简单的说明,完整的代码及用法详见xmfaly/simpleioc

首先定义@Autowired注解用于自动注入

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {

    Class<?> value() default Class.class;

    String name() default "";
}

建立一个Container容器类
建立两个map分别保存类名和bean、对象名和类名的关系

    // 保存所有bean 格式为 类名 : bean
    private Map<String, Object> beans;

    // 存储对象和类名的关系 对象名 :bean
    private Map<String, Object> beanKeys;

这里为了安全起见,使用ConcurrentHashMap()实例化这两个map

    public Container(){
        beans = new ConcurrentHashMap<String, Object>();
        beanKeys = new ConcurrentHashMap<String, String>();
    }

向容器内注册bean,这里我重载了三种形式,当然也可以更多,关键看使用的场景了。

  /**
     * 以class的形式注册
     */
    public Object registerBean(Class<?> cls) {
        String className = cls.getName();
        Object bean = null;

        try {
            bean = cls.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        beans.put(className, bean);

        //不指定对象名的情况下类名和对象名相同
        beanKeys.put(className, bean);
        return bean;
    }

    /**
     * 以bean的形式注册
     */
    public Object registerBean(Object bean) {
        String className = bean.getClass().getName();
        beans.put(className, bean);
        beanKeys.put(className, bean);
        return bean;
    }


    /**
     * 以带对象名的class形式注册
     */
    public Object registerBean(String name, Class<?> cls) {
        String className = cls.getName();
        Object bean = null;

        try {
            bean = cls.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        beans.put(className, bean);
        beanKeys.put(name, bean);
        return bean;
    }

    /**
     * 注册一个带名称的Bean到容器中
     */
    public Object registerBean(String name, Object bean) {
        String className = bean.getClass().getName();
        beans.put(className, bean);
        beanKeys.put(name, bean);
        return bean;
    }

从容器中取出bean

   /**
     * 通过 Class 对象获取bean
     */
    public <T> T getBean(Class<?> cls) {
        String className = cls.getName();
        Object object = beans.get(className);
        if (null != object) {
            return (T) object;
        }
        return null;
    }

    /**
     * 通过对象名获取 bean
     */
    public <T> T getBeanByName(String name) {
        Object object = beanKeys.get(name);;
        if (null != object) {
            return (T) object;
        }
        return null;
    }

在容器启动的时候遍历容器内的所有bean对bean进行注入

  /**
     * 初始化
     */
    public void init() {
        Iterator<Map.Entry<String, Object>> it = beans.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            Object object = entry.getValue();
            injection(object);
        }
    }

其中使用到的方法的实现

     /**
     * 注入
     */
    public void injection(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();
        try {

            //遍历所有属性寻找@Autowired注解
            for (Field field : fields) {
                Autowired autowired = field.getAnnotation(Autowired.class);
                if (null != autowired) {

                    // 要注入的字段
                    Object autoWritedField = null;
                    String name = autowired.name();

                    if (!name.equals("")) {
                        Object bean = beanKeys.get(name);
                        if (null != bean ) {
                            autoWritedField = bean;
                        }


                        if (null == autoWritedField) {
                            throw new RuntimeException("Unable to autoWrited " + name);
                        }
                    } else {
                        if (autowired.value() == Class.class) {
                            //该属性的Type
                            autoWritedField = recursiveAssembly(field.getType());
                        } else {
                            // 指定装配的类
                            autoWritedField = this.getBean(autowired.value());
                            if (null == autoWritedField) {
                                autoWritedField = recursiveAssembly(autowired.value());
                            }
                        }
                    }

                    if (null == autoWritedField) {
                        throw new RuntimeException("Unable to autoWrited " + field.getType().getCanonicalName());
                    }

                    boolean accessible = field.isAccessible();
                    field.setAccessible(true);
                    field.set(object, autoWritedField);
                    field.setAccessible(accessible);
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 修复没有指定注解及默认注入的情况
     */
    private Object recursiveAssembly(Class<?> cls) {
        if (null != cls) {
            return this.registerBean(cls);
        }
        return null;
    }

写个测试测试3中注入类型

public class TestIoc {

    class A{

        @Autowired(name = "myvalue")
        private Integer value;

        @Autowired(name = "str")
        private String myStr;

        @Autowired(value = String.class)
        private String myStr2;

        @Autowired
        public String myStr3;

        public void show(){
            System.out.println("value: " + value);
            System.out.println("str: " + myStr);
            System.out.println(myStr2 == null);
            System.out.println(myStr3 == null);
        }
    }

    @Test
    public void test(){
        Container c = new Container();
        c.registerBean("a",new A());
        c.registerBean("str","注入成功");
        c.registerBean("myvalue",2333);
        c.initWired();
        A a = c.getBeanByName("a");
        a.show();
    }
}

测试成功

value: 2333
str: 注入成功
false
false
上一篇下一篇

猜你喜欢

热点阅读