SSM(九) 反射的實際應用 - 構建日誌對象

前言

相信作Java的童鞋或多或少都聽過反射,這也應該是Java從入門到進階的必經之路。java

可是在咱們的實際開發中直接使用它們的概率貌似仍是比較少的,(除了造輪子或者是Spring Mybatis這些框架外)。git

因此這裏介紹一個在實際開發中仍是小有用處的反射實例。github

傳統日誌

有關反射的一些基本知識就不說了,能夠自行Google,也能夠看下反射入門數據庫

日誌相信你們都不陌生,在實際開發中一些比較敏感的數據表咱們須要對它的每一次操做都記錄下來。緩存

先來看看傳統的寫法:框架

@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);
    }複製代碼

很是簡單,就是在保存完數據表以後再把相同的數據保存到日誌表中。工具

可是這樣有如下幾個問題:spa

  • 若是數據表的字段較多的話,好比幾百個。那麼日誌表的setter()方法就得寫幾百次,還得是都寫對的狀況下。
  • 若是哪天數據表的字段發生了增長,那麼每一個寫日誌的地方都得增長該字段,提升了維護的成本。

針對以上的狀況就得須要反射這個主角來解決了。日誌

利用反射構建日誌

咱們先來先來看下使用反射以後對代碼所帶來的改變:code

@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);
    }複製代碼

一樣的保存日誌,無論多少字段,只須要三行代碼便可解決。
並且就算以後字段發生改變寫日誌這段代碼仍然不須要改動。

其實這裏最主要的一個方法就是CommonUtil.setLogValueModelToModel(content, log);

來看下是如何實現的;

/** * 生成日誌實體工具 * * @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);

                    //設置值
                    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);
                }
            }
        }
    }複製代碼

再使用以前咱們首先須要構建好主的數據表,而後new一個日誌表的對象。

setLogValueModelToModel()方法中:

  • 分別得到數據表和日誌表對象的類類型。
  • 獲取到日誌對象的全部方法集合。
  • 遍歷該集合,並拿到該方法的名稱。
  • 只取其中set開頭的方法,也就是set方法。由於咱們須要在循環中爲日誌對象的每個字段賦值。
  • 以後截取方法名稱得到具體的字段名稱。
  • 用以前截取的字段名稱,經過getMethod()方法返回數據表中的該字段的getter方法。
  • 至關於執行了String content = content.getContent();
  • 執行該方法得到該字段具體的值。
  • 利用當前循環的setter方法爲日誌對象的每個字段賦值。
  • 至關於執行了log.setContent("asdsf");

其中字段名稱爲LogId時跳出了當前循環,由於LogId是日誌表的主鍵,是不須要賦值的。

當循環結束時,日誌對象也就構建完成了。以後只須要保存到數據庫中便可。

總結

反射實際上是很是耗資源的,再使用過程當中仍是要慎用。
其中對method、field、constructor等對象作緩存也是頗有必要的。

項目地址:github.com/crossoverJi…

我的博客地址:crossoverjie.top

GitHub地址:github.com/crossoverJi…

相關文章
相關標籤/搜索