天天看點

org.springframework.core簡單分析

  這個包的類主要用于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) {

            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 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 {

org.springframework.core簡單分析
org.springframework.core簡單分析

   static class jdk13controlflow implements controlflow {

org.springframework.core簡單分析
org.springframework.core簡單分析

    static class jdk14controlflow implements controlflow {

org.springframework.core簡單分析
org.springframework.core簡單分析

在這裡,我們可以學到的東西就如何去判斷目前方法棧的資訊?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(methodname, "method name must not be null");

            for (int i = 0; i < this.stack.length; i++) {

                if (this.stack[i].getclassname().equals(classname) &&

                        this.stack[i].getmethodname().equals(methodname)) {

         * 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反射技術也有不小的幫助。

文章轉自莊周夢蝶  ,原文釋出時間5.17