构建施耐德楼控系统数据库后台服务器示例工程五(JAVA动态生成类)

在做数据库简易工具的过程中遇到了这么一个问题,即程序部署在tomcat下启动运行后,我们无法事先定义数据库中后续创建的表结构的Hibernate Bean对象,这样就需要我们在服务器运行起来后动态创建bean对象。cglib这个开源库即可解决我们的问题,动态创建JAVA对象。

1.cglib开源库简介

CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

反编译后CGLIB结构如下:

其中:

? net.sf.cglib.core

底层字节码处理类,他们大部分与ASM有关系。

? net.sf.cglib.transform

编译期或运行期类和类文件的转换

? net.sf.cglib.proxy

实现创建代理和方法拦截器的类

? net.sf.cglib.reflect

实现快速反射和C#风格代理的类

? net.sf.cglib.util

集合排序工具类

? net.sf.cglib.beans

JavaBean相关的工具类

2.在动态生成类对象中,CGLIB使用代码如下:

1)动态生成类对象操作类

package szx.core.util.sub;

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 DynamicBean {

    private Object object = null;// 动态生成的类
    private BeanMap beanMap = null;// 存放属性名称以及属性的类型

    public DynamicBean() {
        super();
    }

    @SuppressWarnings("rawtypes")
    public DynamicBean(Map propertyMap) {
        this.object = generateBean(propertyMap);
        this.beanMap = BeanMap.create(this.object);
    }

    /**
     * 给bean属性赋值
     * @param property 属性名
     * @param value
     *            值
     */
    public void setValue(Object property, Object value) {
        beanMap.put(property, value);
    }

    /**
     * 通过属性名得到属性值
     * @param property 属性名
     * @return 值
     */
    public Object getValue(String property) {
        return beanMap.get(property);
    }

    /**
     * 得到该实体bean对象
     * @return
     */
    public Object getObject() {
        return this.object;
    }

    /**
     * @param propertyMap
     * @return
     */
    @SuppressWarnings("rawtypes")
    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();
    }

}

2)生成DynamicBean类

    public List<Object> executeSQLGetColumAndValue(String sql)
    {
        Map<String, Class> columnMap = new HashMap<String, Class>();
        DynamicBean beanUtil = null;
        Object ob = null;

        Connection conn = null;
        ResultSet rs = null;
        ResultSetMetaData rsm = null;
        List<Object> list = null;
        try {
            conn = SessionFactoryUtils.getDataSource(super.getSessionFactory()).getConnection();
            rsm = conn.prepareStatement(sql).executeQuery().getMetaData();
            for(int i = 1; i <= rsm.getColumnCount(); i++)
            {
                columnMap.put(rsm.getColumnName(i), Class.forName(rsm.getColumnClassName(i)));
//              System.out.println("colName:"+rsm.getColumnName(i).toString()
//                      +",colNameValue"+rsm.getColumnClassName(i).toString());
            }
            ob = new DynamicBean(columnMap).getObject();

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

            list = new LinkedList<Object>();
            Class cls = ob.getClass();
            Field[] fields = cls.getDeclaredFields();
            while(rs.next())
            {
                Object tmp = 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(tmp, rs.getObject(fieldName));

                    //System.out.println("fieldName:"+fieldName+",setMethodName:"+setMethodName+",\nsetMethod:"+setMethod);
                }

                list.add(tmp);
            }

            return list;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            try {

            } catch (Exception ex) {
            }
            try {
                conn.close();
            } catch (Exception ex) {
            }
        }

    }

上面的示例功能是:从数据库中读取表数据,将读取来的值赋予动态创建的对象中。

上述使用CGLIB的核心代码如下:

Map<String, Class> columnMap = new HashMap<String, Class>();
DynamicBean beanUtil = null;
Object ob = null;

.......

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

.......

ob = new DynamicBean(columnMap).getObject();
Class cls = ob.getClass();
Field[] fields = cls.getDeclaredFields();
while(rs.next())
{
    Object tmp = 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(tmp, rs.getObject(fieldName));
    }

    list.add(tmp);
}

3)从新生成的DynamicBean对象中读取属性及属性值

JSONObject jsonObject = new JSONObject();

Class valueClz = value.getClass();
//System.out.println("valueClz:"+valueClz);
if(valueClz.toString().contains("BeanGeneratorByCGLIB"))
{
    Field fields[] = value.getClass().getDeclaredFields();// 获得对象所有属性

    for (int j = 0; j < fields.length; j++) {
        Field field = fields[j];
        field.setAccessible(true);// 修改访问权限
        String propertyName = fields[j].getName().replace("$cglib_prop_", "");;
        jsonObject.put(propertyName, Object2JSONObject(field.get(value)));
        //System.out.println(propertyName + ":" + field.get(value));
    }
}                

上述判断Class类名是否包含”BeanGeneratorByCGLIB“这个字符串,仅是用于生成JSON串的工具类JSONUtil判断当前的对象是CGLIB创建的对象。

上面的获取对象的属性和值使用的是JAVA的反射机制。

3.CGLIB生成的类输出

动态的生成类名:class net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$5fb90c30
属性名:$cglib_prop_AlarmTypeText,值:NORMAL
属性名:$cglib_prop_rownumber,值:1
属性名:$cglib_prop_AlarmTypeId,值:0

....................................

生成的JSON串:
{"ack": {
    "items": [
        {
            "AlarmTypeText": "NORMAL",
            "rownumber": 1,
            "AlarmTypeId": 0
        }
    ],
    "totalNum": 1
}}

4.其他

1)在Hibernate的OR Mapping、Spring的AOP都使用到了CGLIB完成其功能。

2)CGLIB处理动态生成类外,还可以完成这种动态代理,即代理没有实现接口的继承的类,可以使用CGLIB包。因为JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,就需要使用CGLIB包。

3)CGLIB底层采用的是ASM去实现的,ASM是一个JAVA字节码操纵框架,深入了解需要首先立即JAVA虚拟机JVM的原理。

上述三点需要逐一学习,本篇就不详细介绍了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 07:46:31

构建施耐德楼控系统数据库后台服务器示例工程五(JAVA动态生成类)的相关文章

构建施耐德楼控系统数据库后台服务器示例工程二(数据库查询编写)

构建施耐德楼控系统数据库后台服务器示例工程-(工程创建)记录了一个Spring.Hibernate.Rest的工程如何创建,这篇将简单介绍在这个框架下如何利用注释编程. 1.Spring注释 Spring为我们提供了@Service.@Autowired这些标注来让工程中的Bean自动创建. 在我们的框架中,我们需要为每一个需要被其他类调用到的类名前添加@Service标签,在需要被自动创建的成员类上添加@Autowired,这样程序在运行时Spring会为我们自动装配相关的类实例. 2.Res

构建施耐德楼控系统数据库后台服务器示例工程—(工程创建)

工作中需要在施耐德楼控系统上添加后台管理功能和手机控制功能,单位采购的施耐德的产品仅仅是用于控制现场设备的楼控模块及上位机编程与HMI,我们需要在此基础上,自主开发手机端控制功能,那么就需要通过建立后台工程用于往施耐德的硬件上发信号或者修改其数据库. 本文即是建立在此想法的基础上,记录一下如何采用Spring.Hibernate.Rest这个框架构建一个可以快速开发的后台管理框架. 1.使用eclipse新建一个普通JAVA工程 2.右键工程名,选择属性,点击"Project Facets&qu

构建施耐德楼控系统数据库后台服务器示例工程三(Web端展示)

最近看到Extjs的示例中有仿操作系统桌面的代码,并且展示效果很美观,结合楼控这个系统的Web端展示需求,目前前端采用Extjs.楼控相关的操作会设计成桌面中的不同应用. Extjs初次入手看起来很复杂,但是由于其自带的示例代码很丰富,通常在了解一些基本概念后,参照着示例代码一步一步去做,我认为是最好的学习方式了. 目前我参照着Extjs中仿照桌面的示例代码,做出了如下的画面: 从图中我们可以看出,我目前在仿照着这个示例代码中的GridPanel.TabPanel.Window这些基本的组件,做

构建施耐德楼控系统数据库后台服务器示例工程四(SQLServer查询语句)

由于目前做的是一个数据库操作的一个简易类,涉及到如下查询语句,在此记录一下. 1.查询表名 select object_id,name name from sys.tables 2.查询列信息 SELECT (case when a.colorder = 1 then d.name else null end) 表名, a.colorder 字段序号, a.name 字段名, (case when COLUMNPROPERTY(a.id, a.name, 'IsIdentity') = 1 th

【Mysql】Java中对Mysql数据库的增删改查、Java的System类

这部分也是所谓JDBC.网站数据源的内容,把名字弄得很高深似得,实际上只是Java中对Mysql数据库的增删改查的内容.非常简单,之前写了这么多Mysql的内容,没好好总结一下,实在是不应该.今天就实现一个Java中对Mysql数据库的增删改查,随便带点Java取出当前系统的系统名与系统时间的知识,完成一个还算有点意思的小例子. 一.基本目标 首先,在Mysql数据库中有一张名为testtable的空表,id为自增列,username,class都是文本列,但是class里面都存放数字,也就是整

分布式数据库HBase安装与使用(shell+Java API)

本指南介绍了HBase,详细指导大家安装配置HBase及其使用.本教程在Ubuntu14.04下测试通过. 一.HBase介绍 HBase是一个分布式的.面向列的开源数据库,源于Google的一篇论文<BigTable:一个结构化数据的分布式存储系统>.HBase以表的形式存储数据,表有行和列组成,列划分为若干个列族/列簇(column family).欲了解HBase的官方资讯,请访问HBase官方网站. HBase的运行有三种模式:单机模式.伪分布式模式.分布式模式. 单机模式:在一台计算

火力发电厂工控系统网络安全解决方案 - 对比分析

发电厂网络概述 火电厂网络架构中涉及的系统主要包括:火电机组分散控制系统DCS.火电机组辅机控制系统DCS\PLC.火电厂级信息监控系统.调速系统和自动发电控制功能AGC.励磁系统和自动电压控制功能AVC.梯级调度监控系统.网控系统.继电保护.故障录波.电能量采集装置.电力市场报价终端等系统. 电力行业在安全方面是考虑地比较早的,形成了"安全分区.网络专用.横向隔离.纵向认证"的总体原则. 区域一般分为:生产控制大区(控制区+非控制区),管理信息大区. 也有情况下,电厂会将区域分为4个

业务系统数据库设计常见的隔离和共享模式

多年开发和维护某些业务系统的经验,让人真正理解了什么叫“数据库设计良好,系统就成功了一半”,尤其是那些面向多商户的基础服务平台.公共服务平台.开放服务平台.或者由它们组合而成的综合服务平台.数据库设计之初,必须对业务系统DB的隔离和共享模式的优缺有充分的调研,平衡好业务系统的边界,合理设计使用必要的冗余,以适应系统后续的不断变化,否则后期开发人员将陷入无尽的烦恼和痛苦之中,这绝不是危言耸听,只有开发和维护过平台类产品的人才能深刻体会.下面就介绍三种业务系统中最常见的数据库设计的隔离和共享模式:

java小系统 数据库 图书馆

图书管理系统                          目录 第一章 研究前提................................................................................1 第二章 系统分析................................................................................3 第三章 数据库分析..........................