自定義一個(gè)IOC框架

要實(shí)現(xiàn)的功能:

  1. 將對(duì)象的實(shí)例化交給自定的ioc容器.
  2. 通過注解的方式對(duì)接口進(jìn)行依賴注入
  3. 通過getBean("userName")方法那到對(duì)象,使用對(duì)象的方法
  • 首先,創(chuàng)建一個(gè)對(duì)象,定義對(duì)象的構(gòu)造函數(shù)

    • 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容器掃描帶有指定注解的類,將當(dāng)前類裝配到ioc容器中
      public class UserBean {
      
          @Autowired //自定義的注入注解
          private Service service;
      
          public UserBean() {
              System.out.println("UserBean -> instance");
          }
      
          public void getUser(){
              service.test();     //接口的方法,如果注入失敗,將報(bào)空指針異常
              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實(shí)現(xiàn)類
       * @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 接口實(shí)現(xiàn)方法");
          }
      }
      
    • 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();
      }
      
      
  • 創(chuàng)建自定義的注解

    • 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) //程序運(yùn)行時(shí)執(zhí)行
      @Target(ElementType.TYPE)   //該注解指定標(biāo)注的位置    TYPE:類
      public @interface Component {
      }
      
  • 定義一個(gè)接口,用來獲取bean對(duì)象的方法

    • 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的實(shí)現(xiàn)類
       * @create 2018年11月22日 11:24
       */
      public class ApplicationImpl implements Application {
      
          //定義存放所有類對(duì)象的集合
          private List<Class<?>> classList = new ArrayList<>();
      
          //定義存放類的實(shí)例對(duì)象的集合
          private Map<String,Object> instanceMap = new ConcurrentHashMap<>();
      
      
          //無參構(gòu)造
          public ApplicationImpl() {
          }
      
          /**
           * 有參構(gòu)造,通過傳入的包路徑來實(shí)現(xiàn)掃描
           * @param basePackage
           */
          public ApplicationImpl(String basePackage) {
              //掃描包路徑
              doScan(basePackage);
      
              //實(shí)例化
              doIoc();
      
              System.out.println(instanceMap);
      
              //依賴注入
              doDi();
          }
      
          /**
           * 實(shí)例化對(duì)象
           */
          private void doIoc() {
              //首先判斷一下當(dāng)前類集合中是否含有元素
              if (classList == null){
                  return;
              }
              //遍歷集合
              classList.forEach((clz) ->{
                  try {
                      //通過類對(duì)象,實(shí)例化一個(gè)對(duì)象
                      Object instance = clz.newInstance();
                      //創(chuàng)建key
                      String key = getKeyName(clz.getSimpleName());
                      //存放到map集合中
                      //如果集合中存在則報(bào)錯(cuò)
                      if (instanceMap.containsKey(key)){
                          throw new RuntimeException("相同的類名");
                      }
                      //放入ioc容器中
                      instanceMap.put(key,instance);
                      //判斷當(dāng)前類是否實(shí)現(xiàn)了接口
                      Class<?>[] interfaces = clz.getInterfaces();
                      for (Class<?> inter : interfaces) {
                          instanceMap.put(inter.getName(),instance);
                      }
                  } catch (InstantiationException e) {
                      e.printStackTrace();
                  } catch (IllegalAccessException e) {
                      e.printStackTrace();
                  }
              });
          }
      
          //改名,獲取一個(gè)首字母小寫的類名
          private String getKeyName(String simpleName) {
              char[] chars = simpleName.toCharArray();
              chars[0] += 32;
              return String.valueOf(chars);
          }
      
      
          //依賴注入
          private void doDi() {
              //首先判斷實(shí)例對(duì)象是否有
              if (instanceMap.size() == 0)
                  return;
              //遍歷所有的實(shí)例對(duì)象
              instanceMap.forEach((k,v) -> {
                  Object instance = v;
                  //注入實(shí)體對(duì)象
                  Object injectionInstance = null;
                  //通過反射獲取類對(duì)象
                  Class<?> clz = v.getClass();
                  //獲取當(dāng)前類對(duì)象的所有聲明的字段
                  Field[] fields = clz.getDeclaredFields();
                  //循環(huán)遍歷所有字段
                  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) {
              //獲取當(dāng)前包的位置
              URL resource = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/"));
              //創(chuàng)建一個(gè)文件對(duì)象
              File file = new File(resource.getPath());
      
              //遍歷文件
              File[] fileNames = file.listFiles(new FileFilter() {
                  @Override
                  public boolean accept(File childFile) {
                      //判斷當(dāng)前文件是否是一個(gè)文件夾
                      if (childFile.isDirectory()){
      
                          //如果是文件夾,遞歸,獲取所有的class文件
                          doScan(basePackage+"."+childFile.getName());
                      }else {
                          //判斷當(dāng)前文件是否是一個(gè)類文件
                          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);
          }
      }
      
  • 運(yùn)行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();
      
      
          }
      
      }
      
      
      
  • 結(jié)果:

    TestService -> instance     //接口實(shí)現(xiàn)類的初始化
    UserBean -> instance            //對(duì)象類的初始化
    {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 接口實(shí)現(xiàn)方法      //service.test();
    用戶詳情展示          //userBean.getUser();
    

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盲链,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子胚吁,更是在濱河造成了極大的恐慌,老刑警劉巖曼尊,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚁鳖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡有梆,警方通過查閱死者的電腦和手機(jī)是尖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淳梦,“玉大人析砸,你說我怎么就攤上這事”郏” “怎么了首繁?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)陨囊。 經(jīng)常有香客問我弦疮,道長(zhǎng),這世上最難降的妖魔是什么蜘醋? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任胁塞,我火速辦了婚禮,結(jié)果婚禮上压语,老公的妹妹穿的比我還像新娘啸罢。我一直安慰自己,他們只是感情好胎食,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布扰才。 她就那樣靜靜地躺著,像睡著了一般厕怜。 火紅的嫁衣襯著肌膚如雪衩匣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天粥航,我揣著相機(jī)與錄音琅捏,去河邊找鬼。 笑死递雀,一個(gè)胖子當(dāng)著我的面吹牛柄延,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播映之,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拦焚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蜡坊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赎败,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤秕衙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后僵刮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體据忘,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年搞糕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勇吊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窍仰,死狀恐怖汉规,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驹吮,我是刑警寧澤针史,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站碟狞,受9級(jí)特大地震影響啄枕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜族沃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一频祝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脆淹,春花似錦常空、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咐柜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攘残,已是汗流浹背拙友。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歼郭,地道東北人遗契。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像病曾,于是被迫代替她去往敵國(guó)和親牍蜂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漾根,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容