Cglib动态创建Java类_使用Cglib动态创建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

package

com.javase.util;

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

CglibBeanUtil {

public

Object object =

null;

public

BeanMap beanMap =

null;

public

CglibBeanUtil()

{

super();

}

@SuppressWarnings("unchecked")

public

CglibBeanUtil(Map

propertyMap) {

this.object

=

generateBean(propertyMap);

this.beanMap

=

BeanMap.create(this.object);

}

public

void

setValue(String

property, Object

value) {

beanMap.put(property,

value);

}

public

Object

getValue(String

property) {

return

beanMap.get(property);

}

public

Object

getObject()

{

return

this.object;

}

@SuppressWarnings("unchecked")

private

Object

generateBean(Map

propertyMap) {

BeanGenerator

generator = new

BeanGenerator();

Set

keySet =

propertyMap.keySet();

for

(Iterator i =

keySet.iterator();

i.hasNext();)

{

String

key =

(String)

i.next();

generator.addProperty(key,

(Class)

propertyMap.get(key));

}

return

generator.create();

}

}

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

//下面是测试类

package

com.cglib.test;

import

java.lang.reflect.Method;

import

java.util.HashMap;

import

com.cglib.util.CglibBeanUtil;

public class CglibTest

{

@SuppressWarnings("unchecked")

public static void

main(String[]

args) throws

ClassNotFoundException {

// 设置类成员属性

HashMap propertyMap =

new

HashMap();

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

CglibBeanUtil bean =

new

CglibBeanUtil(propertyMap);

// 给 Bean 设置值

bean.setValue("id",

new

Integer(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的实体

Object object =

bean.getObject();

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

Class clazz =

object.getClass();

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

Method[]

methods =

clazz.getDeclaredMethods();

for (int i

= 0; i

<

methods.length;

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,该接口包含方法

ListgetObjectList(Connection conn, String

tableName);//通过表名和前台传的连接返回对象

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

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

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

ListgetObjectList(Connection conn, Object ob, String

tableName); //和上面的方法一样,只是剥离开重新调用了下

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

GenerateUtil,其中有个方法public static

ListgenerateObjectListFromDB(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

package

com.javase.dao.impl;

import

java.lang.reflect.Field;

import

java.lang.reflect.Method;

import

java.sql.Connection;

import

java.sql.ResultSet;

import

java.sql.ResultSetMetaData;

import

java.sql.SQLException;

import

java.util.HashMap;

import

java.util.List;

import

java.util.Map;

import

com.javase.dao.ObjectDao;

import

com.javase.db.DBUtil;

import

com.javase.util.CglibBeanUtil;

import

com.javase.util.GenerateUtil;

public class

ObjectDaoImpl implements

ObjectDao

{

@Override

public

List<Object>

getObjectList(Connection

conn, String

tableName)

{

Map<String,

Class> columnMap

= new

HashMap<String,

Class>();

CglibBeanUtil

beanUtil =

null;

String

sql = "select * from "

+ tableName;

Object

ob =

null;

try

{

ResultSetMetaData

rs =

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

for(int

i = 1;

i <=

rs.getColumnCount();

i++)

{

columnMap.put(rs.getColumnName(i),

Class.forName(rs.getColumnClassName(i)));

}

ob

= new

CglibBeanUtil(columnMap).getObject();

}

catch (SQLException

e)

{

e.printStackTrace();

}

catch

(ClassNotFoundException

e)

{

e.printStackTrace();

}

return

this.getObjectList(conn,

ob,

tableName);

}

public

List<Object>

getObjectList(Connection

conn, Object

ob, String

tableName)

{

String

sql = "select * from "

+ tableName;

ResultSet

rs =

null;

List<Object>

list =

null;

try

{

rs

=

conn.prepareStatement(sql).executeQuery();

list

=

GenerateUtil.generateObjectListFromDB(ob.getClass(),

rs);

}

catch (SQLException

e)

{

e.printStackTrace();

}

finally

{

DBUtil.closeConnection(conn);

}

return

list;

}

}

其中调用的工具生成类有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

package

com.javase.util;

import

java.lang.reflect.Field;

import

java.lang.reflect.Method;

import

java.sql.ResultSet;

import

java.util.LinkedList;

import

java.util.List;

public class

GenerateUtil

{

public

static

List<Object>

generateObjectListFromDB(Class

cls, ResultSet

rs)

{

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

List<Object>

list = new

LinkedList<Object>();

Field[]

fields =

cls.getDeclaredFields();

try

{

while(rs.next())

{

Object

ob =

cls.newInstance();

for(int

i = 0;

i <

fields.length;

i++)

{

String

fieldName =

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

"");

String

setMethodName = "set"

+

fieldName.substring(0,

1).toUpperCase()

+

fieldName.substring(1);

Method

setMethod =

cls.getDeclaredMethod(setMethodName,

new

Class[]{fields[i].getType()});

setMethod.invoke(ob,

rs.getObject(fieldName));

}

list.add(ob);

}

}

catch(Exception

e)

{

e.printStackTrace();

}

return

list;

}

}

所以我们对外提供的方法就是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

package

com.javase.dao;

import

java.sql.Connection;

import

java.util.List;

import

com.javase.dao.impl.ObjectDaoImpl;

import

com.javase.db.DBUtil;

public class test

{

public

static void

main(String[]

args)

{

Connection

conn =

DBUtil.getConnection('O',

"138.138.2.103",

1522, "SJPT",

"TPS",

"SJPTTPS");

ObjectDaoImpl

odi = new

ObjectDaoImpl();

List<Object>

list =

odi.getObjectList(conn,

"TP_CD00101");

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

}

}

运行后完全正常

还有点是对事务的支持我没做,还有就是获得List后如何使用也没写,既然在daoImpl类中可以得到Class,那么再定义一个获取对于的Class的工具类,构造一个公共的方法获取List中对象的数据的方法即可,在这里我简单提下,方法参数就为(Listlist,

Class class),在其中运用反射即可获取所有数据,这个由各位自己完成。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值