看到一套开源的监控系统的热部署功能,梳理了一下,也就相关知识简单备注如下以备忘。
热部署的过程是调用ProcessorManager类的executeProcessor方法,其中先加载Processor的实例,然后调用此Processor实例的execute方法。
public class ProcessorManager implements BeanFactoryAware{
public void executeProcessor(String processCode,ProcessorContext processorContext) throws Exception{
Processor processor = processorMap.get(processCode);
KldProcess kldProcess = kldProcessDAO.selectByProcessCode(processCode);
//当流程中有组件被重新编译或者组件运行参数有变动,需要重新装载流程
if (processor == null || kldProcess.getIsNeedReload().intValue() == KldProcess.NEED_RELOAD.intValue()) {
processor = loadProcess(processCode ,processorContext);
processorMap.put(processCode, processor);
}
processor.execute();
}
private Processor loadProcess(String processCode,ProcessorContext processorContext) throws Exception{
。。。。。。
if(component.getComponentSourceType().intValue() == KldComponent.JAVA_TYPE){
BaseComponent componentInstance = (BaseComponent) kldHotClassLoader.loadClassFromBinery(
component.getComponentCode(), component.getComponentClassSource(),
component.getComponentClassSource().length,component.getClassSourceStatus()).newInstance();
componentInstance.setBeanFactory(beanFactory);
componentInstance.setRuntimeParameter(parameter);
node.setComponent(componentInstance);
node.setScriptType(component.getComponentSourceType());
}else{
node.setScriptType(component.getComponentSourceType());
node.setScriptSource(component.getComponentSource());
}
node.setRuntimeParameter(parameter);
node.setBeanFactory(beanFactory);
node.setErrorHandler(logPrintErrorHandler);
node.setNodeId(processNode.getNodeId());
node.setNodeCode(processNode.getNodeCode());
processor.addNode(processNode.getNodeId(),node);
}
return processor;
}
public class KldHotClassLoader {
private static ClassLoader cl;
/**
* @param name
* @param byteArray
* @param len
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public Class<?> loadClassFromBinery(String componentCode,byte[] byteArray,long len , Long classStatus) throws Exception{
String classesPath = KldComponentManager.getClassesPath();
String extClassesPath = classesPath.substring(0, classesPath.lastIndexOf(File.separatorChar))+File.separatorChar+"extClasses";
//初始化,需要生成class文件
if( KldComponent.CLASS_STATUS_NEED_COMPILE.equals(classStatus) || KldComponent.CLASS_STATUS_MATCHED.equals(classStatus)){
File extClassesDir = new File(extClassesPath);
if(!extClassesDir.exists())extClassesDir.mkdir();
File classFile= new File(extClassesPath+File.separatorChar+componentCode+".class");
if(classFile.exists())classFile.delete();
OutputStream fos = new FileOutputStream(classFile);
fos.write(byteArray);
fos.flush();
fos.close();
@SuppressWarnings("deprecation")
URL[] externalURLs = new URL[]{new File(extClassesPath+File.separatorChar).toURL()};
cl = new URLClassLoader(externalURLs,KldHotClassLoader.class.getClassLoader());
Class<?> clazz = cl.loadClass(componentCode);
return clazz;
}else if(KldComponent.CLASS_STATUS_OUPUT.equals(classStatus)){
//先判断class文件是否存在,如果不存在则生成
File extClassesFile = new File(extClassesPath);
if(!extClassesFile.exists())extClassesFile.mkdir();
File classFile= new File(extClassesPath+File.separatorChar+componentCode+".class");
if(!classFile.exists()){
classFile.getParentFile().mkdirs();
OutputStream fos = new FileOutputStream(classFile);
fos.write(byteArray);
fos.flush();
fos.close();
}
@SuppressWarnings("deprecation")
URL[] externalURLs = new URL[]{new File(extClassesPath+File.separatorChar).toURL()};
cl = new URLClassLoader(externalURLs,KldHotClassLoader.class.getClassLoader());
Class<?> clazz = cl.loadClass(componentCode);
return clazz;
}else{
throw new Exception("illegal class status");
}
}
}
主要执行加载的代码其实就两句:
URLClassLoader cl = new URLClassLoader(externalURLs,KldHotClassLoader.class.getClassLoader());
Class<?> clazz = cl.loadClass(componentCode);
URLClassLoader的三个构造函数如下:
URLClassLoader(URL[] urls) Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader . |
URLClassLoader(URL[] urls,ClassLoader parent) Constructs a new URLClassLoader for the given URLs. |
URLClassLoader(URL[] urls,ClassLoader parent,URLStreamHandlerFactory factory) Constructs a new URLClassLoader for the specified URLs, parent class loader, and URLStreamHandlerFactory. |
Java利用ClassLoader将类载入内存,通过委派机制,把装载的任务传递给上级的装载器的,依次类推,直到启动类装载器(没有上级类装载器)。如果启动类装载器能够装载这个类,那么它会首先装载。如果不能,则往下传递。当父类为null时,JVM内置的类(称为:bootstrap class loader)就会充当父类。