自定义一个IOC框架

要实现的功能:

  1. 将对象的实例化交给自定的ioc容器.
  2. 通过注解的方式对接口进行依赖注入
  3. 通过getBean("userName")方法那到对象,使用对象的方法
  • 首先,创建一个对象,定义对象的构造函数

    • package cn.lisongyu.ioc.demo.bean;
      
      import cn.lisongyu.ioc.annotation.Component;
      
      /**
       * @author lisongyu
       * @ClassName cn.lisongyu.ioc.demo.bean.UserBean
       * @description userbean
       * @create 2018年11月22日 11:08
       */
      @Component //自定义的组件,让ioc容器扫描带有指定注解的类,将当前类装配到ioc容器中
      public class UserBean {
      
          @Autowired //自定义的注入注解
          private Service service;
      
          public UserBean() {
              System.out.println("UserBean -> instance");
          }
      
          public void getUser(){
              service.test();     //接口的方法,如果注入失败,将报空指针异常
              System.out.println("用户详情展示");
          }
      }
      
    • package cn.lisongyu.ioc.demo.a.b.c;
      
      import cn.lisongyu.ioc.annotation.Component;
      import cn.lisongyu.ioc.demo.a.b.Service;
      
      /**
       * @author lisongyu
       * @ClassName cn.lisongyu.ioc.demo.a.b.c.TestService
       * @description  Service实现类
       * @create 2018年11月22日 11:22
       */
      @Component
      public class TestService implements Service {
      
          public TestService() {
              System.out.println("TestService -> instance");
          }
      
          @Override
          public void test() {
              System.out.println("Service 接口实现方法");
          }
      }
      
    • package cn.lisongyu.ioc.demo.a.b;
      
      /**
       * /**
       *
       * @author lisongyu
       * @ClassName cn.lisongyu.ioc.demo.a.b.Service
       * @description Service接口
       * @create 2018年11月22日 17:31
       */
      public interface Service {
      
          void test();
      }
      
      
  • 创建自定义的注解

    • package cn.lisongyu.ioc.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      //依赖注入注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.FIELD) //只能注解到字段上
      public @interface Autowired {
      }
      
      
    • package cn.lisongyu.ioc.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      //组件注解
      @Retention(RetentionPolicy.RUNTIME) //程序运行时执行
      @Target(ElementType.TYPE)   //该注解指定标注的位置    TYPE:类
      public @interface Component {
      }
      
  • 定义一个接口,用来获取bean对象的方法

    • package cn.lisongyu.ioc.context;
      
      /**
       * /**
       * Application 接口
       * @author lisongyu
       * @ClassName cn.lisongyu.ioc.context.Application
       * @description
       * @create 2018年11月22日 11:24
       */
      public interface Application {
      
          Object getBean(String beanName);
      }
      
      
    • package cn.lisongyu.ioc.context;
      
      import cn.lisongyu.ioc.annotation.Component;
      
      import java.io.File;
      import java.io.FileFilter;
      import java.net.URL;
      import java.sql.SQLOutput;
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Map;
      import java.util.SortedMap;
      import java.util.concurrent.ConcurrentHashMap;
      
      /**
       * @author lisongyu
       * @ClassName cn.lisongyu.ioc.context.ApplicationImpl
       * @description Application的实现类
       * @create 2018年11月22日 11:24
       */
      public class ApplicationImpl implements Application {
      
          //定义存放所有类对象的集合
          private List<Class<?>> classList = new ArrayList<>();
      
          //定义存放类的实例对象的集合
          private Map<String,Object> instanceMap = new ConcurrentHashMap<>();
      
      
          //无参构造
          public ApplicationImpl() {
          }
      
          /**
           * 有参构造,通过传入的包路径来实现扫描
           * @param basePackage
           */
          public ApplicationImpl(String basePackage) {
              //扫描包路径
              doScan(basePackage);
      
              //实例化
              doIoc();
      
              System.out.println(instanceMap);
      
              //依赖注入
              doDi();
          }
      
          /**
           * 实例化对象
           */
          private void doIoc() {
              //首先判断一下当前类集合中是否含有元素
              if (classList == null){
                  return;
              }
              //遍历集合
              classList.forEach((clz) ->{
                  try {
                      //通过类对象,实例化一个对象
                      Object instance = clz.newInstance();
                      //创建key
                      String key = getKeyName(clz.getSimpleName());
                      //存放到map集合中
                      //如果集合中存在则报错
                      if (instanceMap.containsKey(key)){
                          throw new RuntimeException("相同的类名");
                      }
                      //放入ioc容器中
                      instanceMap.put(key,instance);
                      //判断当前类是否实现了接口
                      Class<?>[] interfaces = clz.getInterfaces();
                      for (Class<?> inter : interfaces) {
                          instanceMap.put(inter.getName(),instance);
                      }
                  } catch (InstantiationException e) {
                      e.printStackTrace();
                  } catch (IllegalAccessException e) {
                      e.printStackTrace();
                  }
              });
          }
      
          //改名,获取一个首字母小写的类名
          private String getKeyName(String simpleName) {
              char[] chars = simpleName.toCharArray();
              chars[0] += 32;
              return String.valueOf(chars);
          }
      
      
          //依赖注入
          private void doDi() {
              //首先判断实例对象是否有
              if (instanceMap.size() == 0)
                  return;
              //遍历所有的实例对象
              instanceMap.forEach((k,v) -> {
                  Object instance = v;
                  //注入实体对象
                  Object injectionInstance = null;
                  //通过反射获取类对象
                  Class<?> clz = v.getClass();
                  //获取当前类对象的所有声明的字段
                  Field[] fields = clz.getDeclaredFields();
                  //循环遍历所有字段
                  for (Field field : fields) {
                      //判断字段是否含有@Autowired注解
                      if(field.isAnnotationPresent(Autowired.class)){
                          String name = field.getType().getName();
                          injectionInstance = this.instanceMap.get(name);
                      }
                      // 通过反射注入到该属性中
                      field.setAccessible(true);
                      try {
                          field.set(instance,injectionInstance);
                      } catch (IllegalAccessException e) {
                          e.printStackTrace();
                      }
                  }
              });
          }
      
          //包扫描方法
          private void doScan(String basePackage) {
              //获取当前包的位置
              URL resource = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/"));
              //创建一个文件对象
              File file = new File(resource.getPath());
      
              //遍历文件
              File[] fileNames = file.listFiles(new FileFilter() {
                  @Override
                  public boolean accept(File childFile) {
                      //判断当前文件是否是一个文件夹
                      if (childFile.isDirectory()){
      
                          //如果是文件夹,递归,获取所有的class文件
                          doScan(basePackage+"."+childFile.getName());
                      }else {
                          //判断当前文件是否是一个类文件
                          if (childFile.getName().endsWith(".class")){
                              String classPath = basePackage + "." + childFile.getName().replaceAll("\\.class", "");
                              Class<?> clz = null;
                              try {
                                  clz = Class.forName(classPath);
                                  //判断是否是有@Component注解的类
                                  if (clz.isAnnotationPresent(Component.class)){
                                      classList.add(clz);
                                  }
                              } catch (ClassNotFoundException e) {
                                  e.printStackTrace();
                              }
      
                          }
                      }
                      return false;
                  }
              });
      
          }
      
          @Override
          public Object getBean(String beanName) {
              return this.instanceMap.get(beanName);
          }
      }
      
  • 运行main()

    • package cn.lisongyu.ioc;
      
      import cn.lisongyu.ioc.context.Application;
      import cn.lisongyu.ioc.context.ApplicationImpl;
      import cn.lisongyu.ioc.demo.bean.UserBean;
      
      import java.util.*;
      
      /**
       * Hello world!
       *
       */
      public class App
      {
          public static void main( String[] args ) {
      
              //包路径
              Application app = new ApplicationImpl("cn.lisongyu.ioc.demo");
      
              UserBean userBean = (UserBean) app.getBean("userBean");
      
              userBean.getUser();
      
      
          }
      
      }
      
      
      
  • 结果:

    TestService -> instance     //接口实现类的初始化
    UserBean -> instance            //对象类的初始化
    {cn.lisongyu.ioc.demo.a.b.Service=cn.lisongyu.ioc.demo.a.b.c.TestService@4dd8dc3, testService=cn.lisongyu.ioc.demo.a.b.c.TestService@4dd8dc3, userBean=cn.lisongyu.ioc.demo.bean.UserBean@6d03e736} //装配到容器中的类
    Service 接口实现方法      //service.test();
    用户详情展示          //userBean.getUser();
    

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容