当前位置: 代码迷 >> J2EE >> 怎的动态生成类
  详细解决方案

怎的动态生成类

热度:23   发布时间:2016-04-17 23:35:18.0
怎样动态生成类
我看到别人说有三种方法可以动态生成类, 反射时的GeneratedConstructorAccessor和动态代理以及CGLib技术。
请问各位大牛,有谁实现了吗??最好给出源代码。。。
------解决思路----------------------
在比较高层的上面,可以用一些设计模式
在比较低层的上面,可以用一些反射技术
------解决思路----------------------
可以用javassist
------解决思路----------------------
曾经写过的一个例子:


package com.test.dyna;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.List;

import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaFileObject.Kind;

public class DynaCompTest {

public static void main(String[] args) throws InstantiationException,
IllegalAccessExceptionClassNotFoundException {
// TODO Auto-generated method stub

// Full name of the class that will be compiled.
// If class should be in some package,
// fullName should contain it too
// (ex. "testpackage.DynaClass")
String fullName = "com.test.dyna.DynaClass";

// Here we specify the source code of the class to be compiled
StringBuilder src = new StringBuilder();
src.append("package com.test.dyna;\n");
src.append("import com.test.dyna.RecordAccessor;\n");
src.append("public class DynaClass extends RecordAccessor{\n");
src.append("    public String toString() {\n");
src.append("        return \"Hello, I am \" + ");
src.append("this.getClass().getSimpleName();\n");
src.append("    }\n");
src.append("    protected void sayHello() {\n");
src.append("        System.out.println(\"Hello World!!!!\");\n");
src.append("    }\n");
src.append("}\n");

System.out.println(src);

// We get an instance of JavaCompiler. Then
// we create a file manager
// (our custom implementation of it)
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager fileManager = new ClassFileManager(
compiler.getStandardFileManager(null, null, null));

// Dynamic compiling requires specifying
// a list of "files" to compile. In our case
// this is a list containing one "file" which is in our case
// our own implementation (see details below)
List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
jfiles.add(new CharSequenceJavaFileObject(fullName, src));

// We specify a task to the compiler. Compiler should use our file
// manager and our list of "files".
// Then we run the compilation with call()
compiler.getTask(null, fileManager, null, null, null, jfiles).call();

// Creating an instance of our compiled class and
// running its toString() method
Object instance = fileManager.getClassLoader(null).loadClass(fullName)
.newInstance();
System.out.println(instance);

RecordAccessor rd = (RecordAccessor) instance;
rd.sayHello();

}
}

class ClassFileManager extends ForwardingJavaFileManager {
/**
 * Instance of JavaClassObject that will store the compiled bytecode of our
 * class
 */
private JavaClassObject jclassObject;

/**
 * Will initialize the manager with the specified standard java file manager
 * 
 * @param standardManger
 */
public ClassFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
}

/**
 * Will be used by us to get the class loader for our compiled class. It
 * creates an anonymous class extending the SecureClassLoader which uses the
 * byte code created by the compiler and stored in the JavaClassObject, and
 * returns the Class for it
 */
@Override
public ClassLoader getClassLoader(Location location) {
return new SecureClassLoader() {
@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
byte[] b = jclassObject.getBytes();
return super.defineClass(name, jclassObject.getBytes(), 0,
b.length);
}
};
}

/**
 * Gives the compiler an instance of the JavaClassObject so that the
 * compiler can write the byte code into it.
 */
@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling) throws IOException {
jclassObject = new JavaClassObject(className, kind);
return jclassObject;
}
}

class CharSequenceJavaFileObject extends SimpleJavaFileObject {

/**
 * CharSequence representing the source code to be compiled
 */
private CharSequence content;

/**
 * This constructor will store the source code in the internal "content"
 * variable and register it as a source code, using a URI containing the
 * class full name
 * 
 * @param className
 *            name of the public class in the source code
 * @param content
 *            source code to compile
 */
public CharSequenceJavaFileObject(String className, CharSequence content) {
super(URI.create("string:///" + className.replace('.', '/')
+ Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}

/**
 * Answers the CharSequence to be compiled. It will give the source code
 * stored in variable "content"
 */
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return content;
}
}

class JavaClassObject extends SimpleJavaFileObject {

/**
 * Byte code created by the compiler will be stored in this
 * ByteArrayOutputStream so that we can later get the byte array out of it
 * and put it in the memory as an instance of our class.
 */
protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();

/**
 * Registers the compiled class object under URI containing the class full
 * name
 * 
 * @param name
 *            Full name of the compiled class
 * @param kind
 *            Kind of the data. It will be CLASS in our case
 */
public JavaClassObject(String name, Kind kind) {
super(
URI.create("string:///" + name.replace('.', '/')
+ kind.extension), kind);
}

/**
 * Will be used by our file manager to get the byte code that can be put
 * into memory to instantiate our class
 * 
 * @return compiled byte code
 */
public byte[] getBytes() {
return bos.toByteArray();
}

/**
 * Will provide the compiler with an output stream that leads to our byte
 * array. This way the compiler will write everything into the byte array
 * that we will instantiate later
 */
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
  相关解决方案