我們到底能走多遠系列(14)
扯淡:各位,你們的錢是省出來的嗎?前幾天一個同事(女)結婚,了解了下情況:男女一起買房接近80平方,實際房子是60平,四五十萬的首付吧,加上裝潢,男女全家,連外公外婆都出力出錢,搞定,圓滿買房結婚啦。大多數的我們都會走這么一段路或已經走了這一段路。我不知道你們聽到這樣普通的八卦會是怎樣的感受。
剛看完《溫州一家人》的前兩集,買家送女兒出國學習,帶着兒子老婆以撿破爛開始溫州的新生活。雖然是電視劇,但上點年紀的都應該知道我們的上一輩很多人都有類似的魄力,對,因為那時候窮,窮怕了,拼了,現在一無所有,輸了,還是一無所有,不怕。
可是現在不一樣了,我們稍稍付出點努力就可以溫飽,再多付出點,還能接近傳說的小康。我們安逸,我們愛安逸,誰想打破安逸?誰也不想。所以我們寧願背負巨額的按揭,寧願接過父母的血汗,寧願丟掉自己的夢想,也要維護住着安逸。
我也不知道那個是好的那個是不好的,畢竟我也沒資格評價,但是這種矛盾是我們大多數人現在要面對的,睿智的你會怎么度過?
--------------------------------------------------------------------------------------
前幾天利用了下午休時間去了家公司面試,有個問題說:如何來確保你寫的模塊或方法是高質量的呢?
我當時說:通過單元測試,什么review,性能測試。
回答方向不對。
可讀性:代碼是否可讀易讀,對於一個團隊來說,編碼標准是否一致,編碼風格是否一致;
功能性:代碼正確得實現了業務邏輯;
可維護性:代碼邏輯是有層次的,是容易修改的;
高效性:代碼實現在時間和空間的使用上是高效的;
你會怎么回答呢?
主題:
外圍知識:
1,jvm(java virtual mechanism)load class的基本原理 可以參考園子里的文章
2,關於class.forName(String)
首先,我們是明白class文件被jvm加載進來后,可以理解成以二進制形式存在內存中,每一個class我們可以通過包名和類名找到它。
其次,有了new這樣的操作,我們為什么還需要這東西做什么呢?
網上的一段代碼解釋了這個問題:
String className = readfromXMlConfig;//從xml 配置文件中獲得字符串 class c = Class.forName(className); factory = (ExampleInterface)c.newInstance();
我們可以看到被newInstance出來的實例只要是繼承ExampleInterface接口就可以滿足了,有一點需要記住的是,如果提供的類沒有繼承ExampleInterface,就會異常。
new關鍵字和newInstance()方法的區別:
newInstance: 弱類型。低效率。只能調用無參構造。(可是后面的代碼看來似乎能夠有參構造...)
new: 強類型。相對高效。能調用任何public構造。
3,加載類 java.lang.ClassLoader
我們可以通過調用ClassLoader的loadClass(String)方法來加載自己需要的類。
例子:
package code.loader; import java.net.URL; import java.net.URLClassLoader; import code.mytest.Test2; public class MyLoader1 { public static void main(String[] args) throws Exception { // 類名(注意:這里是包含了包名沒有.class的形式) String className = "code.mytest.Test2"; // class文件位置 URL url = new URL("file:/D:/"); // ClassLoader實例 ClassLoader loader = new URLClassLoader(new URL[] {url}); // load進來之后是一個Class實例 Class c1 = loader.loadClass(className); // 利用Class實例得到我們想要的實例 Test2 test = (Test2)c1.newInstance(); // 調用新實例的方法 test.sayYouILY(); } }
tomcat load class:
Tomcat需要自己加載web工程中的servlet類,我們頻繁發布修改后的工程,Tomcat就需要加載我們提供的代碼讓他跑起來。
在Http請求進入tomcat后,tomcat需要根據調用的servlet名把這個類先加載進來,這個過程是由tomcat的內部類:org.apache.catalina.loader.WebappLoader實現的,這個類實現了tomcat的org.apache.catalina.Loader接口,而WebappLoader中引用org.apache.catalina.loader.WebappClassLoader,而WebappClassLoader繼承了URLClassLoader
WebappLoader用getClassLoader()方法向外提供出一個自定義的ClassLoader,為什么這么說呢?來看下源碼:
1,WebappLoader中的start()方法中會調用下面兩句:
classLoader = createClassLoader();//這個是內置的private方法 classLoader.setResources(container.getResources());
2,createClassLoader源碼:
private WebappClassLoader createClassLoader() throws Exception { // 這個loaderClass是啥東西呀? // 其實是WebappClassLoader私有變量,定義成:private String loaderClass ="org.apache.catalina.loader.WebappClassLoader"; Class clazz = Class.forName(loaderClass); WebappClassLoader classLoader = null; if (parentClassLoader == null) { parentClassLoader = container.getParentClassLoader(); } Class[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; // API:返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。parameterTypes 參數是 Class 對象的一個數組,這些 Class 對象按聲明順序標識構造方法的形式參數類型。 Constructor constr = clazz.getConstructor(argTypes); //使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。(這樣做是不是達到了前面提到的有參構造呢) classLoader = (WebappClassLoader) constr.newInstance(args); return classLoader; }
3,通過WebappClassLoader,可以控制已經加載的類不用再重復操作。
每一個通過WebappClassLoader加載的類都會被org.apache.catalina.loader.ResourceEntry記錄下來
package org.apache.catalina.loader; import java.net.URL; import java.security.cert.Certificate; import java.util.jar.Manifest; public class ResourceEntry { public long lastModified = -1; public byte[] binaryContent = null;// 類是以byte數組類型被儲存在內存中 public volatile Class loadedClass = null; public URL source = null;// URL名稱 public URL codeBase = null; public Manifest manifest = null; public Certificate[] certificates = null; }
在WebappClassLoader里有一個Map來記錄已經被加載的類
/** * The cache of ResourceEntry for classes and resources we have loaded, * keyed by resource name. */ protected HashMap resourceEntries = new HashMap();
這樣一來當需要加載新類是我們先在這個map里面去找一下
來看一下findResource方法的源碼:
public URL findResource(final String name) { if (log.isDebugEnabled()) log.debug(" findResource(" + name + ")"); URL url = null; if (hasExternalRepositories && searchExternalFirst) url = super.findResource(name); if (url == null) { // 去傳說中的內存里找是否已經加載 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); // 沒有加載過 if (entry == null) { if (securityManager != null) { PrivilegedAction<ResourceEntry> dp = new PrivilegedFindResourceByName(name, name); entry = AccessController.doPrivileged(dp); } else { entry = findResourceInternal(name, name); } } // 加載過 if (entry != null) { url = entry.source; } } if ((url == null) && hasExternalRepositories && !searchExternalFirst) url = super.findResource(name); if (log.isDebugEnabled()) { if (url != null) log.debug(" --> Returning '" + url.toString() + "'"); else log.debug(" --> Resource not found, returning null"); } // 返回URL return (url); }
總結:
1,tomcat自定義自己的class loader,值得借鑒,還沒有研究核心的實現類,因為還需要學習下自定義loader的實現。
2,用hashmap來存需要實時查詢的資源,很實用。
讓我們繼續前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不會成功。
共勉