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 维护名称和对象的关系。
在装配的时候步骤如下:
- 判断是否使用了自定义命名的对象(是:根据name查找bean)
- 判断是否使用了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.
浙公网安备 33010602011771号