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