概述
我們知道在開發(fā)工程的時候jsp文件是即修改即生效的娃兽。Tomcat jsp熱部署的實現(xiàn)原理是每個JSP頁面從上次訪問到下次訪問總是有默認幾秒的緩存時間的绰上,也就說并不是嚴格的即修改即生效搁拙,tocmat7默認是有4秒的緩存延遲的。這個默認的緩存延遲是在類 EmbeddedServletOptions 的 private intmodificationTestInterval = 4; 這個屬性定義的俄周。如果過了4秒緩存時間即失效沪铭,這個時候tomcat就會讀取jsp的modified時間戳和work目錄下編譯好的class文件的modified的時間戳作對比。如果相等則class文件沒有過期硅瞧,則不會重新編譯jsp文件份乒,如果過期了則重新將jsp編譯成java,并進一步編譯成class腕唧。同時創(chuàng)建一個新的JasperLoader來重新加載這個有jsp編譯好的class文件或辖。
熱部署原理
一個class只能由classloader加載一次,如果再次加載將會導(dǎo)致類沖突枣接。但是JVM表示一個類是否是同一個類有兩個條件颂暇。
- 看這個類的完整類名是否一樣(包名和類名)
- 加載這個類的ClassLoader是否是同一個,也就是說這個ClassLoader是否是同一個實例但惶。
如果是同一個ClassLoader的不同的實例加載同一個類耳鸯,那么就可以實現(xiàn)熱更新部署了。
下面具體分析一下這個過程:
JspServlet.serviceJspFile() 方法
- 判斷當前jsp頁面的JspServletWrapper對象是否存在膀曾,如果不存在县爬,則創(chuàng)建并存放到 jsps緩存中。
private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>();
2.調(diào)用JspServletWrapper.service() 方法
JspServletWrapper.service() 方法
- 判斷該jsp是否刪除
- 判斷該 jsp 是否可用
- 判斷當前項目是不是development模式運行添谊,如果是則每次都執(zhí)行JspCompilationContext.compile() 方法
- 判斷是否是首次請求捌省,如果首次請求則也執(zhí)行JspCompilationContext.compile() 方法。
development 模式配置
JspServlet 模式是development模式碉钠,可以通過web.xml中把development模式關(guān)閉 development=false
JspCompilationContext.compile() 方法
- 根據(jù)class文件(或java文件,通過一個參數(shù)可以選擇)的最后修改時間卷拘,判斷文件是否更新過喊废,如果更新過,
- 刪除之前編譯過的文件信息
- 把jspLoader置空栗弟,需要重新創(chuàng)建一個ClassLoader污筷,來達到熱加載的目的。
- 調(diào)用Compiler.compile()重新把jsp轉(zhuǎn)換成servlet,并編譯servlet成class文件瓣蛀。
- 把JspServletWrapper.reload 修改為true陆蟆。后面getServlet() 根據(jù)這個參數(shù)判斷是否重新加載該servlet。
Compiler.isOutDated()方法
判斷上次請求的時候+4秒的時候惋增,是否大于當前時間叠殷,也就是說,距離上次檢查文件更新時間是否有4秒的時間诈皿,如果小于4秒則不進行檢查文件是否更新林束,不重新加載編譯jsp文件。
根據(jù)上次最后修改時間稽亏,和這次獲得的文件最后修改時候做對比壶冒,來判斷文件是否更新過。
ctxt.getOptions().getModificationTestInterval() 默認的時間為4秒
Compiler.compile() 方法
- 把jsp文件轉(zhuǎn)換成java(servlet)文件
- 把java文件編譯成class文件截歉。
JspServletWrapper.getServlet() 方法
- 通過reload判斷是否需要重新加載Servlet
- 如果需要重新加載胖腾,則先銷毀之前的Servlet
- ctx.getJspLoader() 當前這個ClassLoader在上面已經(jīng)賦值為null,在這個方法里又重新創(chuàng)建了一個Classloader實例
- 初始化新創(chuàng)建的Servlet
- 把reload賦值為 false
getJspLoader() 方法
調(diào)用Servlet.service() 方法
在JspServlet.serviceJspFile() 方法 獲取Jsp對應(yīng)的Servlet實例后瘪松,然后調(diào)用Servlet的Service方法咸作。
想了解更多精彩內(nèi)容請關(guān)注我的公眾號