读书人

java动态署理总结(狗星例子)

发布时间: 2012-12-19 14:13:14 作者: rapoo

java动态代理总结(狗星例子)

本文省略了异常

1.生成对象:

Process process = getObjectAsClassName("test.Process");

// 根据classname来生成对象public static <U extends IProcess> U getObjectAsClassName(String className) {U proess = null;proess = (U) Class.forName(className).newInstance();return proess;}

?2、通过方法名执行方法:

Process process = getObjectAsClassName("test.Process");
callMehod("process", process);

?

// 根据method方法名执行方法public static void callMehod(String methodName, Process p) {Method[] methods = Process.class.getMethods();//Method[] methods = Class.forName("com.Process").getMethods();for (Method method : methods) {if (method.getName().equals(methodName)) {// 找到方法,执行method.invoke(p, new Object[] {});}}

?method.invoke():

第一个参数是对象,第二个参数是参数列表

?

3、基于接口的JDK动态代理:

??? ??? IProcess processxy = getProxyProcess(process);
??? ??? processxy.process();

//创建代理对象@SuppressWarnings("unchecked")public static <U extends IProcess> U getProxyProcess(Object process) {ProcessProxy pp = new ProcessProxy(process);return (U) Proxy.newProxyInstance(Process.class.getClassLoader(),Process.class.getInterfaces(), pp);}

Proxy.newProxyInstance:

第一个参数是代理类的ClassLoader ,第二个参数是Interfaces,第三个是InvocationHandler对象


?ProcessProxy.java:

public class ProcessProxy implements InvocationHandler {private Object targs;public ProcessProxy(Object targs) {this.targs = targs;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("被代理对象执行前");Object ret = method.invoke(targs, args);System.out.println("被代理对象执行后");return ret;}}

4、动态生成java文件并编译为class文件执行

// 生成动态类//运行时动态生成文本的.java文件,调用java编译工具类编译成.class二进制文件,就像web服务器将jsp编译成servlet一样 @SuppressWarnings("unchecked")public static IProcess makeDynamicClassObject(IProcess p) {String _package = "package test;\r\n";String classDefine = "public class DynamicClass implements IProcess {"+ "\r\n" + "private IProcess p;\r\n" +"public DynamicClass(IProcess p) {\r\n" + "this.p = p;" + "}\r\n" +"public void process() {\r\n"+ "System.out.println(\"动态生成的java类,开始执行\");" + "p.process();\r\n"+ "}" + "}";String javaSourceCode = _package + classDefine;System.out.println("System.getProperty('user.dir'):"+System.getProperty("user.dir"));//获取项目的根路径String fileName = System.getProperty("user.dir")+ "/src/test/DynamicClass.java"; // 设置一个路径File javaFile = new File(fileName);try {// 创建java文件(写入文件)FileWriter outFile = new FileWriter(javaFile);outFile.write(javaSourceCode);outFile.flush();outFile.close();} catch (IOException e) {e.printStackTrace();}// 生成class文件JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//此处需要使用JDK包,而非jre包,因为jre包中无编译器StandardJavaFileManager fileMang = compiler.getStandardFileManager(null, null, Charset.forName("utf-8"));Iterable  units = fileMang.getJavaFileObjects(fileName);CompilationTask t = compiler.getTask(null, fileMang, null, null, null,units);t.call();fileMang.close();javaFile.delete();//执行class文件URL url = new URL("file://" + System.getProperty("user.dir") + "/src/");URLClassLoader uloader = new URLClassLoader(new URL[] { url });Class c = uloader.loadClass("test.DynamicClass");return (IProcess) c.getConstructor(IProcess.class).newInstance(p);return null;}

问题1:JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();出现空指针异常的问题

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();可以获得环境下边的编译器的引用,但为什么我们在debug到这一语句的时候,查看到此函数返回的是一个null值,即没有编译器。。。。

我们知道,jre是java runtime environment,我们在运行java程序的时候其实就是调用jre里面的java.exe或者javaw.exe,我们安装jdk1.6的时候,会在安装包java下发现jdk1.6和jre1.6两个文件夹,在jdk1.6下有一个jre包,包里的内容和jre1.6文件夹下的内容是一样的。这是因为我们在开发程序的时候需要用到jre,所以jdk1.6.0_07下有一个jre包,但只运行java程序的时候,只会用到jre1.6.0_07下的命令。

弄清楚这一点,问题就好说了,我们要获得编译器,可是jre1.6.0_07文件夹下根本没有编译器,所有我们应该使用jdk1.6.0_07文件夹下的jre,在windows=》pereference=》java=>installl jre里面,添加jdk1.6中的jre,并勾选它。这样空指针异常就解决了。。。。

为什么我们用命令行执行相同的程序不会出现那个空指针异常呢,那是因为我们在寻找jre的时候是在优先考虑jdk下的jre的,但eclipse下是指定了jre的,所有我们在命令行下不会出错。。

?

?

读书人网 >编程

热点推荐