莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          org.springframework.core簡單分析

          Posted on 2007-04-10 16:56 dennis 閱讀(4556) 評論(2)  編輯  收藏 所屬分類: java源碼解讀
              這個包的類主要用于spring框架的異常處理和一些核心的助手類(與框架具體部分無關的)。
              這個包中主要應用到了簡單工廠模式,用于判斷jdk版本,根據jdk版本不同提供不同的集合類、當前方法棧信息等。我們來看看是如何判斷當前用戶的jdk版本的:

          package org.springframework.core;

          public class JdkVersion {
              
              
          public static final int JAVA_13 = 0;
              
              
          public static final int JAVA_14 = 1;
              
              
          public static final int JAVA_15 = 2;

              
          private static String javaVersion;

              
          private static int majorJavaVersion = JAVA_13;
              
              
          static {
                  javaVersion 
          = System.getProperty("java.version");
                  
          // should look like "1.4.1_02"
                  if (javaVersion.indexOf("1.4."!= -1) {
                      majorJavaVersion 
          = JAVA_14;
                  }
                  
          else if (javaVersion.indexOf("1.5."!= -1) {
                      majorJavaVersion 
          = JAVA_15;
                  }
                  
          // else leave as 1.3 default
              }

              
          /**
               * Return the full Java version string, as returned by
               * <code>System.getProperty("java.version")</code>.
               
          */
              
          public static String getJavaVersion() {
                  
          return javaVersion;
              }

              
          /**
               * Get the major version code. This means we can do things like
               * <code>if (getMajorJavaVersion() < JAVA_14)</code>.
               * 
          @return a code comparable to the JAVA_XX codes in this class
               * 
          @see #JAVA_13
               * 
          @see #JAVA_14
               * 
          @see #JAVA_15
               
          */
              
          public static int getMajorJavaVersion() {
                  
          return majorJavaVersion;
              }

          }

          直接獲取系統的java.version屬性來進行jdk版本的判斷。而CollectionFactory依據這個類來創建不同的集合類型,如果是jdk1.4就優先使用jdk1.4的集合框架,再次選擇Commons Collections,最后才不得已就使用jdk1.3的集合框架,這里比較有趣的是判斷Commons Collections的方法就是嘗試Class.forName一個Commons集合框架中的對象,如果成功,當然證明classpath有commons-collections.jar包:
          static {
                  
          // Check whether JDK 1.4+ collections and/or
                  
          // Commons Collections 3.x are available.
                  if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_14) {
                      logger.info(
          "JDK 1.4+ collections available");
                  }
                  
          try {
                      Class.forName(COMMONS_COLLECTIONS_CLASS_NAME);
                      commonsCollections3xAvailable 
          = true;
                      logger.info(
          "Commons Collections 3.x available");
                  }
                  
          catch (ClassNotFoundException ex) {
                      commonsCollections3xAvailable 
          = false;
                  }
              }

          然后就是一系列的getXXXIfPossible()方法用以獲取最優版本的集合類型,比如getLinkedHashMapIfPossible():
          public static Map createLinkedMapIfPossible(int initialCapacity) {
                  
          if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_14) {
                      logger.debug(
          "Creating [java.util.LinkedHashMap]");
                      
          return Jdk14CollectionFactory.createLinkedHashMap(initialCapacity);
                  }
                  
          else if (commonsCollections3xAvailable) {
                      logger.debug(
          "Creating [org.apache.commons.collections.map.LinkedMap]");
                      
          return CommonsCollectionFactory.createLinkedMap(initialCapacity);
                  }
                  
          else {
                      logger.debug(
          "Falling back to [java.util.HashMap] for linked map");
                      
          return new HashMap(initialCapacity);
                  }
              }
          其中的Jdk14CollectionFactory 和CommonsCollectionFactory 也都是工廠類。可以看到,一個優秀的通用框架對于版本的兼容性非常重視。

              這個包中另外一個需要注意的就是用于spring AOP功能實現的輔助類——ControlFlow。ControlFlow按照rod johnson的說法就是用于獲取當前調用的方法棧的具體信息。ControlFlow是一個接口,擁有3個方法用于判斷當前方法棧的位置:
          public interface ControlFlow {

              
          /**
                查找當前方法調用是否則在某類中
               * 
          @param clazz the clazz to look for
               
          */
              
          boolean under(Class clazz);

              
          /**
               * 查找當前方法調用是否則在某類的某個方法中
               * according to the current stack trace.
               * 
          @param clazz the clazz to look for
               * 
          @param methodName the name of the method to look for
               
          */
              
          boolean under(Class clazz, String methodName);

              
          /**
               * 當前棧幀是否包含傳入的記號
               * 
          @param token the token to look for
               
          */
              
          boolean underToken(String token);

          }

          然后根據jdk版本的不同采用不同的方式實現這個接口:Jdk14ControlFlow和Jdk13ControlFlow。這是典型的策略模式的應用。需要注意的是,這兩個具體類的是放在工廠類ControlFlowFactory中作為內部類實現的:
          public abstract class ControlFlowFactory {
             
             
          static class Jdk13ControlFlow implements ControlFlow {
            
             

              
          static class Jdk14ControlFlow implements ControlFlow {
             
          }

          在這里,我們可以學到的東西就如何去判斷當前方法棧的信息?jdk1.4之前只能通過對StackTrace的字符串進行分析,而jdk1.4引入了java.lang.StackTraceElement用于獲取當前方法調用所處的棧幀的信息,看看spring的使用方法,相當簡單:
          static class Jdk14ControlFlow implements ControlFlow {

                  
          private StackTraceElement[] stack;

                  
          public Jdk14ControlFlow() {
                      
          this.stack = new Throwable().getStackTrace();
                  }

                  
          /**
                   * Searches for class name match in a StackTraceElement.
                   
          */
                  
          public boolean under(Class clazz) {
                      Assert.notNull(clazz, 
          "Class must not be null");
                      String className 
          = clazz.getName();
                      
          for (int i = 0; i < stack.length; i++) {
                          
          if (this.stack[i].getClassName().equals(className)) {
                              
          return true;
                          }
                      }
                      
          return false;
                  }

                  
          /**
                   * Searches for class name match plus method name match
                   * in a StackTraceElement.
                   
          */
                  
          public boolean under(Class clazz, String methodName) {
                      Assert.notNull(clazz, 
          "Class must not be null");
                      Assert.notNull(methodName, 
          "Method name must not be null");
                      String className 
          = clazz.getName();
                      
          for (int i = 0; i < this.stack.length; i++) {
                          
          if (this.stack[i].getClassName().equals(className) &&
                                  
          this.stack[i].getMethodName().equals(methodName)) {
                              
          return true;
                          }
                      }
                      
          return false;
                  }

                  
          /**
                   * Leave it up to the caller to decide what matches.
                   * Caller must understand stack trace format, so there's less abstraction.
                   
          */
                  
          public boolean underToken(String token) {
                      
          if (token == null) {
                          
          return false;
                      }
                      StringWriter sw 
          = new StringWriter();
                      
          new Throwable().printStackTrace(new PrintWriter(sw));
                      String stackTrace 
          = sw.toString();
                      
          return stackTrace.indexOf(token) != -1;
                  }
          }

          獲取當前棧幀的信息,對于一般的java開發者沒有什么意義,對于AOP的實現和框架開發者可能有比較重要的作用,我還未研讀spring的aop部分,不敢妄言,留待以后解答,如果您已經研讀過這部分代碼,不吝賜教。

          這個包另外的一個特點就是將java的反射API演示了一遍,特別是Constant.java(用于提取某個類public static final定義的常量)和ReflectiveVisitorHelper (反射助手類),對于學習java反射技術也有不小的幫助。


          評論

          # re: org.springframework.core簡單分析  回復  更多評論   

          2007-04-11 11:53 by cresposhi
          不錯 up
          最近正在重讀Core Java
          對這些框架源代碼很有感覺。。。

          # re: org.springframework.core簡單分析  回復  更多評論   

          2007-04-11 14:44 by dennis
          @cresposhi
          呵呵,我也是最近閑著無聊就讀讀源碼,多謝關注
          主站蜘蛛池模板: 阿克苏市| 遂昌县| 宿迁市| 东方市| 札达县| 桃源县| 镇赉县| 武功县| 汾西县| 鹰潭市| 昆明市| 漾濞| 大余县| 岳池县| 富平县| 尼玛县| 白河县| 黄陵县| 雅江县| 潮安县| 田林县| 福安市| 绍兴县| 健康| 那坡县| 洪湖市| 平顶山市| 隆子县| 十堰市| 海伦市| 新和县| 木兰县| 乐至县| 闻喜县| 岗巴县| 沧州市| 莱西市| 安化县| 江孜县| 永昌县| 睢宁县|