热门关键字:
jquery > jquery教程 > java > java代码实现简易版IOC容器,含IOC容器实现步骤分解

java代码实现简易版IOC容器,含IOC容器实现步骤分解

755
作者:管理员
发布时间:2020/4/2 15:11:27
评论数:0
转载请自觉注明原文:http://www.jq-school.com/Show.aspx?id=1187


一、需求

  实现一个简易的IOC容器,管理Bean,从IOC容器的BeanFactory中获取实例,从而取代自己new实例的做法。

二、实现步骤分析

  java代码实现简易版IOC容器,含IOC容器实现步骤分解

三、具体代码实现

  自定义注解类 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






如果您觉得本文的内容对您的学习有所帮助:支付鼓励



关键字:java代码实现简易版IOC容器
友荐云推荐