package dynacode;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
public final class DynaCode {
private String compileClasspath;
private ClassLoader parentClassLoader;
private ArrayList sourceDirs = new ArrayList();
// class name => LoadedClass
private HashMap loadedClasses = new HashMap();
public DynaCode() {
this(Thread.currentThread().getContextClassLoader());
}
public DynaCode(ClassLoader parentClassLoader) {
this(extractClasspath(parentClassLoader), parentClassLoader);
}
/**
* @param compileClasspath
* used to compile dynamic classes
* @param parentClassLoader
* the parent of the class loader that loads all the dynamic
* classes
*/
public DynaCode(String compileClasspath, ClassLoader parentClassLoader) {
this.compileClasspath = compileClasspath;
this.parentClassLoader = parentClassLoader;
}
/**
* Add a directory that contains the source of dynamic java code.
*
* @param srcDir
* @return true if the add is successful
*/
public boolean addSourceDir(File srcDir) {
try {
srcDir = srcDir.getCanonicalFile();
} catch (IOException e) {
// ignore
}
synchronized (sourceDirs) {
// check existence
for (int i = 0; i < sourceDirs.size(); i++) {
SourceDir src = (SourceDir) sourceDirs.get(i);
if (src.srcDir.equals(srcDir)) {
return false;
}
}
// add new
SourceDir src = new SourceDir(srcDir);
sourceDirs.add(src);
info("Add source dir " + srcDir);
}
return true;
}
/**
* Returns the up-to-date dynamic class by name.
*
* @param className
* @return
* @throws ClassNotFoundException
* if source file not found or compilation error
*/
public Class loadClass(String className) throws ClassNotFoundException {
LoadedClass loadedClass = null;
synchronized (loadedClasses) {
loadedClass = (LoadedClass) loadedClasses.get(className);
}
// first access of a class
if (loadedClass == null) {
String resource = className.replace('.', '/') + ".java";
SourceDir src = locateResource(resource);
if (src == null) {
throw new ClassNotFoundException("DynaCode class not found "
+ className);
}
synchronized (this) {
// compile and load class
loadedClass = new LoadedClass(className, src);
synchronized (loadedClasses) {
loadedClasses.put(className, loadedClass);
}
}
return loadedClass.clazz;
}
// subsequent access
if (loadedClass.isChanged()) {
// unload and load again
unload(loadedClass.srcDir);
return loadClass(className);
}
return loadedClass.clazz;
}
private SourceDir locateResource(String resource) {
for (int i = 0; i < sourceDirs.size(); i++) {
SourceDir src = (SourceDir) sourceDirs.get(i);
if (new File(src.srcDir, resource).exists()) {
return src;
}
}
return null;
}
private void unload(SourceDir src) {
// clear loaded classes
synchronized (loadedClasses) {
for (Iterator iter = loadedClasses.values().iterator(); iter
.hasNext();) {
LoadedClass loadedClass = (LoadedClass) iter.next();
if (loadedClass.srcDir == src) {
iter.remove();
}
}
}
// create new class loader
src.recreateClassLoader();
}
/**
* Get a resource from added source directories.
*
* @param resource
* @return the resource URL, or null if resource not found
*/
public URL getResource(String resource) {
try {
SourceDir src = locateResource(resource);
return src == null ? null : new File(src.srcDir, resource).toURL();
} catch (MalformedURLException e) {
// should not happen
return null;
}
}
/**
* Get a resource stream from added source directories.
*
* @param resource
* @return the resource stream, or null if resource not found
*/
public InputStream getResourceAsStream(String resource) {
try {
SourceDir src = locateResource(resource);
return src == null ? null : new FileInputStream(new File(
src.srcDir, resource));
} catch (FileNotFoundException e) {
// should not happen
return null;
}
}
/**
* Create a proxy instance that implements the specified access interface
* and delegates incoming invocations to the specified dynamic
* implementation. The dynamic implementation may change at run-time, and
* the proxy will always delegates to the up-to-date implementation.
*
* @param interfaceClass
* the access interface
* @param implClassName
* the backend dynamic implementation
* @return
* @throws RuntimeException
* if an instance cannot be created, because of class not found
* for example
*/
public Object newProxyInstance(Class interfaceClass, String implClassName)
throws RuntimeException {
MyInvocationHandler handler = new MyInvocationHandler(
implClassName);
return Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[] { interfaceClass }, handler);
}
private class SourceDir {
File srcDir;
File binDir;
Javac javac;
URLClassLoader classLoader;
SourceDir(File srcDir) {
this.srcDir = srcDir;
String subdir = srcDir.getAbsolutePath().replace(':', '_').replace(
'/', '_').replace('\\', '_');
this.binDir = new File(System.getProperty("java.io.tmpdir"),
"dynacode/" + subdir);
this.binDir.mkdirs();
// prepare compiler
this.javac = new Javac(compileClasspath, binDir.getAbsolutePath());
// class loader
recreateClassLoader();
}
void recreateClassLoader() {
try {
classLoader = new URLClassLoader(new URL[] { binDir.toURL() },
parentClassLoader);
} catch (MalformedURLException e) {
// should not happen
}
}
}
private static class LoadedClass {
String className;
SourceDir srcDir;
File srcFile;
File binFile;
Class clazz;
long lastModified;
LoadedClass(String className, SourceDir src) {
this.className = className;
this.srcDir = src;
String path = className.replace('.', '/');
this.srcFile = new File(src.srcDir, path + ".java");
this.binFile = new File(src.binDir, path + ".class");
compileAndLoadClass();
}
boolean isChanged() {
return srcFile.lastModified() != lastModified;
}
void compileAndLoadClass() {
if (clazz != null) {
return; // class already loaded
}
// compile, if required
String error = null;
if (binFile.lastModified() < srcFile.lastModified()) {
error = srcDir.javac.compile(new File[] { srcFile });
}
if (error != null) {
throw new RuntimeException("Failed to compile "
+ srcFile.getAbsolutePath() + ". Error: " + error);
}
try {
// load class
clazz = srcDir.classLoader.loadClass(className);
// load class success, remember timestamp
lastModified = srcFile.lastModified();
} catch (ClassNotFoundException e) {
throw new RuntimeException("Failed to load DynaCode class "
+ srcFile.getAbsolutePath());
}
info("Init " + clazz);
}
}
private class MyInvocationHandler implements InvocationHandler {
String backendClassName;
Object backend;
MyInvocationHandler(String className) {
backendClassName = className;
try {
Class clz = loadClass(backendClassName);
b
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
proxy_java_study.zip (15个子文件)
PostmanExample
dynacode
sample
PostmanImpl.java 406B
.project 390B
bin
dynacode
DynaCode$DynaCodeInvocationHandler.class 2KB
Javac.class 3KB
DynaCode.class 6KB
DynaCode$SourceDir.class 2KB
DynaCode$LoadedClass.class 2KB
sample
PostmanApp.class 2KB
Postman.class 151B
run.bat 266B
src
dynacode
DynaCode.java 9KB
Javac.java 3KB
sample
Postman.java 88B
PostmanApp.java 714B
.classpath 301B
共 15 条
- 1
资源评论
- MMLoveMeMM2015-11-19一般般,虽然还算是,但是感觉不怎么通用,还是非常感谢
- VenomSplasher2012-12-26....首先谢谢分享资源,其次没有太理解压缩包中的东西(只看到了java类)
fantaxy025025
- 粉丝: 26
- 资源: 48
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功