关于理论不多说,本人不善于理论。这里有一篇文章讲ClassLoad的,讲的很详细:Java ClassLoad详解
我这里所讲的是,我实际开发中曾经遇到一个问题,是这样的,以前有个需求是每天爬取多个日报的网站。然后我自己写了个爬虫框架,每个日报都用java实现了一个爬取规则类,框架会选出当天需要爬取的报纸,并对这些报纸没分报纸启动一个每日任务,对一份报纸来说,每隔半小时尝试爬取一次,爬取到数据结束任务。然而对于规则而言,有些网站经常会有变动,爬取规则就需要有相应的更新。那么问题来了,规则更新了怎么办?
最简单解决办法是,重新上传规则,然后重启Tomcat,然后继续运行。显然不太现实,后来通过对ClassLoader的研究,自己实现了一种ClassLoader,从而使每次加载类的时候重新读取该类。
下面是我的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);
}
}测试
任务类
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
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();
}
}
}
}主方法入口
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();
}
}
}测试方法:
1、以默认ClassLoader加载任务类,只开输出语句a,编译获取四个class文件
2、以默认ClassLoader加载任务类,打开输出语句a和b,编译获取四个class文件
3、以MyClassLoader加载任务类,只开输出语句a,编译获取四个class文件
4、以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每次都是重新读取任务类并加载的。
原文:http://my.oschina.net/u/1240328/blog/392108