IOC实现原理(一)

设计一个IOC

我们要自己设计一个IOC,那么目标是什么呢? 我们的IOC容器要可以存储对象,还要有注解注入的功能即可。

首先设计接口,一个IOC容器中最核心的当属容器接口,来一个Container。

那么容器里应该有什么呢,我想它至少要有存储和移除一个对象的能力,其次可以含括更多的获取和注册对象的方法。

/**
 * 
 */
package ioc;

import java.util.Set;

/**
 * Title: Container
 * Description: Container.java
 * @author  lizhitao
 * @date 2017年8月15日 下午2:54:15
 *
 */
public interface Container {

    /**
     * 根据Class获取Bean
     * @param clazz
     * @return
     */
    public <T> T getBean(Class<T> clazz);
    
    /**
     * 根据名称获取Bean
     * @param name
     * @return
     */
    public <T> T getBeanByName(String name);
    
    /**
     * 注册一个Bean到容器中
     * @param object
     */
    public Object registerBean(Object bean);
    
    /**
     * 注册一个Class到容器中
     * @param clazz
     */
    public Object registerBean(Class<?> clazz);
    
    /**
     * 注册一个带名称的Bean到容器中
     * @param name
     * @param bean
     */
    public Object registerBean(String name, Object bean);
    
    /**
     * 删除一个bean
     * @param clazz
     */
    public void remove(Class<?> clazz);
    
    /**
     * 根据名称删除一个bean
     * @param name
     */
    public void removeByName(String name);
    
    /**
     * @return    返回所有bean对象名称
     */
    public Set<String> getBeanNames();
    
    /**
     * 初始化装配
     */
    public void initWrited();
}

那么我写一个简单的实现代码:

/**
 * 
 */
package ioc;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import sun.reflect.misc.ReflectUtil;

/**
 * Title: SampleContainer Description: SampleContainer.java
 * 
 * @author lizhitao
 * @date 2017年8月15日 下午2:55:01
 *
 */
public class SampleContainer implements Container {

    /**
     * 保存所有bean对象,格式为 com.xxx.Person : @52x2xa
     */
    private Map<String, Object> beans;

    /**
     * 存储bean和name的关系
     */
    private Map<String, String> beanKeys;

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

    public <T> T getBean(Class<T> clazz) {
        String name = clazz.getName();
        Object object = beans.get(name);
        if (null != object) {
            return (T) object;
        }
        return null;
    }

    public <T> T getBeanByName(String name) {
        Object object = beans.get(name);
        if (null != object) {
            return (T) object;
        }
        return null;
    }

    public Object registerBean(Object bean) {
        String name = bean.getClass().getName();
        beanKeys.put(name, name);
        beans.put(name, bean);
        return bean;
    }

    public Object registerBean(Class<?> clazz) {
        String name = clazz.getName();
        beanKeys.put(name, name);
        Object bean = null;
        try {
            bean = ReflectUtil.newInstance(clazz);
            beans.put(name, bean);
            System.out.println("registerBean " + beans.size() + " " + beans.keySet());
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return bean;
    }

    public Object registerBean(String name, Object bean) {
        String className = bean.getClass().getName();
        beanKeys.put(name, className);
        beans.put(className, bean);
        return bean;
    }

    public Set<String> getBeanNames() {
        return beanKeys.keySet();
    }

    public void remove(Class<?> clazz) {
        String className = clazz.getName();
        if (null != className && !className.equals("")) {
            beanKeys.remove(className);
            beans.remove(className);
        }
    }

    public void removeByName(String name) {
        String className = beanKeys.get(name);
        if (null != className && !className.equals("")) {
            beanKeys.remove(name);
            beans.remove(className);
        }
    }

    public void initWrited() {
        Iterator<Entry<String, Object>> it = beans.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
            Object object = entry.getValue();
            // System.out.println(beans.size());
            injection(object);
        }
    }

    /**
     * 注入对象
     * 
     * @param object
     */
    public void injection(Object object) {
        // 所有字段
        try {
            Field[] fields = object.getClass().getDeclaredFields();
//            System.out.println(fields.length);
            for (Field field : fields) {
                // 需要注入的字段
                AutoWrited autoWrited = field.getAnnotation(AutoWrited.class);
//                System.out.println(field);
//                System.out.println(autoWrited);
                if (null != autoWrited) {

                    // 要注入的字段
                    Object autoWritedField = null;

                    String name = autoWrited.name();
                    
                    if (!name.equals("")) {//如果name中制定了要获取的对象名,直接获取对象
                        String className = beanKeys.get(name);
                        if (null != className && !className.equals("")) {
                            autoWritedField = beans.get(className);
                        }
                        if (null == autoWritedField) {
                            throw new RuntimeException("Unable to load " + name);
                        }
                    } else {
//                        System.out.println((autoWrited.value() == Class.class) + " " + field.getType());
                        if (autoWrited.value() == Class.class) {
                            autoWritedField = recursiveAssembly(field.getType());
                        } else {
                            // 指定装配的类
                            autoWritedField = this.getBean(autoWrited.value());
                            if (null == autoWritedField) {
                                autoWritedField = recursiveAssembly(autoWrited.value());
                            }
                        }
                    }

                    if (null == autoWritedField) {
                        throw new RuntimeException("Unable to load " + 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<?> clazz) {
        if (null != clazz) {
            return this.registerBean(clazz);
        }
        return null;
    }
}

这里将所有Bean的名称存储在 beanKeys 这个map中,将所有的对象存储在 beans 中,用 beanKeys 维护名称和对象的关系。

在装配的时候步骤如下:

  1. 判断是否使用了自定义命名的对象(是:根据name查找bean)
  2. 判断是否使用了Class类型Bean(是:根据Class查找Bean,如果查找不到则创建一个无参构造函数的Bean)

下面是一个测试:

/**
 * 
 */
package ioc;

/**
 * Title: IOCTest
 * Description: IOCTest.java
 * @author  lizhitao
 * @date 2017年8月15日 下午2:58:21
 *
 */
public class IocTest {

    private static Container container = new SampleContainer();
    
    public static void baseTest(){
        container.registerBean(Lol.class);
        // 初始化注入
        container.initWrited();
        
        Lol lol = container.getBean(Lol.class);
        lol.work();
    }
    

    public static void main(String[] args) {
        baseTest();
        //iocClassTest();
        //iocNameTest();
    }
    
}

Lol类

/**
 * 
 */
package ioc;

import java.util.ArrayList;

/**
 * Title: Lol
 * Description: Lol.java
 * @author  lizhitao
 * @date 2017年8月15日 下午3:11:48
 *
 */
public class Lol {
    
    @AutoWrited
    private Lol2 lol;//应用的第三方类
    
    @AutoWrited
    private ArrayList<String> strList;
    
    public void work(){
        strList.add("ddddddddddd");
        strList.add("EEEEEEEE");
        System.out.println(strList.toString());
        lol.work();
    }
}

Lol2类

/**
 * 
 */
package ioc;

import java.util.ArrayList;

/**
 * Title: Lol
 * Description: Lol.java
 * @author  lizhitao
 * @date 2017年8月15日 下午3:11:48
 *
 */
public class Lol2 {
//    @AutoWrited
//    private Lol2 lol;
//    
//    @AutoWrited
//    private ArrayList<String> strlist;
    
    public void work(){
//        System.out.println(strlist.add("ddddddddddd"));
        System.out.println("I am work in Lol2.");
    }
}

注解类:

package ioc;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWrited {
    String name() default "";//指定要加载的对象名
    Class value() default Class.class;
}

测试结果:

registerBean 1 [ioc.Lol]
registerBean 2 [ioc.Lol2, ioc.Lol]
registerBean 3 [ioc.Lol2, ioc.Lol, java.util.ArrayList]
[ddddddddddd, EEEEEEEE]
I am work in Lol2.

 

posted on 2017-08-15 17:25  小鸟的士林  阅读(159)  评论(0)    收藏  举报

导航