动态生成java类_使用Cglib动态创建Java类,解决你意想不到的问题,让复杂变简单...

在日常Java数据库开发中我们很少会用到自动创建Java类及类中的变量和方法,目前最常见的第三方数据库操作框架基本都要手动创建一个和数据库表一模一样的javabean,并提供每个字段对于的set,get方法,鉴于这种方式能否用一种方法只要一个数据库表名称,就可以返回一个对应该表的javabean的List列表或者其他集合,而完全不用创建一系列的Javabean呢? 答案是有,Java本身自带的类库目前好像还没有类似的功能,但是开源组织开发出一个jar包,就是cglib,目前的版本已经到cglib-nodep-2.1_3.jar,其底层采用asm动态创建字节码,对外只提供了很少的几个方法,而且也没有相应的API文档。所以学习起来比较难以下手。

下面我简单的介绍下如何使用cglib动态创建类。(例子是参考网上的)

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

packagecom.javase.util;

importjava.util.Iterator;

importjava.util.Map;

importjava.util.Set;

importnet.sf.cglib.beans.BeanGenerator;

importnet.sf.cglib.beans.BeanMap;

publicclassCglibBeanUtil{

publicObjectobject=null;

/**

* 属性map

*/

publicBeanMapbeanMap=null;

publicCglibBeanUtil(){

super();

}

@SuppressWarnings("unchecked")

publicCglibBeanUtil(MappropertyMap){

this.object=generateBean(propertyMap);

this.beanMap=BeanMap.create(this.object);

}

/**

* 给bean属性赋值

*

* @param property

*            属性名

* @param value

*            值

*/

publicvoidsetValue(Stringproperty,Objectvalue){

beanMap.put(property,value);

}

/**

* 通过属性名得到属性值

*

* @param property

*            属性名

* @return 值

*/

publicObjectgetValue(Stringproperty){

returnbeanMap.get(property);

}

/**

* 得到该实体bean对象

*

* @return

*/

publicObjectgetObject(){

returnthis.object;

}

@SuppressWarnings("unchecked")

privateObjectgenerateBean(MappropertyMap){

BeanGeneratorgenerator=newBeanGenerator();

SetkeySet=propertyMap.keySet();

for(Iteratori=keySet.iterator();i.hasNext();){

Stringkey=(String)i.next();

generator.addProperty(key,(Class)propertyMap.get(key));

}

returngenerator.create();

}

}

//-----------------------------------------------------------------------------------------------------

//下面是测试类

packagecom.cglib.test;

importjava.lang.reflect.Method;

importjava.util.HashMap;

importcom.cglib.util.CglibBeanUtil;

publicclassCglibTest{

@SuppressWarnings("unchecked")

publicstaticvoidmain(String[]args)throwsClassNotFoundException{

// 设置类成员属性

HashMappropertyMap=newHashMap();

propertyMap.put("id",Class.forName("java.lang.Integer"));

propertyMap.put("name",Class.forName("java.lang.String"));

propertyMap.put("address",Class.forName("java.lang.String"));

// 生成动态 Bean

CglibBeanUtilbean=newCglibBeanUtil(propertyMap);

// 给 Bean 设置值

bean.setValue("id",newInteger(123));

bean.setValue("name","454");

bean.setValue("address","789");

// 从 Bean 中获取值,当然了获得值的类型是 Object

System.out.println(" >> id = "+bean.getValue("id"));

System.out.println(" >> name = "+bean.getValue("name"));

System.out.println(" >> address = "+bean.getValue("address"));

// 获得bean的实体

Objectobject=bean.getObject();

// 通过反射查看所有方法名

Classclazz=object.getClass();

System.out.println(clazz.getSimpleName());

Method[]methods=clazz.getDeclaredMethods();

for(inti=0;i

System.out.println(methods[i].getName());

}

}

}

通过以上例子我们可以发现,只要提供一个Map型的属性键值对(键是变量名,值是变量的类型),就可以创建出对应的类的所以字段(注意,cglib在给创建的字段前面都有前缀“$cglib_prop_”,使用时要注意,而类名是$cglib开头的如“net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$b5c0bff6”,这个类是唯一的),并自动提供了每个字段的set,get方法。并且该类是生成在内存中,并没有生成在本地。

现在我们要做一种用底层jdbc操作数据只需根据表名返回的List型的集合,完全不用手动创建Javabean。

思路是:

1:创建一个数据库连接工具类DBUtil

2:定义一个接口:ObjectDao,该接口包含方法

List getObjectList(Connection conn, String tableName);//通过表名和前台传的连接返回对象

//如果是一个完整的项目,一般数据库连接是固定的不会每次都是一个新的数据库连接。所以上面方法中的连接可以根据实际情况省掉,而只需一个全局的连接。

现在有个问题是,通过jdbc获取到该表的数据后,如果动态的将不同的表的字段和值能组装成一个类实例并放入List中,那么只能有一种方法那就是反射。要用反射那么我们就要用Class,所以上面接口的方法看着不能满足,

所以我们在上面接口再定义个方法

List getObjectList(Connection conn, Object ob, String tableName); //和上面的方法一样,只是剥离开重新调用了下

我们最终目的是用jdbc查询后返回的ResultSet和Class来组装成一个List,所以单独定义一个工具类

GenerateUtil,其中有个方法public static List generateObjectListFromDB(Class cls, ResultSet rs),这样在接口的实现类中最终调用这个工具类的方法就可以返回我们所要的集合了。

3:下面就要实现这个接口:ObjectDaoImpl

下面直接贴上代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

packagecom.javase.dao.impl;

importjava.lang.reflect.Field;

importjava.lang.reflect.Method;

importjava.sql.Connection;

importjava.sql.ResultSet;

importjava.sql.ResultSetMetaData;

importjava.sql.SQLException;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

importcom.javase.dao.ObjectDao;

importcom.javase.db.DBUtil;

importcom.javase.util.CglibBeanUtil;

importcom.javase.util.GenerateUtil;

publicclassObjectDaoImplimplementsObjectDao

{

@Override

publicListgetObjectList(Connectionconn,StringtableName)

{

MapcolumnMap=newHashMap();

CglibBeanUtilbeanUtil=null;

Stringsql="select * from "+tableName;

Objectob=null;

try

{

ResultSetMetaDatars=conn.prepareStatement(sql).executeQuery().getMetaData();

for(inti=1;i<=rs.getColumnCount();i++)

{

columnMap.put(rs.getColumnName(i),Class.forName(rs.getColumnClassName(i)));

}

ob=newCglibBeanUtil(columnMap).getObject();

}catch(SQLExceptione)

{

e.printStackTrace();

}catch(ClassNotFoundExceptione)

{

e.printStackTrace();

}

returnthis.getObjectList(conn,ob,tableName);

}

publicListgetObjectList(Connectionconn,Objectob,StringtableName)

{

Stringsql="select * from "+tableName;

ResultSetrs=null;

Listlist=null;

try

{

rs=conn.prepareStatement(sql).executeQuery();

list=GenerateUtil.generateObjectListFromDB(ob.getClass(),rs);

}catch(SQLExceptione)

{

e.printStackTrace();

}finally

{

DBUtil.closeConnection(conn);

}

returnlist;

}

}

其中调用的工具生成类有2个,一个是CglibBeanUtil,和最上面的cglib例子一样,

另一个工具类是GenerateUtil

代码为:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

packagecom.javase.util;

importjava.lang.reflect.Field;

importjava.lang.reflect.Method;

importjava.sql.ResultSet;

importjava.util.LinkedList;

importjava.util.List;

publicclassGenerateUtil

{

publicstaticListgenerateObjectListFromDB(Classcls,ResultSetrs)

{

System.out.println(cls.getName());

Listlist=newLinkedList();

Field[]fields=cls.getDeclaredFields();

try

{

while(rs.next())

{

Objectob=cls.newInstance();

for(inti=0;i

{

StringfieldName=fields[i].getName().replace("$cglib_prop_","");

StringsetMethodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);

MethodsetMethod=cls.getDeclaredMethod(setMethodName,newClass[]{fields[i].getType()});

setMethod.invoke(ob,rs.getObject(fieldName));

}

list.add(ob);

}

}catch(Exceptione)

{

e.printStackTrace();

}

returnlist;

}

}

所以我们对外提供的方法就是ObjectDaoImpl类的 getObjectList(Connection conn, String tableName),其中的数据库连接可以根据自己需要删掉换成全局的,再往外还可以包装对应的业务层Service及其ServiceImpl,完全根据自己实际需要。

最后我们用一个测试类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

packagecom.javase.dao;

importjava.sql.Connection;

importjava.util.List;

importcom.javase.dao.impl.ObjectDaoImpl;

importcom.javase.db.DBUtil;

publicclasstest

{

publicstaticvoidmain(String[]args)

{

Connectionconn=DBUtil.getConnection('O',"138.138.2.103",1522,"SJPT","TPS","SJPTTPS");

ObjectDaoImplodi=newObjectDaoImpl();

Listlist=odi.getObjectList(conn,"TP_CD00101");

System.out.println(list.size());

}

}

运行后完全正常

还有点是对事务的支持我没做,还有就是获得List后如何使用也没写,既然在daoImpl类中可以得到Class,那么再定义一个获取对于的Class的工具类,构造一个公共的方法获取List中对象的数据的方法即可,在这里我简单提下,方法参数就为(List list, Class class),在其中运用反射即可获取所有数据,这个由各位自己完成。

cglib的实例运用就说到这,谢谢

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java.lang.NoClassDefFoundError是Java中的一个错误,表示在运行时找不到某个的定义。这个错误通常发生在编译时存在某个的引用,但在运行时找不到该的情况下。而net.sf.cglib.beans.BeanMap是一个,它是CGLIB库中的一部分,用于生成和操作JavaBean的映射。 解决java.lang.NoClassDefFoundError错误的方法有以下几种: 1. 检查路径:确保所需的文件存在于正确的位置,并且可以被Java虚拟机找到。可以通过检查路径设置、JAR文件是否正确导入等方式来解决问题。 2. 检查依赖关系:如果出现NoClassDefFoundError错误,可能是由于缺少依赖库或版本不匹配导致的。请确保所需的依赖库已正确导入,并且版本与代码兼容。 3. 检查编译环境:如果在编译时存在某个的引用,但在运行时找不到该,可能是由于编译环境与运行环境不一致导致的。请确保编译和运行环境一致,并且使用相同的依赖库版本。 4. 检查加载器:如果使用自定义加载器加载,可能会导致NoClassDefFoundError错误。请确保自定义加载器正确加载所需的。 关于net.sf.cglib.beans.BeanMap,它是CGLIB库中的一个,用于生成和操作JavaBean的映射。它提供了一种动态生成JavaBean映射的方式,可以方便地访问和操作JavaBean的属性。如果在使用EasyExcel时遇到了Could not initialize class net.sf.cglib.beans.BeanMap$Generator问题,可能是由于缺少CGLIB库或版本不匹配导致的。请确保正确导入CGLIB库,并且版本与EasyExcel兼容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值