java代码实现简易版IOC容器,含IOC容器实现步骤分解
一、需求
实现一个简易的IOC容器,管理Bean,从IOC容器的BeanFactory中获取实例,从而取代自己new实例的做法。
二、实现步骤分析
三、具体代码实现
自定义注解类 MyComponent 和 MyAutowired:
1 package MyIOCAndMyAop.Annotations; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target(ElementType.TYPE) 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface MyComponent { 11 12 }
1 package MyIOCAndMyAop.Annotations; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Target(ElementType.FIELD) 9 @Retention(RetentionPolicy.RUNTIME) 10 public @interface MyAutowired { 11 12 }
MyIOC容器的实现:自己实现简单的IOC容器,来管理bean:BeanFactory<String, Object>,String为全类名,Object为通过类加载器加载进来的Class对象反射创建的bean。
1 package MyIOCAndMyAop; 2 3 import java.io.File; 4 import java.lang.annotation.Annotation; 5 import java.lang.reflect.Field; 6 import java.lang.reflect.InvocationTargetException; 7 import java.lang.reflect.Method; 8 import java.net.MalformedURLException; 9 import java.net.URL; 10 import java.net.URLClassLoader; 11 import java.util.ArrayList; 12 import java.util.HashMap; 13 import java.util.Map; 14 import MyIOCAndMyAop.Annotations.MyAutowired; 15 import MyIOCAndMyAop.Annotations.MyComponent; 16 17 public class MyIOC { 18 19 // beanFactory 要声明为类变量,因为它不能被GC回收: 20 private static HashMap<String, Object> beanFactory = new HashMap<>(); 21 22 /** 23 * 随着MyIOC类被加载到内存进行初始化,就会执行其静态代码块 24 * @param args 25 */ 26 static { 27 init(); 28 } 30 31 /** 32 * 获取BeanFactory 33 * @return 34 */ 35 public static HashMap<String, Object> getBeanFactory(){ 36 return beanFactory; 37 } 38 39 /** 40 * 根据全类名更新BeanFactory中的bean 41 * @param typeName 42 * @param proxyInstance 43 */ 44 public static void updateBeanFromBeanFactory(String typeName, Object proxyInstance) { 45 beanFactory.put(typeName, proxyInstance); 46 } 47 48 /** 49 * 通过全类名获得对应的实例 50 * @param completeClassName 51 * @return 52 */ 53 public static Object getBean(String completeClassName) { 54 return beanFactory.get(completeClassName); 55 } 56 57 public static void init() { 58 HashMap<String, Class> loadedClazzList;//<全类名, Class对象> 59 try { 60 //1.加载指定的类 61 File file = new File("C:\\workplace\\test\\bin");//!!!这里写死了路径不合适,可以做改进 62 loadedClazzList = loadAllClazz(file); 63 64 //2.实例化并放入IOC容器中:对于那些有注解的类,做实例化 65 newInstance(loadedClazzList); 66 67 // 3.完成依赖注入 68 autoWired(); 69 70 // 4.测试:找到beanFactory中的某个bean,并执行其某个方法 ===> 这里有个问题,只能执行指定的方法,所以beanFactory中的所有bean都得有这个方法,这里先这么做了,但这明显不合理。 71 // test(); 72 } catch (Exception e) { 73 e.printStackTrace(); 74 } 75 } 76 77 public static void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 78 for(Map.Entry<String, Object> entry : beanFactory.entrySet()) { 79 // System.out.println(entry.getKey() + " ---> "); 80 Method method = entry.getValue().getClass().getMethod("test"); 81 method.invoke(entry.getValue()); 82 } 83 } 84 85 /** 86 * 对BeanFactory中管理的所有bean完成依赖注入。 87 * 交给IOC容器管理的类,需要注入成员变量,如果该成员变量是自定义的类,该类也是需要交给IOC容器管理的。 88 * @throws IllegalAccessException 89 * @throws IllegalArgumentException 90 * @throws MalformedURLException 91 * @throws ClassNotFoundException 92 */ 93 public static void autoWired() throws IllegalArgumentException, IllegalAccessException, ClassNotFoundException, MalformedURLException { 94 for(Map.Entry<String, Object> entry : beanFactory.entrySet()) { 95 Field[] fields = entry.getValue().getClass().getDeclaredFields();//!!!getFields():只能获取到运行时类中及其父类中声明为public的属性;getDeclaredFields():获取运行时类本身声明的所有的属性 96 for(Field field : fields) { 97 Annotation[] annotations = field.getAnnotations(); 98 for(int i = 0; i < annotations.length; i++) { 99 if(annotations[i].annotationType() == MyAutowired.class) { 100 //从beanFactory中找到相应的bean,赋值给该成员变量,以完成依赖注入。 101 Object object = beanFactory.get(field.getType().getTypeName()); 102 // System.out.println(field.getType().getTypeName());//MyIOCAndMyAop.bean.Student 103 //通过Field(反射)为成员变量赋值: 104 field.setAccessible(true); 105 field.set(entry.getValue(), object); 106 } 107 } 108 } 109 } 110 } 111 112 /** 113 * 实例化: 放到loadedClazzlist集合中的Class对象都是需要做实例化的(加了@MyComponent注解的类) 114 */ 115 public static void newInstance(HashMap<String, Class> loadedClazzList) throws InstantiationException, IllegalAccessException, ClassNotFoundException, MalformedURLException { 116 for(Map.Entry<String, Class> entry : loadedClazzList.entrySet()) { 117 beanFactory.put(entry.getKey(), entry.getValue().newInstance()); 118 } 119 } 120 121 /** 122 * 加载指定路径下的类。 123 * 类加载:javase/src/classLoader/a01helloworld/A03GetExtClassLoader 124 * @return 类加载器加载进来的指定路径下的所有Class对象 125 * @throws IllegalAccessException 126 * @throws InstantiationException 127 */ 128 public static HashMap<String, Class> loadAllClazz(File file) throws ClassNotFoundException, MalformedURLException, InstantiationException, IllegalAccessException { 129 //用于存放类加载器加载进来的Class对象<全类名, Class对象> 130 HashMap<String, Class> loadedClazzList = new HashMap<>(); 131 132 URL[] urls = new URL[]{file.toURI().toURL()}; 133 URLClassLoader classLoader = new URLClassLoader(urls); 134 135 ArrayList<String> allCompleteClassName = getAllCompleteClassName(file); 136 137 for(String element : allCompleteClassName) { 138 Class<?> clazz = classLoader.loadClass(element); 139 Annotation[] annotations = clazz.getAnnotations();// !!!拿到Class对象的时候,就进行筛选出有注解的Class再放到容器中,而不是把指定路径下的所有类都加载进来。 140 for(int i = 0; i < annotations.length; i++) { 141 if(annotations[i].annotationType() == MyComponent.class) { 142 loadedClazzList.put(element, clazz);//得到各个类对象了 143 } 144 } 145 } 146 return loadedClazzList; 147 } 148 149 /** 150 * 得到allNeedLoadClassFiles中所有要加载的class文件的全类名 151 */ 152 private static ArrayList<String> getAllCompleteClassName(File file) { 153 // 所有要加载的class的全类名,如:classLoader.a02myclassloader.bean.Bean 154 ArrayList<String> completeClassNames = new ArrayList<>(); 155 // 用于存放指定路径下所有要加载的class文件 156 ArrayList<File> allNeedLoadClassFiles = new ArrayList<File>(); 157 158 getAllNeedLoadClassFile(file, allNeedLoadClassFiles); 159 160 for (File element : allNeedLoadClassFiles) { 161 String filePath = element.getPath().replace("\\", "."); 162 163 if(filePath.endsWith(".class")) { 164 //filePath.indexOf("bin.")+4:"bin."之后。filePath.lastIndexOf(".class"):".class"之前,该方法是从后往前找,性能更高。 165 String completeClassName = filePath.substring(filePath.indexOf("bin.")+4, filePath.lastIndexOf(".class")); 166 completeClassNames.add(completeClassName); 167 } 168 } 169 return completeClassNames; 170 } 171 172 /** 173 * 通过递归获取指定路径下所有要加载的class文件 174 * 递归:javase/src/recursion/A_PrintFolder 175 * @param file 176 */ 177 private static ArrayList<File> getAllNeedLoadClassFile(File file, ArrayList<File> allNeedLoadClassFiles) { 178 if(!file.exists()) {//!!!这里要多一层判断 179 return allNeedLoadClassFiles; 180 } 181 182 if (file.isDirectory()) {//是文件夹 183 File[] listFiles = file.listFiles(); 184 for (File element : listFiles) { 185 getAllNeedLoadClassFile(element, allNeedLoadClassFiles); 186 } 187 } else {//是文件 188 allNeedLoadClassFiles.add(file); 189 } 190 return allNeedLoadClassFiles; 191 } 192 }
自己实现AOP 1.0版本,含步骤分解:https://www.cnblogs.com/laipimei/p/11137250.html
自己实现SpringAOP 2.0版本,含实现步骤分解:https://www.cnblogs.com/laipimei/p/11163377.html
作者:赖皮梅
声明:
1.原创博文,欢迎转载、引用;转载、引用请注明作者并附上原文链接,否则保留追究法律责任的权利。
2.本博文中引用他人的博文内容时均已注明出处,如有侵权,请联系作者删除。
3.博文内容如有错误、不妥之处,欢迎留言指正,还请不吝赐教 =^_^=