溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java怎么實現(xiàn)Spring的IoC容器的操作

發(fā)布時間:2021-08-16 15:15:06 來源:億速云 閱讀:78 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“Java怎么實現(xiàn)Spring的IoC容器的操作”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

目錄
  • 實現(xiàn)的功能:

  • 項目結(jié)構(gòu)

    • 下面是程序的項目結(jié)構(gòu)圖:

  • 自定義注解

    • 容器實現(xiàn)

      • 測試

        • 實體類User的定義:

      實現(xiàn)的功能:

      • 默認(rèn)情況下將掃描整個項目的文件

      • 可以使用@ComponentScan注解配置掃描路徑

      • 只將被@Component注解修飾的類裝載到容器中

      • 可以使用@AutoWired注解實現(xiàn)自動裝配

      • 讀取配置文件中的聲明的類并注冊到容器中

      項目結(jié)構(gòu)

      下面是程序的項目結(jié)構(gòu)圖:

      Java怎么實現(xiàn)Spring的IoC容器的操作

      自定義注解

      下面是自定義的三個注解: @AutoWired,@Component,@ComponentScan。

      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface AutoWired {
      }
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface Component {
      }
      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface ComponentScan {
        String[] value();
      }

      容器實現(xiàn)

      其中AnnotationConfigApplicationContext和ClassPathXMLApplicationContext為核心的類,其中

      AnnotationConfigApplicationContext類實現(xiàn)掃描文件和解析注解等功能。

      package learn.reflection.reflect;
      import learn.reflection.Bootstrap;
      import learn.reflection.annotation.AutoWired;
      import learn.reflection.annotation.Component;
      import learn.reflection.annotation.ComponentScan;
      import java.io.File;
      import java.io.InputStream;
      import java.lang.reflect.Field;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.Properties;
      import java.util.Set;
      public class AnnotationConfigApplicationContext<T>{
        //使用HaspMap存儲Bean
        private HashMap<Class,Object> beanFactory=new HashMap<>();
        //獲取Bean的方法
        public T getBean(Class clazz){
          return (T) beanFactory.get(clazz);
        }
        String path;//編譯后的字節(jié)碼存儲路徑
        /**
         * 初始化ApplicationContext,加載注解修飾的Bean到beanFactory
         */
        public void initContextByAnnotation(){
          //編譯后的項目根目錄:D:/idea_workplace/javaAppliTechnology/target/classes/
          path = AnnotationConfigApplicationContext.class.getClassLoader().getResource("").getFile();
          //查看啟動類Bootstrap是否有定義掃描包
          ComponentScan annotation = Bootstrap.class.getAnnotation(ComponentScan.class);
          if (annotation!=null){
            //有定義就只掃描自定義的
            String[] definedPaths = annotation.value();
            if (definedPaths!=null&&definedPaths.length>0){
              loadClassInDefinedDir(path,definedPaths);
            }
          }else{
            //默認(rèn)掃描整個項目的目錄
            System.out.println(path);
            findClassFile(new File(path));
          }
          assembleObject();
        }
        /**
         * 給@AutoWired修飾的屬性賦值
         */
        private void assembleObject(){
          Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
          //掃描所有容器中的Bean
          for (Map.Entry<Class, Object> entry : entries) {
            Object value = entry.getValue();
            //獲取所有屬性
            Field[] fields = value.getClass().getDeclaredFields();
            for (Field field : fields) {
              //如果被@AutoWired注解修飾則進(jìn)行賦值
              AutoWired annotation = field.getAnnotation(AutoWired.class);
              if (annotation!=null){
                try {
                  field.setAccessible(true);
                  field.set(value,beanFactory.get(field.getType()));
                } catch (IllegalAccessException e) {
                  e.printStackTrace();
                }
              }
            }
          }
        }
        /**
         * 掃描用戶自定義的包
         * @param path
         * @param definedPaths
         */
        private void loadClassInDefinedDir(String path, String[] definedPaths){
          for (String definedPath : definedPaths) {
            //轉(zhuǎn)換成絕對路徑
            String s = definedPath.replaceAll("\\.", "/");
            String fullName=path+s;
            System.out.println(s);
            findClassFile(new File(fullName));
          }
        }
        /**
         * 掃描項目中的每一個文件夾找到所有的class文件
         */
        private void findClassFile(File pathParent) {
          //路徑是否是目錄,子目錄是否為空
          if (pathParent.isDirectory()) {
            File[] childrenFiles = pathParent.listFiles();
            if (childrenFiles == null || childrenFiles.length == 0) {
              return;
            }
            for (File childrenFile : childrenFiles) {
              if (childrenFile.isDirectory()) {
                //遞歸調(diào)用直到找到所有的文件
                findClassFile(childrenFile);
              } else {
                //找到文件
                loadClassWithAnnotation(childrenFile);
              }
            }
          }
        }
        /**
         *   裝配找到的所有帶有@Component注解的類到容器
         */
        private void loadClassWithAnnotation(File file) {
          //1.去掉前面的項目絕對路徑
          String pathWithClass=file.getAbsolutePath().substring(path.length()-1);
          //2.將路徑的“/”轉(zhuǎn)化為“.”和去掉后面的.class
          if (pathWithClass.contains(".class")){
            String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
            /**
             *  根據(jù)獲取到的類的全限定名使用反射將實例添加到beanFactory中
             */
            try {
              Class<?> clazz = Class.forName(fullName);
              //3.判斷是不是接口,不是接口才創(chuàng)建實例
              if (!clazz.isInterface()){
                //4.是否具有@Bean注解
                Component annotation = clazz.getAnnotation(Component.class);
                if (annotation!=null){
                  //5.創(chuàng)建實例對象
                  Object instance = clazz.newInstance();
                  //6.判斷是否有實現(xiàn)的接口
                  Class<?>[] interfaces = clazz.getInterfaces();
                  if (interfaces!=null&&interfaces.length>0){
                    //如果是有接口就將其接口的class作為key,實例對象作為value
                    System.out.println("正在加載【"+interfaces[0].getName()+"】 實例對象:"+instance.getClass().getName());
                    beanFactory.put(interfaces[0],instance);
                  }else{
                    System.out.println("正在加載【"+clazz.getName()+"】 實例對象:"+instance.getClass().getName());
                    beanFactory.put(clazz,instance);
                  }
                  //如果沒有接口就將自己的class作為key,實例對象作為value
                }
              }
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
      }

      ClassPathXMLApplicationContext類實現(xiàn)解析xml配置文件,并裝載組件到容器中。

      package learn.reflection.reflect;
      import java.net.URL;
      import java.util.HashMap;
      import java.util.Map;
      import org.jdom2.Document;
      import org.jdom2.JDOMException;
      import org.jdom2.Element;
      import org.jdom2.xpath.XPath;
      import org.jdom2.input.SAXBuilder;
      import java.io.File;
      import java.io.IOException;
      import java.net.URL;
      import java.net.URISyntaxException;
      import java.util.*;
      import java.lang.reflect.Field;
      import java.lang.reflect.Method;
      import java.lang.reflect.InvocationTargetException;
      /**
       * @author Hai
       * @date 2020/5/17 - 18:47
       */
      public class ClassPathXMLApplicationContext{
        private File file;
        private Map<String,Object> map = new HashMap();
        public ClassPathXMLApplicationContext(String config_file) {
          URL url = this.getClass().getClassLoader().getResource(config_file);
          try {
            file = new File(url.toURI());
            XMLParsing();
          } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
        private void XMLParsing() throws Exception {
          SAXBuilder builder = new SAXBuilder();
          Document document = builder.build(file);
          Element root = document.getRootElement();
          List elementList = root.getChildren("bean");
          Iterator i = elementList.iterator();
          //讀取bean節(jié)點(diǎn)的所有信息
          while (i.hasNext()) {
            Element bean = (Element) i.next();
            String id = bean.getAttributeValue("id");
            //根據(jù)class創(chuàng)建實例
            String cls = bean.getAttributeValue("class");
            Object obj = Class.forName(cls).newInstance();
            Method[] method = obj.getClass().getDeclaredMethods();
            List<Element> list = bean.getChildren("property");
            for (Element el : list) {
              for (int n = 0; n < method.length; n++) {
                String name = method[n].getName();
                String temp = null;
                //找到屬性對應(yīng)的setter方法進(jìn)行賦值
                if (name.startsWith("set")) {
                  temp = name.substring(3, name.length()).toLowerCase();
                  if (el.getAttribute("name") != null) {
                    if (temp.equals(el.getAttribute("name").getValue())) {
                      method[n].invoke(obj, el.getAttribute("value").getValue());
                    }
                  }
                }
              }
            }
            map.put(id, obj);
          }
        }
        public Object getBean(String name) {
          return map.get(name);
        }
      }

      測試

      實體類User的定義:

      @Component
      public class User {
        private String username;
        private String password;
        
        public User(String username, String password) {
          this.username = username;
          this.password = password;
        }
        public User() {
        }
        //省略getter,setter方法
        }

      在UserServiceImpl類中添加@Component注解,并使用@AutoWired注解注入容器中的IUerDao接口的實現(xiàn)類UserDaoImpl。

      @Component
      public class UserServiceImpl implements IUserService {
        @AutoWired
        private IUserDao userDao;
        @Override
        public void login(User user) {
          System.out.println("調(diào)用UserDaoImpl的login方法");
          userDao.loginByUsername(user);
        }
      }

      UserDaoImpl類同樣添加@Component注解

      @Component
      public class UserDaoImpl implements IUserDao {
        @Override
        public void loginByUsername(User user) {
          System.out.println("驗證用戶【"+user.getUsername()+"】登錄");
        }
      }

      在beans.xml中配置注冊User類,文件beans.xml的內(nèi)容如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans>
          <bean id="user" class="learn.reflection.entity.User">
              <property name="username" value="張三" />
              <property name="password" value="123" />
          </bean>
      </beans>

      下面同時使用 AnnotationConfigApplicationContext類和 ClassPathXMLApplicationContext類。

      Bootstrap類作為啟動類添加注解@ComponentScan,指定掃描learn.reflection.dao和learn.reflection.service這兩個包。

      @ComponentScan(value = {"learn.reflection.dao","learn.reflection.service"})
      public class Bootstrap {
        public static void main(String[] args) {
          AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          applicationContext.initContextByAnnotation();
          UserServiceImpl userService = (UserServiceImpl) applicationContext.getBean(IUserService.class);
          ClassPathXMLApplicationContext xmlApplicationContext = new ClassPathXMLApplicationContext("beans.xml");
          User user = (User) xmlApplicationContext.getBean("user");
          System.out.println(user);
          userService.login(user);
        }
      }

      運(yùn)行Bootstrap類,程序運(yùn)行結(jié)果如下:

      learn/reflection/dao
      正在加載【learn.reflection.dao.IUserDao】 實例對象:learn.reflection.dao.impl.UserDaoImpl
      learn/reflection/service
      正在加載【learn.reflection.service.IUserService】 實例對象:learn.reflection.service.impl.UserServiceImpl
      User{username='張三', password='123'}
      調(diào)用UserDaoImpl的login方法
      驗證用戶【張三】登錄

      “Java怎么實現(xiàn)Spring的IoC容器的操作”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

      向AI問一下細(xì)節(jié)

      免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

      AI