自定义ClassLoader详解_将web程序部分业务转化到本地程序执行

核心类:

package com.zizhu.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.HashSet;
import java.util.Set;

/**
 * 自定义类加载器,重载URLClassLoader大部分方法,将jar文件添加到ClassLoader,将jar包路径下所有jar包添加到
 * ClassLoader,将ClassPath路径下所有的类以及资源加载到ClassLoader
 * @author 紫竹
 *
 */
public class MyClassLoader extends URLClassLoader {
	
	private Set<String> names = new HashSet<String>();// 存放自定义类的名称

	public MyClassLoader(URL[] urls, ClassLoader parent,
			URLStreamHandlerFactory factory) {
		super(urls, parent, factory);
	}

	public MyClassLoader(URL[] urls, ClassLoader parent) {
		super(urls, parent);
	}

	public MyClassLoader(URL[] urls) {
		super(urls);
	}

	/**
	 * url 既可以是一个文件路径(这个文件路径必须是url格式),里面存放了资源文件,存放了类;也可以是一个jar文件的url格式
	 * @param urls
	 */
	public void addURL(URL... urls){
		for (URL url : urls) {
			System.out.println("加载类路径:" + url.toString());
			super.addURL(url);
		}
	}
	
	/**
	 * 加载jar文件到ClassLoader
	 * @param files
	 */
	public void addJar(File... files){
		if(files == null || files.length == 0) return ;
		for(File file : files){
			try {
				addURL(file.toURI().toURL());
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 加载ClassPath到ClassLoader,classPath下所有的资源文件,类全部加载到ClassLoader
	 * @param classPath 类路径
	 */
	public void addClassPath(String classPath){
		if(isEmpty(classPath)) return;
		addClassPath(new File(classPath));
	}
	
	/**
	 * 添加类路径到ClassLoader
	 * @param path
	 */
	public void addClassPath(File path){
		if(path.isFile()) return;
		try {
			addURL(path.toURI().toURL());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 添加jar包的路径,即我们所说的lib包
	 * @param path
	 */
	public void addJarPath(File path){
		URL []urls = Path2URL(path);
		if(urls == null || urls.length == 0) return ;
		addURL(urls);
	}
	
	/**
	 * @param path jar包路径
	 * @return ClassLoader支持的URL数组
	 */
	public static URL[] Path2URL(File path){
		if(path.isFile()) return new URL[0];
		File files[] = path.listFiles();
		URL urls [] = new URL[files.length];
		for(int i = 0;i<files.length;i++){
			try {
				urls[i] = files[i].toURI().toURL();
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		return urls;
	}
	
	@Override
	public URL findResource(String name) {
		System.out.println("查找资源:" + name);
		return super.findResource(name);
	}
	
	private boolean isEmpty(String classPath) {
		if(classPath != null && classPath.trim().length() > 0) return false;
		return true;
	}

}
通过这个类,能将用户指定的jar包,classpath下用户的所有类手动加载到classLoader,这个类增强了很多URLClassLoader的方法,使得它更好理解,更好使用

调用web业务逻辑类:

package com.zizhu;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;

import com.zizhu.util.ConfigUtil;
import com.zizhu.util.MyClassLoader;

public class WebToNative {
	
	public void startToRun(){
		String libPath = ConfigUtil.getValue("libPath");
		String mainClass = ConfigUtil.getValue("mainClass");
		String homePath = ConfigUtil.getValue("homePath");
		String methodName = ConfigUtil.getValue("methodName");
		try {
			File lib = new File(libPath);
			File files[] = lib.listFiles();
			URL []urls = MyClassLoader.Path2URL(new File(libPath));
			MyClassLoader loader = new MyClassLoader(urls, 
					Thread.currentThread().getContextClassLoader());
			//三种方式都可以,都是添加类路径
//			loader.addURL(new File(homePath).toURI().toURL());
//			loader.addClassPath(new File(homePath));
			loader.addClassPath(homePath);
			Thread.currentThread().setContextClassLoader(loader);
			Class clazz = loader.loadClass(mainClass);
			Method m = clazz.getMethod(methodName, null);
			m.invoke(clazz.newInstance(), null);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} 
	}

}

下面使用这两个类实现将web程序的部分逻辑在不开web服务器的情况下直接转化成命令行的形式执行:

1.测试类:

package com.zizhu;

public class Test {
	
	public static void main(String args[]){
		new WebToNative().startToRun();
	}
	
}

接下来就是想方设法让这个程序跑起来,让这个类跑起来必须定义一个native.properties的配置文件,里面提供四个属性:

libPath=D:/Java/WorkspaceForMyeclipse/exam2.0/WebRoot/WEB-INF/lib/
homePath=D:/Java/WorkspaceForMyeclipse/exam2.0/WebRoot/WEB-INF/classes/
mainClass=com.onnet.utils.schedule.ExamTipAndDeleteSchedule
methodName=tipAndDelete

接下来就能启用命令行,运行这个程序,这个程序运行的原理是这样的:

1.首先会用自定义的MyClassLoader去加载libPath下所有的jar包

2.加载jar包后,必须把web程序的classpath,也就是源码的类加入到classLoader,homePath,这样,自定义的MyClassLoader就能找到web程序所有的资源,web程序运行的类(也就是web程序需要执行的业务逻辑)

3.然后将自定义的这个MyClassLoader设置为当前线程的ClassLoader

4.最后采用反射机制调用web的业务逻辑类,以及业务逻辑的某个方法



发布了116 篇原创文章 · 获赞 15 · 访问量 35万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章