如何动态去生成一个bean 我想在配置文件里写一些方法名 然后运行的时候动态去生成bean 不知道能不能做到注意:不是自动生成bean文件内容 然后自动编译 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 没有啊 没实际困难 我只是在思考问题比如一个UserBean 我想在数据库里给User表添加个字段 但是我并不想去修改那个UserBean 我要它动态生成 它里面有哪些set方法或者get方法要根据我的配置文件或者数据库里读出来的内容来生成 或者说就是根据配置文件动态生成一个类 类中有哪些方法及方法内容 都是动态生成的 你的想法很有创意.事实上你的这个想法 正好是用在 struts 的 DynamicActionForm 里面 .它是结合了反射来实现的。你可以去参看 struts的源代码. 通过读取你的配置文件可以或的 类名 方法 及一些参数信息.通过Class c =Class.forName("类名");得到类对象. Object = c.newInstance() ; 可以得到这个类的一个实例.得到方法对象 Method m = c.getMethod("方法名");再通过 m.invoke(o); 就可以调用你的方法了。这只是一个模拟的实现.具体你还得去看struts的源代码. 郁闷了,找到去年的资料,发现用普通的发射机制无法动态增加方法,需要操作字节码才行,楼主看下下面这个方法吧利用sum的tool.jar动态编译java文件,另外可能aspectj或ASM可以在原有对象上面增加方法.下面这个方法来自skyyoung(路人甲)你参考下吧package com.syj;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileWriter;import java.lang.reflect.Method;import java.util.Date;public class MakeTodayClass { Date today = new Date(); String todayMillis = Long.toString(today.getTime()); String todayClass = "z_" + todayMillis; String todaySource = todayClass + ".java"; public static void main(String args[]) { MakeTodayClass mtc = new MakeTodayClass(); mtc.createIt(); if (mtc.compileIt()) { System.out.println("Running " + mtc.todayClass + ":\n\n"); mtc.runIt(); } else System.out.println(mtc.todaySource + " is bad."); } public void createIt() { try { FileWriter aWriter = new FileWriter(todaySource, true); // aWriter.write("package com;"); aWriter.write("public class " + todayClass + "{"); aWriter.write(" public void doit() {"); aWriter.write(" System.out.println(\"" + todayMillis + "\");"); aWriter.write(" }}\n"); aWriter.flush(); aWriter.close(); } catch (Exception e) { e.printStackTrace(); } } public boolean compileIt() { String f = new File(MakeTodayClass.class.getClassLoader().getResource( "").getFile()).getAbsolutePath(); String[] source = { "-d", f, new String(todaySource) }; ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.out.println(com.sun.tools.javac.Main.compile(source)); System.out.println("================" + new String(baos.toByteArray())); return (baos.toString().indexOf("error") == -1); } public void runIt() { try { Class params[] = {}; Object paramsObj[] = {}; Class thisClass = Class.forName(todayClass); Object iClass = thisClass.newInstance(); Method thisMethod = thisClass.getDeclaredMethod("doit", params); thisMethod.invoke(iClass, paramsObj); } catch (Exception e) { e.printStackTrace(); } }} cglib貌似可以不过这个东东没用过,但是spring和hibernate都十分依赖它,利用它动态创建一个子类来实现,进行扩展. 上面的所有通过 invoke调用的方法 都是取的字符串的方法名啊。这个名字在你的配置文件里可以配置啊。 你不是要动态添加吗。在配置文件里再配置一个方法名。就可以了。 不知道你是不是这个意思啊。继续关注。 9楼的代码还没看 先回答你这个问题你的那个意思是已经存在这个类 类中的方法也都已经确定 运行的时候生成这个类的实例 然后通过配置文件去决定要调用哪些方法我的意思是这个类本身并不存在 而是在运行的时候才生成的这个类 这个类里有哪些方法并不确定 最容易想到的办法就是自动生成源代码 然后自动编译这个源代码 来得到或者修改这个类 但是我并不想用这个方法举个具体的例子 比如有个UserBeanclass UserBean{ String name; void setName(String name){ this.name=name; } String getName(){ return name; }}如果我现在想要加个密码 就得修改这个文件重新编译class UserBean{ String name,password; void setName(String name){ this.name=name; } String getName(){ return name; } void setPassword(String password){ this.password=password; } String getPassword(){ return password; }}如果现在有个类 它能根据配置文件读取的内容来生成这个UserBean(现在感觉似乎只有去生成代码 再自动编译了) 或者达到同样功能 而且适用于所有可以使用javabean的场合 就是我想要的了比如可以这样class UserBeanProxy{ HashMap bean;//存放从文件中读取的"name"、"password"等 //…… //读取文件内容 添加到bean中 //…… //原先的setName("CSDN") 变成了setBean("name","CSDN")或者setBean("setName","CSDN") void setBean(String key,String value){ bean.put(key,value); } String getBean(String key){ return bean.get(key); }}这个类是死的 用户表添加字段或者删除删除字段 不需要去修改这个类文件 但是它并不适用于那个UserBean的场合没法取代那个UserBean其实现在就是想要一个或者几个文件配合可以取代原先那个UserBean 以后更改用户属性不需要修改这些文件 cglib 利用 asm 工具动态生成一个带有 set/get 方法的 JavaBean,产生net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$b37f650b 这样的类名如果要添加非 set/get 方法,这个就无能为力了。import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;import net.sf.cglib.beans.BeanGenerator;import net.sf.cglib.beans.BeanMap;public class DynaBeanCglibTest { public static void main(String[] args) throws ClassNotFoundException { System.out.println("Generate JavaBean"); Map properties = new HashMap(); properties.put("id", Class.forName("java.lang.Integer")); properties.put("name", Class.forName("java.lang.String")); properties.put("address", Class.forName("java.lang.String")); Object stu = generateObject(properties); System.out.println("Set values"); setValue(stu, "id", 123); setValue(stu, "name", "454"); setValue(stu, "address", "789"); System.out.println("Get values"); System.out.println(">> " + getValue(stu, "id")); System.out.println(">> " + getValue(stu, "name")); System.out.println(">> " + getValue(stu, "address")); System.out.println("Show all methods"); Method[] methods = stu.getClass().getDeclaredMethods(); for(Method method : methods) { System.out.println(">> " + method.getName()); } System.out.println("Show all properties"); Field[] fields = stu.getClass().getDeclaredFields(); for(Field field : fields) { System.out.println(">> " + field.getName()); } } private static Object generateObject(Map properties) { BeanGenerator generator = new BeanGenerator(); Set keySet = properties.keySet(); for(Iterator i = keySet.iterator(); i.hasNext();) { String key = (String)i.next(); generator.addProperty(key, (Class)properties.get(key)); } return generator.create(); } private static Object getValue(Object obj, String property) { BeanMap beanMap = BeanMap.create(obj); return beanMap.get(property); } private static void setValue(Object obj, String property, Object value) { BeanMap beanMap = BeanMap.create(obj); beanMap.put(property, value); }} 能不能实现动态为一个类添加方法我还不清楚,不过可能性不打,因为java中的对象一旦生成了就拥有了固定的借口,应该是不能改变的,除非你试图去修改JVM,但是Struts中的DynamicActionForm 的实现,并不是动态为DynamicActionForm 添加某个方法,建议你去看看DynamicActionForm 的源代码吧,它其实是把xml文件中配置的属性都存放在一个HashMap中,你配置的属性名字作为key,表单传过来的值作为value,当调用DynamicActionForm 的get方法时候传入你所需要的属性名字才能返回值,绝非你所说的动态生成方法,建议以后不清楚得问题别回答的那么肯定,呵呵。一面误导他人。 局域网(分子网的)主机搜索 增强的for循环 编译出现警告未经检查的类型使用 调试问题 有jsp经验的看看 50分给一人 java连接MySQL的问题 Java中如何将摄像头捕获的图像保存为视频格式? 全局变量和静态变量的区别是什么? JAVA GUI做统计报表。 有关字符编码格式转换的问题?望不吝赐教。 [求助]帮忙测试,这个程序还有什么问题吗? JAVA中连接sqlserver数据库
比如一个UserBean 我想在数据库里给User表添加个字段 但是我并不想去修改那个UserBean 我要它动态生成 它里面有哪些set方法或者get方法要根据我的配置文件或者数据库里读出来的内容来生成
或者说就是根据配置文件动态生成一个类 类中有哪些方法及方法内容 都是动态生成的
事实上你的这个想法 正好是用在 struts 的 DynamicActionForm 里面 .
它是结合了反射来实现的。你可以去参看 struts的源代码.
通过
Class c =Class.forName("类名");
得到类对象. Object = c.newInstance() ; 可以得到这个类的一个实例.
得到方法对象 Method m = c.getMethod("方法名");
再通过 m.invoke(o); 就可以调用你的方法了。
这只是一个模拟的实现.
具体你还得去看struts的源代码.
另外可能aspectj或ASM可以在原有对象上面增加方法.下面这个方法来自skyyoung(路人甲)你参考下吧package com.syj;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Method;
import java.util.Date;public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = "z_" + todayMillis;
String todaySource = todayClass + ".java"; public static void main(String args[]) {
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.todayClass + ":\n\n");
mtc.runIt();
} else
System.out.println(mtc.todaySource + " is bad.");
} public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
// aWriter.write("package com;");
aWriter.write("public class " + todayClass + "{");
aWriter.write(" public void doit() {");
aWriter.write(" System.out.println(\"" + todayMillis + "\");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
} public boolean compileIt() {
String f = new File(MakeTodayClass.class.getClassLoader().getResource(
"").getFile()).getAbsolutePath();
String[] source = { "-d", f, new String(todaySource) };
ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.out.println(com.sun.tools.javac.Main.compile(source));
System.out.println("================" + new String(baos.toByteArray()));
return (baos.toString().indexOf("error") == -1);
} public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("doit", params);
thisMethod.invoke(iClass, paramsObj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
利用它动态创建一个子类来实现,进行扩展.
上面的所有通过 invoke调用的方法 都是取的字符串的方法名啊。
这个名字在你的配置文件里可以配置啊。 你不是要动态添加吗。
在配置文件里再配置一个方法名。就可以了。 不知道你是不是这个意思啊。
继续关注。
9楼的代码还没看 先回答你这个问题你的那个意思是已经存在这个类 类中的方法也都已经确定 运行的时候生成这个类的实例 然后通过配置文件去决定要调用哪些方法我的意思是这个类本身并不存在 而是在运行的时候才生成的这个类 这个类里有哪些方法并不确定 最容易想到的办法就是自动生成源代码 然后自动编译这个源代码 来得到或者修改这个类 但是我并不想用这个方法举个具体的例子 比如有个UserBean
class UserBean{
String name;
void setName(String name){
this.name=name;
}
String getName(){
return name;
}
}如果我现在想要加个密码 就得修改这个文件重新编译
class UserBean{
String name,password;
void setName(String name){
this.name=name;
}
String getName(){
return name;
}
void setPassword(String password){
this.password=password;
}
String getPassword(){
return password;
}
}如果现在有个类 它能根据配置文件读取的内容来生成这个UserBean(现在感觉似乎只有去生成代码 再自动编译了) 或者达到同样功能 而且适用于所有可以使用javabean的场合 就是我想要的了比如可以这样
class UserBeanProxy{
HashMap bean;//存放从文件中读取的"name"、"password"等
//……
//读取文件内容 添加到bean中
//…… //原先的setName("CSDN") 变成了setBean("name","CSDN")或者setBean("setName","CSDN")
void setBean(String key,String value){
bean.put(key,value);
}
String getBean(String key){
return bean.get(key);
}
}
这个类是死的 用户表添加字段或者删除删除字段 不需要去修改这个类文件 但是它并不适用于那个UserBean的场合没法取代那个UserBean
其实现在就是想要一个或者几个文件配合可以取代原先那个UserBean 以后更改用户属性不需要修改这些文件
net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$b37f650b 这样的类名如果要添加非 set/get 方法,这个就无能为力了。import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;public class DynaBeanCglibTest { public static void main(String[] args) throws ClassNotFoundException {
System.out.println("Generate JavaBean");
Map properties = new HashMap();
properties.put("id", Class.forName("java.lang.Integer"));
properties.put("name", Class.forName("java.lang.String"));
properties.put("address", Class.forName("java.lang.String"));
Object stu = generateObject(properties);
System.out.println("Set values");
setValue(stu, "id", 123);
setValue(stu, "name", "454");
setValue(stu, "address", "789"); System.out.println("Get values");
System.out.println(">> " + getValue(stu, "id"));
System.out.println(">> " + getValue(stu, "name"));
System.out.println(">> " + getValue(stu, "address")); System.out.println("Show all methods");
Method[] methods = stu.getClass().getDeclaredMethods();
for(Method method : methods) {
System.out.println(">> " + method.getName());
} System.out.println("Show all properties");
Field[] fields = stu.getClass().getDeclaredFields();
for(Field field : fields) {
System.out.println(">> " + field.getName());
}
} private static Object generateObject(Map properties) {
BeanGenerator generator = new BeanGenerator();
Set keySet = properties.keySet();
for(Iterator i = keySet.iterator(); i.hasNext();) {
String key = (String)i.next();
generator.addProperty(key, (Class)properties.get(key));
}
return generator.create();
} private static Object getValue(Object obj, String property) {
BeanMap beanMap = BeanMap.create(obj);
return beanMap.get(property);
} private static void setValue(Object obj, String property, Object value) {
BeanMap beanMap = BeanMap.create(obj);
beanMap.put(property, value);
}
}
能不能实现动态为一个类添加方法我还不清楚,不过可能性不打,因为java中的对象一旦生成了就拥有了固定的借口,应该是不能改变的,
除非你试图去修改JVM,但是Struts中的DynamicActionForm 的实现,并不是动态为DynamicActionForm 添加某个方法,建议你去看看
DynamicActionForm 的源代码吧,它其实是把xml文件中配置的属性都存放在一个HashMap中,你配置的属性名字作为key,表单传过来的值
作为value,当调用DynamicActionForm 的get方法时候传入你所需要的属性名字才能返回值,绝非你所说的动态生成方法,建议以后不清楚
得问题别回答的那么肯定,呵呵。一面误导他人。