關於Java的ClassLoader

關於理論很少說,本人不善於理論。這裏有一篇文章講ClassLoad的,講的很詳細:Java ClassLoad詳解java

我這裏所講的是,我實際開發中曾經遇到一個問題,是這樣的,之前有個需求是天天爬取多個日報的網站。而後我本身寫了個爬蟲框架,每一個日報都用java實現了一個爬取規則類,框架會選出當天須要爬取的報紙,並對這些報紙沒分報紙啓動一個每日任務,對一份報紙來講,每隔半小時嘗試爬取一次,爬取到數據結束任務。然而對於規則而言,有些網站常常會有變更,爬取規則就須要有相應的更新。那麼問題來了,規則更新了怎麼辦?框架

最簡單解決辦法是,從新上傳規則,而後重啓Tomcat,而後繼續運行。顯然不太現實,後來經過對ClassLoader的研究,本身實現了一種ClassLoader,從而使每次加載類的時候從新讀取該類。ide

下面是個人MyClassLoader的實現,以及測試辦法測試

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

/**
 *
 * @author yun
 * @date 2015年3月26日
 * @time 下午3:21:38
 * @todo 以字節數據讀取類文件並加載
 *
 */
public class MyClassLoader extends ClassLoader {
	
	public MyClassLoader() {
		super(MyClassLoader.class.getClassLoader());
	}

	public Class<?> forName(String name) throws Exception {
		String path = "/" + name + ".class";
		InputStream is = System.class.getResourceAsStream(path);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int size = 0;
		while ((size = is.read()) != -1) {
			baos.write(size);
		}
		byte[] classData = baos.toByteArray();
		baos.close();
		is.close();
		return super.defineClass(name, classData, 0, classData.length, null);
	}
}


測試網站

任務類ui

import java.text.SimpleDateFormat;
import java.util.Date;
 
public class Task {
     
	private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss ");
	
    public void execute() {
        //執行任務
        System.out.println(format.format(new Date()) + "Just A Test");//輸出語句a
        System.out.println(format.format(new Date()) + "The Other Test");//輸出語句b
    }
}

Quartz定時Job
spa

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class ActionJob implements Job {

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		while (true) {
			try {
				String path = "Task";
				// 加載任務類
				Class<?> clas = Class.forName(path);//默認ClassLoad
//				Class<?> clas = new MyClassLoader().forName(path);//我本身實現的ClassLoad
				Object o = clas.newInstance();// 實例化已任務類對象
				// 獲取啓動方法,並啓動
				clas.getMethod("execute").invoke(o);
				Thread.sleep(20000);//每隔20秒加載並執行一次Task
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

主方法入口code

import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

public class Start {

	public static void main(String[] args) {
		try {
			StdSchedulerFactory factory = new StdSchedulerFactory();
			Scheduler scheduler = factory.getScheduler();
			JobDetail detail = newJob(ActionJob.class)
					.withIdentity("d_name", "d_group")
					.build();
			Trigger trigger = newTrigger()
					.withIdentity("t_name", "t_group")
					.startNow()
					.build();
			scheduler.scheduleJob(detail, trigger);
			scheduler.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

測試方法:orm

一、以默認ClassLoader加載任務類,只開輸出語句a,編譯獲取四個class文件對象

二、以默認ClassLoader加載任務類,打開輸出語句a和b,編譯獲取四個class文件

三、以MyClassLoader加載任務類,只開輸出語句a,編譯獲取四個class文件

四、以MyClassLoader加載任務類,打開輸出語句a和b,編譯獲取四個class文件

在1中執行Start,每隔20秒輸出一次語句a,不中止把2中的Task.class文件copy覆蓋1中的Task.class,繼續觀察輸出,會發現一隻輸出語句a,而後在刪掉Task.class文件,繼續觀察輸出,結果是繼續輸出語句a


能夠看出在刪除Task.class後程序依舊執行,說明修改Task.class不會影響任務的執行


而後中止以前的人物,執行3中的Start,只有輸出語句a,而後修改把4中的Task.class覆蓋3中的,繼續觀察數據,會發現輸出語句a和b都有了

刪除Task.class以後

報異常了,說明同過MyClassLoad每次都是從新讀取任務類並加載的。

相關文章
相關標籤/搜索