SSM(九) 反射的實(shí)際應(yīng)用 - 構(gòu)建日志對(duì)象

1

前言

相信做Java的童鞋或多或少都聽過反射,這也應(yīng)該是Java從入門到進(jìn)階的必經(jīng)之路。

但是在我們的實(shí)際開發(fā)中直接使用它們的幾率貌似還是比較少的,(除了造輪子或者是Spring Mybatis這些框架外)。

所以這里介紹一個(gè)在實(shí)際開發(fā)中還是小有用處的反射實(shí)例。

傳統(tǒng)日志

有關(guān)反射的一些基本知識(shí)就不說(shuō)了,可以自行Google,也可以看下反射入門。

日志相信大家都不陌生,在實(shí)際開發(fā)中一些比較敏感的數(shù)據(jù)表我們需要對(duì)它的每一次操作都記錄下來(lái)。

先來(lái)看看傳統(tǒng)的寫法:

    @Test
    public void insertSelective() throws Exception {

        Content content = new Content() ;
        content.setContent("asdsf");
        content.setCreatedate("2016-12-09");
        contentService.insertSelective(content) ;

        ContentLog log = new ContentLog();
        log.setContentid(content.getContentid());
        log.setContent("asdsf");
        log.setCreatedate("2016-12-09");
        contentLogService.insertSelective(log);
    }

非常簡(jiǎn)單,就是在保存完數(shù)據(jù)表之后再把相同的數(shù)據(jù)保存到日志表中。

但是這樣有以下幾個(gè)問題:

  • 如果數(shù)據(jù)表的字段較多的話,比如幾百個(gè)。那么日志表的setter()方法就得寫幾百次,還得是都寫對(duì)的情況下。
  • 如果哪天數(shù)據(jù)表的字段發(fā)生了增加,那么每個(gè)寫日志的地方都得增加該字段,提高了維護(hù)的成本。

針對(duì)以上的情況就得需要反射這個(gè)主角來(lái)解決了。

利用反射構(gòu)建日志

我們先來(lái)先來(lái)看下使用反射之后對(duì)代碼所帶來(lái)的改變:

    @Test
    public void insertSelective2() throws Exception {
        Content content = new Content();
        content.setContent("你好");
        content.setContentname("1");
        content.setCreatedate("2016-09-23");

        contentService.insertSelective(content);

        ContentLog log = new ContentLog();
        CommonUtil.setLogValueModelToModel(content, log);
        contentLogService.insertSelective(log);
    }

同樣的保存日志,不管多少字段,只需要三行代碼即可解決。
而且就算之后字段發(fā)生改變寫日志這段代碼仍然不需要改動(dòng)。

其實(shí)這里最主要的一個(gè)方法就是CommonUtil.setLogValueModelToModel(content, log);

來(lái)看下是如何實(shí)現(xiàn)的;

/**
     * 生成日志實(shí)體工具
     *
     * @param objectFrom
     * @param objectTo
     */
    public static void setLogValueModelToModel(Object objectFrom, Object objectTo) {
        Class<? extends Object> clazzFrom = objectFrom.getClass();
        Class<? extends Object> clazzTo = objectTo.getClass();

        for (Method toSetMethod : clazzTo.getMethods()) {
            String mName = toSetMethod.getName();
            if (mName.startsWith("set")) {
                //字段名
                String field = mName.substring(3);

                //獲取from 值
                Object value;
                try {
                    if ("LogId".equals(field)) {
                        continue;
                    }
                    Method fromGetMethod = clazzFrom.getMethod("get" + field);
                    value = fromGetMethod.invoke(objectFrom);

                    //設(shè)置值
                    toSetMethod.invoke(objectTo, value);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

再使用之前我們首先需要構(gòu)建好主的數(shù)據(jù)表,然后new一個(gè)日志表的對(duì)象。

setLogValueModelToModel()方法中:

  • 分別獲得數(shù)據(jù)表和日志表對(duì)象的類類型。
  • 獲取到日志對(duì)象的所有方法集合。
  • 遍歷該集合,并拿到該方法的名稱。
  • 只取其中set開頭的方法,也就是set方法。因?yàn)槲覀冃枰谘h(huán)中為日志對(duì)象的每一個(gè)字段賦值。
  • 之后截取方法名稱獲得具體的字段名稱。
  • 用之前截取的字段名稱,通過getMethod()方法返回?cái)?shù)據(jù)表中的該字段的getter方法。
  • 相當(dāng)于執(zhí)行了String content = content.getContent();
  • 執(zhí)行該方法獲得該字段具體的值。
  • 利用當(dāng)前循環(huán)的setter方法為日志對(duì)象的每一個(gè)字段賦值。
  • 相當(dāng)于執(zhí)行了log.setContent("asdsf");

其中字段名稱為LogId時(shí)跳出了當(dāng)前循環(huán),因?yàn)長(zhǎng)ogId是日志表的主鍵,是不需要賦值的。

當(dāng)循環(huán)結(jié)束時(shí),日志對(duì)象也就構(gòu)建完成了。之后只需要保存到數(shù)據(jù)庫(kù)中即可。

總結(jié)

反射其實(shí)是非常耗資源的,再使用過程中還是要慎用。
其中對(duì)method、field、constructor等對(duì)象做緩存也是很有必要的。

項(xiàng)目地址:https://github.com/crossoverJie/SSM.git

個(gè)人博客地址:http://crossoverjie.top。

GitHub地址:https://github.com/crossoverJie。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容