关于Java的ClassLoader
关于理论不多说,本人不善于理论。这里有一篇文章讲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每次都是重新读取任务类并加载的。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。