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包:
然後就是一系列的getXXXIfPossible()方法用以獲取最優版本的集合型別,比如getLinkedHashMapIfPossible():
這個包中另外一個需要注意的就是用於spring AOP功能實現的輔助類——ControlFlow。ControlFlow按照rod johnson的說法就是用於獲取當前呼叫的方法棧的具體資訊。ControlFlow是一個介面,擁有3個方法用於判斷當前方法棧的位置:
然後根據jdk版本的不同採用不同的方式實現這個介面:Jdk14ControlFlow和Jdk13ControlFlow。這是典型的策略模式的應用。需要注意的是,這兩個具體類的是放在工廠類ControlFlowFactory中作為內部類實現的:
在這裡,我們可以學到的東西就如何去判斷當前方法棧的資訊?jdk1.4之前只能通過對StackTrace的字串進行分析,而jdk1.4引入了java.lang.StackTraceElement用於獲取當前方法呼叫所處的棧幀的資訊,看看spring的使用方法,相當簡單:
獲取當前棧幀的資訊,對於一般的java開發者沒有什麼意義,對於AOP的實現和框架開發者可能有比較重要的作用,我還未研讀spring的aop部分,不敢妄言,留待以後解答,如果您已經研讀過這部分程式碼,不吝賜教。
這個包另外的一個特點就是將java的反射API演示了一遍,特別是Constant.java(用於提取某個類public static final定義的常量)和ReflectiveVisitorHelper (反射助手類),對於學習java反射技術也有不小的幫助。
這個包中主要應用到了簡單工廠模式,用於判斷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;
}
}
// 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
也都是工廠類。可以看到,一個優秀的通用框架對於版本的相容性非常重視。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);
}
}
這個包中另外一個需要注意的就是用於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);
}
/**
查詢當前方法呼叫是否則在某類中
* @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 {
}
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;
}
}
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反射技術也有不小的幫助。
相關文章
- mr原理簡單分析
- SSRF漏洞簡單分析
- 簡單陰影分析
- HDLC報文簡單分析
- 簡單的UrlDns鏈分析DNS
- js熱更新簡單分析JS
- MediaScanner原始碼簡單分析原始碼
- 骷髏病毒簡單分析
- CVE-2016-1757簡單分析
- CVE-2016-0799簡單分析
- redux簡單實現與分析Redux
- 一隻android簡訊控制馬的簡單分析Android
- SpringBoot2.0原始碼分析(一):SpringBoot簡單分析Spring Boot原始碼
- 伺服器系統簡單分析伺服器
- Java 8 ArrayList 原始碼簡單分析Java原始碼
- ZipperDown漏洞簡單分析及防護
- 編譯程式(compiler)的簡單分析編譯Compile
- ElasticSearch 簡單的 搜尋 聚合 分析Elasticsearch
- 面試官:簡單聊聊 Go 逃逸分析?面試Go
- 簡單分析軟體專案成本管理
- 簡單分析MySQL中的primary key功能MySql
- JavaScript簡單計算器程式碼分析JavaScript
- Linux SNAT/DNAT簡單理解與案例分析。Linux
- 金融大資料分析還不簡單,有了Smartbi簡單幾步就能搞定大資料
- 分析一個簡單的goroutine資源池Go
- CVE-2015-7547簡單分析與除錯除錯
- 伺服器使用系統簡單的分析伺服器
- Linux4.1.15核心啟動流程簡單分析Linux
- 簡單程式的時間複雜度分析時間複雜度
- 一個left join SQL 簡單優化分析SQL優化
- 簡單易懂的tinker熱修復原理分析
- openGauss核心分析2:簡單查詢的執行
- 簡單分析Flask 資料庫遷移詳情Flask資料庫
- 對 MySQL 慢查詢日誌的簡單分析MySql
- 簡單分析synchronized不會鎖洩漏的原因synchronized
- 瞭解Java物件,簡單聊聊JVM調優分析Java物件JVM
- 依存句法分析器的簡單實現
- Python3 | 簡單爬蟲分析網頁元素Python爬蟲網頁
- Python運用於資料分析的簡單教程Python