zoukankan      html  css  js  c++  java
  • 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.博文内容如有错误、不妥之处,欢迎留言指正,还请不吝赐教 =^_^=
  • 相关阅读:
    Pytorch环境搭建(Anaconda+Pycharm,清华镜像源)
    Leetcode 220. 存在重复元素 III (Contains Duplicate III)
    Leetcode 217. 存在重复元素 (Contains Duplicate)
    Leetcode 219. 存在重复元素 II (Contains Duplicate II)
    Leetcode 1073. 负二进制数相加(Adding Two Negabinary Numbers)
    极客战记(codecombat)攻略-地牢-Kithgard 地牢
    python elasticsearch 深度分页——scroll的使用与清除(clear_scroll)
    sqlmap参数
    文件包含
    web安全
  • 原文地址:https://www.cnblogs.com/laipimei/p/11205510.html
Copyright © 2011-2022 走看看