今天在修改項(xiàng)目一個(gè)JSP文件時(shí),突然想到Tomat是怎么實(shí)現(xiàn)動(dòng)態(tài)實(shí)時(shí)加載JSP編譯后的class類的?
查了半天資料,看了很多文章,終于明白是怎么回事了:ClassLoader,當(dāng)tomcat發(fā)現(xiàn)jsp改變后,將用新的ClassLoader去加載新的類
具體原理我將單獨(dú)總結(jié)一下,這里簡(jiǎn)單實(shí)現(xiàn)了動(dòng)態(tài)加載類
1.定義服務(wù)類
public
class
Servlet {
public
void
service(){
System.out.println(
"運(yùn)行服務(wù)方法"
);
}
}
2.定義服務(wù)線程
public
class
ServiceThread
extends
Thread{
public
void
run(){
try
{
ClassLoader classLoader
=
this
.getContextClassLoader();
Class clazz
= classLoader.loadClass("Servlet"
);
Method service
= clazz.getMethod("service",
null
);
service.invoke(clazz.newInstance(),
null
);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
?
3.自定義ClassLoader
public
class
MyClassLoader
extends
ClassLoader{
@Override
public
Class loadClass(String name,
boolean
resolve)
throws
ClassNotFoundException{
try
{
//
我們要?jiǎng)?chuàng)建的Class對(duì)象
Class clasz =
null
;
//
必需的步驟1:如果類已經(jīng)在系統(tǒng)緩沖之中
//
我們不必再次裝入它
clasz =
findLoadedClass(name);
if
(clasz !=
null
)
return
clasz;
try
{
//
讀取經(jīng)過加密的類文件
if
(name.equals("Servlet"
)){
//加載class文件字節(jié)
byte
classData[] = Util.readFile(ProgramPathHelper.getProgramPath()+"/"+name + ".class"
);
if
(classData !=
null
) {
//
... 再把它轉(zhuǎn)換成一個(gè)類
clasz = defineClass(name, classData, 0
,
classData.length);
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
//
必需的步驟2:如果上面沒有成功
//
我們嘗試用默認(rèn)的ClassLoader裝入它
if
(clasz ==
null
)
clasz
=
findSystemClass(name);
//
必需的步驟3:如有必要,則裝入相關(guān)的類
if
(resolve && clasz !=
null
)
resolveClass(clasz);
//
把類返回給調(diào)用者
return
clasz;
}
catch
(Exception ie) {
throw
new
ClassNotFoundException(ie.toString());
}
}
}
?
4.實(shí)現(xiàn)文件監(jiān)聽類
public
class
CCFileListener
implements
FileAlterationListener{
public
static
HashMap<String,ClassLoader> claMap =
new
HashMap<String, ClassLoader>
();
ZJPFileMonitor monitor
=
null
;
@Override
public
void
onStart(FileAlterationObserver observer) {
//
System.out.println("onStart");
}
@Override
public
void
onDirectoryCreate(File directory) {
System.out.println(
"onDirectoryCreate:" +
directory.getName());
}
@Override
public
void
onDirectoryChange(File directory) {
System.out.println(
"onDirectoryChange:" +
directory.getName());
}
@Override
public
void
onDirectoryDelete(File directory) {
System.out.println(
"onDirectoryDelete:" +
directory.getName());
}
@Override
public
void
onFileCreate(File file) {
System.out.println(
"onFileCreate:" +
file.getName());
dyncLoadClass(file.getName());
}
@Override
public
void
onFileChange(File file) {
//文件改變處理函數(shù)
System.out.println(
"onFileChange : " +
file.getName());
dyncLoadClass(file.getName());
}
private
void
dyncLoadClass(String className){
if
(className.contains("Servlet"
)){
//
ZJPFileMonitor.thread.setContextClassLoader(new MyClassLoader());
claMap.put(className,
new
MyClassLoader());
}
}
@Override
public
void
onFileDelete(File file) {
System.out.println(
"onFileDelete :" +
file.getName());
}
@Override
public
void
onStop(FileAlterationObserver observer) {
//
System.out.println("onStop");
}
}
public
class
CCFileMonitor {
FileAlterationMonitor monitor
=
null
;
public
CCFileMonitor(
long
interval)
throws
Exception {
monitor
=
new
FileAlterationMonitor(interval);
}
public
void
monitor(String path, FileAlterationListener listener) {
FileAlterationObserver observer
=
new
FileAlterationObserver(
new
File(path));
monitor.addObserver(observer);
observer.addListener(listener);
}
public
void
stop()
throws
Exception{
monitor.stop();
}
public
void
start()
throws
Exception {
monitor.start();
}
public
static
void
main(String[] args)
throws
Exception {
CCFileMonitor m
=
new
CCFileMonitor(5000
);
m.monitor(ProgramPathHelper.getProgramPath(),
new
CCFileListener());
m.start();
Servlet servlet
=
new
Servlet();
servlet.service();
MyClassLoader defaultCl
=
new
MyClassLoader();
while
(
true
){
Thread.currentThread().sleep(
3000
);
Thread t
=
new
ServiceThread();
//設(shè)置新線程的類加載器
ClassLoader classLoader
= CCFileListener.claMap.get("Servlet.class"
);
if
(classLoader==
null
){
classLoader
=
defaultCl;
}
t.setContextClassLoader(classLoader);
t.start();
}
}
}
public static HashMap<String,ClassLoader> claMap = new HashMap<String, ClassLoader>
();
在監(jiān)聽到文件改變后,依據(jù)類名重new一個(gè)類加載器,用于加載類。
ClassLoader classLoader = CCFileListener.claMap.get("Servlet.class"
);
if(classLoader==null
){
classLoader =
defaultCl; }
首先獲取類名對(duì)應(yīng)的加載器,如果沒有使用默認(rèn)的加載器
ClassLoader classLoader = this
.getContextClassLoader(); Class clazz = classLoader.loadClass("Servlet"
); Method service = clazz.getMethod("service", null
); service.invoke(clazz.newInstance(), null
);
在線程內(nèi)部使用剛才在外部設(shè)置的線程上下文加載器加載新的Servlet,并執(zhí)行
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

