自定義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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章