<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          因為造輪子,我一個月就轉(zhuǎn)正了

          共 16413字,需瀏覽 33分鐘

           ·

          2022-04-28 21:57

          往期熱門文章:

          1、用了Stream后,代碼反而越寫越丑?
          2、一不小心節(jié)約了 591 臺機器!
          3、你見過哪些目瞪口呆的 Java 代碼技巧?
          4、笑死!程序員延壽指南開源了
          5、互聯(lián)網(wǎng)黑話,被上海人翻譯火了

          作者 |?Baldwin_KeepMind

          責(zé)編 | 伍杏玲

          出品 | CSDN博客


          2019年6月,我通過社招入職現(xiàn)在所工作的公司,理論上應(yīng)該有三個月時間的試用期,只有試用期表現(xiàn)良好我才有機會轉(zhuǎn)正,但因為一次優(yōu)化代碼過程中造了一個輪子,我獲得了一個月轉(zhuǎn)正的機會。
          我是一個懶人,又特別喜歡琢磨,在工作的過程中我發(fā)現(xiàn)有一個模塊運行非常的慢,主要原因是在這個模塊種需要大量的進行數(shù)據(jù)庫操作,而目前公司業(yè)務(wù)擴大,在數(shù)據(jù)庫中已經(jīng)有上億條數(shù)據(jù),每次對這個表進行操作,都需要花費將近3S的時間,而實際上,整個流程走下來,程序也就花費4S的時間,所以我就特別想把這段代碼優(yōu)化一下,將代碼的耗時降低下來,經(jīng)過一個星期的努力,輪子的初版發(fā)布,同事們用完之后都覺得不錯,然后老大就給我遞交了提前轉(zhuǎn)正申請,我工作一個月就順利轉(zhuǎn)正了。
          現(xiàn)在將我當時造輪子的主要思路在這里寫下來,希望能給你一點啟發(fā)。

          輪子相關(guān)

          首先,我們現(xiàn)在所說的輪子可不是汽車上的輪子,之所以叫“輪子”,是為了更好的理解。
          汽車輪子是圓的,這種圓形輪子已經(jīng)被各界廣泛認可是比較好的結(jié)構(gòu),我們無論怎么去做,也很難超越“圓輪子”,所以我們只能在“圓輪子”的基礎(chǔ)上去<重復(fù)發(fā)明輪子>,即是所說的造輪子。但是有一句話叫做“不要重復(fù)造輪子”,因為無論我們怎么努力,也很難去超越以前已經(jīng)有的輪子,那我們?yōu)槭裁催€要去造輪子呢?
          1.只有我們自己才懂得我們的需求,你在編程中無論用什么框架,總覺得跟業(yè)務(wù)不是很契合,甚至有時候框架很臃腫,但是因為要用到其中一個內(nèi)容而不得不導(dǎo)入一個很大的框架。
          2.已有的框架太復(fù)雜,我們完全沒法掌握他的所有內(nèi)容,出了bug后一頭霧水解決不了問題。
          3.公司要求,不可使用第三方框架(多見于數(shù)據(jù)保密的公司),但是程序中要反復(fù)使用某一組件功能。
          4.找不到合適的輪子。
          5.想裝B。
          如果遇到以上問題,或許自己造輪子才是一個好辦法。
          前期準備

          本文所講的,可能只是造輪子最基礎(chǔ)的教程了,所以知識儲備方面要求的不是很全面,如果有大佬看到這篇文章,請輕點噴,我絕對虛心接受批評。
          2.1.基礎(chǔ)知識
          總從上次發(fā)了那篇關(guān)于閱讀源碼的文章,總是有朋友問我“你好,請問我現(xiàn)在剛大一,看不懂源碼怎么辦?”,每每遇到這種問題,我都很絕望,我在那篇文章中所講的內(nèi)容,都是建立在已經(jīng)有一定編程基礎(chǔ)的前提上,如果正在看這篇文章的你沒有接觸過編程,那現(xiàn)在可以先點一下關(guān)注,點贊,收藏,然后回去好好學(xué)習(xí)一下基礎(chǔ)再看這篇文章。
          我們想造一個輪子,最起碼有一定的編程能力,如果要有一個標準,就是能夠獨自搭建一個項目。
          本文中主要運用到的知識點有:注解、反射、多態(tài)。
          2.2.了解源碼
          比如JDK源碼和一些框架的源碼,造輪子在某種層面上來說,就是寫一個框架,我們在沒有基礎(chǔ)的情況下,先看一些大佬寫好的框架源碼是很有幫助的,在我們自己的輪子中,可以模仿他們框架的結(jié)構(gòu)。
          2.3.不怕失敗
          第一次造輪子絕對是一個艱難而又漫長的過程,你會一次次失敗,你需要經(jīng)受住失敗帶來的對你信心和耐心的打擊,如果你無法堅持,還不如不要開始。

          開工

          如果你看到這里,相信你已經(jīng)準備好了,那么現(xiàn)在就開始吧!
          3.1.想好需求
          既然是造輪子,那么總得先想好這個輪子的用途,我們我們假設(shè)一個需求:通過注解實現(xiàn)系統(tǒng)日志輸出到文件。
          具體需求如下:
          1.記錄注解注入的數(shù)據(jù)
          2.日志記錄應(yīng)通過文件保存到系統(tǒng)中,路徑可配置,若無配置則選用默認配置
          3.日志記錄需要添加時間標簽
          4.日志文件名可在注解中設(shè)置
          5.引入隊列傳遞日志MSG
          3.2.創(chuàng)建項目
          為了簡化過程,我們可以直接創(chuàng)建一個Maven項目,在你對底層有更好的理解之后,就可以用更好的架構(gòu)。
          新建一個LogUtil項目,項目架構(gòu)如下:


          因為只是一個簡單的示例,所以有很多的內(nèi)容知識有思想,但是還沒有實現(xiàn)。
          3.2.一些常量
          主要保存在Constants.java文件中:

          public?interface?Constants?{

          ????//等下要引入的配置文件名

          ????String?CONFIG_FILE_NAME?=?"yzlogconfig";

          ????//配置文件中配置的日志路徑

          ????String?CONFIG_LOG_PATH?=?"logpath";

          ????//配置文件中配置的要掃描的,可能存在我們注解的路徑

          ????String?CONFIG_SACN_PATH?=?"scanpath";

          ????//若未聲明某些信息,則使用以下默認值

          ????//默認的我們的日志信息前綴,對日志信息做簡單描述

          ????String?DEFAULT_CONTENT_PREFIX?=?"注入值:";

          ????//默認的日志文件名(實際寫入時會在日志文件名后加上日期標簽)

          ????String?DEFAULT_FILE_NAME?=?"log";

          ????//日志信息類型,處理消息時會用到

          ????String?MSG_TYPE_LOG?=?"log";

          ????//默認的Linux系統(tǒng)下的日志路徑

          ????String?LINUX_LOG_PATH?=?"/home/data/";

          ????//默認的Windows系統(tǒng)下的日志路徑

          ????String?WIN_LOG_PATH?=?"D:/winLog/data/";

          }
          3.3.加載配置

          思想:給予用戶配置權(quán)限。
          框架是拿給別人用的,一定要給予用戶自主配置的權(quán)限,這里要加載的是那些引入我們輪子的項目的配置。
          某個項目在引入我們的輪子的時候,他自己是應(yīng)當有權(quán)限去自己設(shè)置一些東西的,比如我們這里的文件處理路徑,是給了用戶權(quán)限去配置的。
          我們規(guī)定配置文件的文件名為yzlogconfig.xml,等下在代碼中也可以看到這個配置文件名的設(shè)置。
          ConfigurationUtil
          這個工具類主要用來加載配置信息,基礎(chǔ)工具類,這里不再累述。

          import?java.util.ResourceBundle;

          public?class?ConfigurationUtil?{

          ????private?static?Object?lock?=?new?Object();

          ????private?static?ConfigurationUtil?config?=?null;

          ????private?static?ResourceBundle?rb?=?null;

          ????private?ConfigurationUtil(String?filename)?{

          ????????rb?=?ResourceBundle.getBundle(filename);

          ????}

          ????public?static?ConfigurationUtil?getInstance(String?filename)?{

          ????????synchronized?(lock)?{

          ????????????if?(null?==?config)?{

          ????????????????config?=?new?ConfigurationUtil(filename);

          ????????????}

          ????????}

          ????????return?(config);

          ????}

          ????public?String?getValue(String?key)?{

          ????????String?ret?=?"";

          ????????if?(rb.containsKey(key))?{

          ????????????ret?=?rb.getString(key);

          ????????}

          ????????return?ret;

          ????}

          }
          3.4.日志記錄功能實現(xiàn)

          這里算是核心功能的一部分了,需要的工具類有:DateUtil(獲取日期)、SystemUtil(獲取當前系統(tǒng)的類型)、FileUtil(創(chuàng)建日志文件)。
          DataUtil

          import?java.text.SimpleDateFormat;

          import?java.util.Date;

          public?class?DateUtil?{

          ????public?final?static?String?DATE_A?=?"yyyy-MM-dd";

          ????public?final?static?String?DATE_B?=?"yyyy-MM-dd?HH:mm:ss";

          ????public?final?static?String?DATE_C?=?"yyyyMMddHHmmss";

          ????public?final?static?String?DATE_D?=?"yyyyMMdd-HHmmss-SS";

          ????public?final?static?String?DATE_E?=?"M月d日";

          ????public?final?static?String?DATE_F?=?"MM-dd";

          ????public?final?static?String?DATE_G?=?"yyyyMMddHHmmss";

          ????//?普通的當前時間轉(zhuǎn)字符串方法,格式為yyyy-MM-dd

          ????public?static?String?getDate()?{

          ????????SimpleDateFormat?sdf?=?new?SimpleDateFormat(DATE_A);

          ????????return?sdf.format(new?Date());

          ????}



          ????public?static?String?getDateTime()?{

          ????????Date?date?=?new?Date();

          ????????String?datestr;

          ????????SimpleDateFormat?sdf?=?new?SimpleDateFormat(DATE_B);

          ????????datestr?=?sdf.format(date);

          ????????return?datestr;

          ????}

          }
          ?SystemUtil
          /**

          ?*@描述?用于判斷當前系統(tǒng)

          ?*@參數(shù)

          ?*@返回值

          ?*@創(chuàng)建人??Baldwin

          ?*@創(chuàng)建時間??2020/4/4

          ?*@修改人和其它信息

          ?*/


          public?class?SystemUtil?{


          ????/**

          ?????*?判斷系統(tǒng)時win還是linux

          ?????*?@return

          ?????*/


          ????public?static?boolean?isLinux(){

          ????????String?name?=?System.getProperty("os.name");

          ????????if(name.toLowerCase().startsWith("win"))

          ????????????return?false;

          ????????else

          ????????????return?true;

          ????}

          }
          FileUtil
          import?java.io.BufferedWriter;

          import?java.io.File;

          import?java.io.FileOutputStream;

          import?java.io.OutputStreamWriter;


          public?class?FileUtil?{


          ????//?在已經(jīng)存在的文件后面追加寫的方式

          ????public?static?boolean?write(String?path,?String?str)?{

          ????????File?f?=?new?File(path);

          ????????File?fileParent?=?f.getParentFile();

          ????????BufferedWriter?bw?=?null;

          ????????try?{

          ????????????if(!fileParent.exists()){

          ????????????????fileParent.mkdirs();

          ????????????}


          ????????????if(!f.exists()){

          ????????????????f.createNewFile();

          ????????????}

          ????????????//?new?FileWriter(name,true)設(shè)置文件為在尾部添加模式,參數(shù)為false和沒有參數(shù)都代表覆寫方式

          ????????????bw?=?new?BufferedWriter(new?OutputStreamWriter(new?FileOutputStream(path,?true),?"UTF-8"));

          ????????????bw.write(str);

          ????????}?catch?(Exception?e)?{

          ????????????e.printStackTrace();

          ????????????return?false;

          ????????}?finally?{

          ????????????try?{

          ????????????????if(bw!=null)bw.close();

          ????????????}?catch?(Exception?e)?{

          ????????????????System.out.println("FileUtil.write?colse?bw?wrong:"?+?e);

          ????????????}

          ????????}

          ????????return?true;

          ????}

          }
          LogUtil

          思想:默認配置
          很多時候,我們的用戶可能沒有配置需要配置的信息,而且注解中也沒有聲明,那么就要求我們存在默認的配置來填補這些空缺,從而避免由于空配置導(dǎo)致的錯誤。
          在這個類里面,我們主要進行一些日志路徑和內(nèi)容的整理:

          import?cn.yzstu.support.Constants;

          import?cn.yzstu.support.DateUtil;

          import?cn.yzstu.support.FileUtil;

          import?cn.yzstu.support.SystemUtil;


          public?class?LogUtil?{


          ????//日志寫入操作
          ????public?static?void?write2file(String?path,?String?fileName,?String?content)?{


          ????????//獲取當前日期,我們的日志保存的文件夾名是自定義path+日期
          ????????String?date?=?DateUtil.getDate()+"/";

          ????????try?{

          ????????????//傳了path,那我們直接用這個path

          ????????????if?(null?!=?path?&&?0?!=?path.length())?{

          ????????????????//寫入
          ????????????????FileUtil.write(path?+?date?+?fileName?+?".txt",

          ????????????????????????DateUtil.getDateTime()?+?":"?+?content?+?"\r\n");

          ????????????}?else?{

          ????????????????//沒有傳path或錯誤使用默認的路徑

          ????????????????if?(SystemUtil.isLinux())?{

          ????????????????????FileUtil.write(Constants.LINUX_LOG_PATH?+?date?+?fileName?+?".txt",

          ????????????????????????????DateUtil.getDateTime()?+?":"?+?content?+?"\r\n");

          ????????????????}?else?{

          ????????????????????FileUtil.write(Constants.WIN_LOG_PATH?+?date?+?fileName?+?".txt",

          ????????????????????????????DateUtil.getDateTime()?+?":"?+?content?+?"\r\n");
          ????????????????}

          ????????????}

          ????????}?catch?(Exception?e)?{

          ????????????e.printStackTrace();

          ????????}
          ????}
          }
          3.5.日志消息

          我們等一下要把日志消息放到隊列里來處理,這里定義一個日志類的消息類型,方便后續(xù)處理,在本示例中,做了簡化處理,實際上對于隊列消息,我們需要定義一個統(tǒng)一接口,讓所有的消息類型都實現(xiàn)他,這樣如果我們的消息類型很多的時候,就能做一個統(tǒng)一的管理了。
          我們?yōu)榱朔奖闾幚恚跇?gòu)造函數(shù)中就讓這個消息入列了,并且把他的MsgType直接設(shè)置成了logmsg。

          import?cn.yzstu.core.MsgQueue;

          import?cn.yzstu.support.Constants;

          public?class?LogMsg?{

          ????private?String?path;

          ????private?String?content;

          ????private?String?fileName;

          ????private?String?msgType;

          ????public?LogMsg(String?path,?String?content,?String?fileName)?{

          ????????this.path?=?path;

          ????????this.content?=?content;

          ????????this.fileName?=?fileName;

          ????????this.msgType?=?"logmsg";

          ????????//在構(gòu)造函數(shù)中就讓這個消息入列

          ????????MsgQueue.push(this);

          ????}?

          ????public?String?getPath()?{

          ????????return?path;

          ????}

          ????public?void?setPath(String?path)?{

          ????????this.path?=?path;

          ????}

          ????public?String?getContent()?{

          ????????return?content;

          ????}

          ????public?void?setContent(String?content)?{

          ????????this.content?=?content;

          ????}

          ????public?String?getFileName()?{

          ????????return?fileName;

          ????}

          ????public?void?setFileName(String?fileName)?{

          ????????this.fileName?=?fileName;

          ????}

          ????public?String?getMsgType()?{

          ????????return?this.msgType;

          ????}

          ????public?void?setMsgType(String?msgType)?{

          ????????this.msgType?=?msgType;

          ????}

          ????@Override

          ????public?String?toString()?{

          ????????return?"LogMsg{"?+

          ????????????????"path='"?+?path?+?'\''?+

          ????????????????",?content='"?+?content?+?'\''?+

          ????????????????",?fileName='"?+?fileName?+?'\''?+

          ????????????????",?msgType='"?+?msgType?+?'\''?+

          ????????????????'}';

          ????}

          }
          3.6.定義隊列

          實際情況中,我們的隊列里面會存在很多中類型的消息,在本示例中只存在logmsg。

          import?cn.yzstu.beans.LogMsg;

          import?java.util.Queue;

          import?java.util.concurrent.ConcurrentLinkedDeque;

          public?class?MsgQueue?{

          ????private?static?Queue?queue?=?new?ConcurrentLinkedDeque<>();

          ????//消息入列

          ????public?static?boolean?push(LogMsg?logMsg){

          ????????return?queue.offer(logMsg);

          ????}



          ????//消息出列

          ????public?static?LogMsg?poll(){

          ????????return?queue.poll();

          ????}



          ????//消息隊列是否已經(jīng)處理完畢,處理完畢返回true

          ????public?static?boolean?isFinash(){

          ????????return?!queue.isEmpty();

          ????}

          }
          3.7.定義注解

          在此我們定義一個名為YzLogWrite的注解類,它主要實現(xiàn)的功能是值注入及日志標記。
          對于注解不是很了解的同僚可以看我的另一篇文章:想自己寫框架?不了解注解可不行。
          YzLogWrite

          import?java.lang.annotation.*;

          //作用于字段
          @Target({ElementType.FIELD})
          //運行時生效
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public?@interface?YzLogWrite?{

          ????//需要注解的值
          ????int?value()?default?-1;
          ????//默認是Linux系統(tǒng),默認記錄文件夾如下
          ????String?path()?default?"";
          ????//文件名
          ????String?fileName()?default?"";
          ????//內(nèi)容
          ????String?msgPrefix()?default?"";
          }
          3.8.注解邏輯實現(xiàn)

          思想:聲明大于配置
          如果我們在注解中聲明了一些用到的信息,但是配置文件中也有這些信息,我們應(yīng)該有限選用注解中聲明的信息。
          思想:自定義掃描路徑
          我們應(yīng)當給予用戶權(quán)限去讓他自己規(guī)定自己注解使用的包。
          我們定義了注解,但是還需要進行一些操作來完善注解的功能,在這一部分,我們要將值注入,并且將值信息發(fā)送到消息隊列中。
          DealAnnotation

          import?cn.yzstu.annotation.YzLogWrite;
          import?cn.yzstu.beans.LogMsg;
          import?cn.yzstu.support.Constants;
          import?java.io.File;
          import?java.lang.annotation.Annotation;
          import?java.lang.reflect.Field;
          import?java.net.URL;
          import?java.util.ArrayList;
          import?java.util.List;

          public?class?DealAnnotation?{

          ????//配置文件中設(shè)置的log所在地址
          ????private?static?String?LOG_PATH?=?ConfigurationUtil.getInstance(Constants.CONFIG_FILE_NAME).getValue(Constants.CONFIG_LOG_PATH);
          ????//保存那些存在注解的class的類名
          ????private?List<String>?registyClasses?=?new?ArrayList<>();
          ????public?void?injectAndMakeMsg()?{

          ????????//需要掃描的注解可能存在的位置
          ????????String?scanPath?=?ConfigurationUtil.getInstance(Constants.CONFIG_FILE_NAME).getValue(Constants.CONFIG_SACN_PATH);
          ????????doScanner(scanPath);
          ????????for?(String?className?:?registyClasses)?{
          ????????????try?{
          ????????????????Class?clazz?=?Class.forName(className);
          ????????????????Field[]?fields?=?clazz.getDeclaredFields();
          ????????????????for?(Field?field?:?fields)?{
          ????????????????????//獲取類的所有注解
          ????????????????????Annotation[]?annotations?=?field.getAnnotations();
          ????????????????????//沒有注解或沒有我們的注解,跳過
          ????????????????????if?(0?==?annotations.length?||?!field.isAnnotationPresent(YzLogWrite.class))?{
          ????????????????????????continue;
          ????????????????????}

          ????????????????????//獲取注解
          ????????????????????YzLogWrite?yzLogWrite?=?field.getAnnotation(YzLogWrite.class);
          ????????????????????//提取注解中的值
          ????????????????????//聲明大于配置
          ????????????????????String?path?=?null?==?yzLogWrite.path()?||?yzLogWrite.path().isEmpty()???LOG_PATH?:?yzLogWrite.path();
          ????????????????????String?content?=?null?==?yzLogWrite.msgPrefix()?||?yzLogWrite.msgPrefix().isEmpty()???Constants.DEFAULT_CONTENT_PREFIX?:?yzLogWrite.msgPrefix();
          ????????????????????String?fileName?=?null?==?yzLogWrite.fileName()?||?yzLogWrite.fileName().isEmpty()???Constants.DEFAULT_FILE_NAME?:?yzLogWrite.fileName();
          ????????????????????int?value?=?yzLogWrite.value();
          ????????????????????//新建logMsg,在構(gòu)造函數(shù)中已入列
          ????????????????????new?LogMsg(path,?content?+?":"?+?value,?fileName);
          ????????????????????//開始注入
          ????????????????????//強制訪問該成員變量
          ????????????????????field.setAccessible(true);
          ????????????????????//注入int值
          ????????????????????field.setInt(Integer.class,?value);
          ????????????????}
          ????????????}?catch?(ClassNotFoundException?|?IllegalAccessException?e)?{
          ????????????????e.printStackTrace();
          ????????????}
          ????????}
          ????}

          ????private?void?doScanner(String?scanPath)?{

          ????????URL?url?=?this.getClass().getClassLoader().getResource(scanPath.replaceAll("\\.",?"/"));
          ????????File?classPath?=?new?File(url.getFile());
          ????????for?(File?file?:?classPath.listFiles())?{
          ????????????if?(file.isDirectory())?{
          ????????????????//如果是目錄則遞歸調(diào)用,直到找到class
          ????????????????doScanner(scanPath?+?"."?+?file.getName());
          ????????????}?else?{
          ????????????????if?(!file.getName().endsWith(".class"))?{
          ????????????????????continue;
          ????????????????}
          ????????????????String?className?=?(scanPath.replace("/",?".")?+?"."?+?file.getName().replace(".class",?""));
          ????????????????registyClasses.add(className);
          ????????????}
          ????????}
          ????}
          }
          3.9.處理消息

          思想:多態(tài)分發(fā)
          盡量讓我們的隊列能夠處理不同種類的消息,我們在獲取到隊列中的消息之后,應(yīng)當有一個對消息類型的判斷,并將不同類型的消息分發(fā)到不同方法中的操作。
          通過上面的操作,我們已經(jīng)把值注入并且把日志消息傳到隊列中去了,現(xiàn)在還要對隊列中的消息進行處理。

          import?cn.yzstu.beans.LogMsg;
          public?class?DealMsg?extends?Thread{

          ????@Override
          ????public?void?run()?{
          ????????while?(MsgQueue.isFinash()){
          ????????????//多態(tài)
          ????????????//實際中,我們可以定義很多中msg,用type來區(qū)分,并通過不同的方法來處理
          ????????????//此處運用了這種思想,但是沒有實現(xiàn)具體操作
          ????????????LogMsg?logMsg?=?MsgQueue.poll();
          ????????????switch?(logMsg.getMsgType()){
          ????????????????case?"logmsg"?:
          ????????????????????//如果類型是logmsg,那就通過日志來處理
          ????????????????????dealLogMsg(logMsg);
          ????????????????????break;
          ????????????????default:defaultMethod(logMsg);
          ????????????}
          ????????}
          ????????this.interrupt();
          ????}

          ????private?void?defaultMethod(LogMsg?logMsg)?{
          ????????System.out.println("no?msg");
          ????}

          ????private?void?dealLogMsg(LogMsg?logMsg)?{
          ? ? ? ?LogUtil.write2file(logMsg.getPath(),logMsg.getFileName(),logMsg.getContent());
          ????}

          ????@Override
          ????public?synchronized?void?start()?{
          ????????this.run();
          ????}
          }
          3.10.提供入口

          我們的一個簡單的實例基本上功能已經(jīng)完成了,那如何引入呢?這里我采取的方法是留一個操作的方法來執(zhí)行我們所有的功能。

          import?cn.yzstu.annotation.YzLogWrite;
          public?class?StartWork?{

          ????//程序入口
          ????public?static?void?doWork(){

          ????????//處理:掃描注解、注入、發(fā)送日志消息到隊列
          ????????new?DealAnnotation().injectAndMakeMsg();
          ????????//創(chuàng)建線程來處理消息
          ????????new?DealMsg().start();
          ????}
          }



          測試


          我們以上已經(jīng)完成了所有的功能,需要現(xiàn)在就來測試一下。
          創(chuàng)建配置類
          我們規(guī)定配置文件名為“yzlogconfig”,那么現(xiàn)在在resource文件夾下創(chuàng)建一個該配置文件。

          #logpath最后需要帶/
          logpath?=?/opt/
          scanpath?=?cn/yzstu/tt
          我們只配置了log日志路徑和注解位置,用以測試默認參數(shù)是否生效

          創(chuàng)建測試類
          我們在上面配置文件中規(guī)定了我們注解使用的包,所以應(yīng)當在該包下去使用注解,否則掃描不到我們的注解。

          import?cn.yzstu.annotation.YzLogWrite;
          import?cn.yzstu.core.StartWork;

          public?class?Demo?{
          ????//因為測試用的main函數(shù)是static,所以此時將age設(shè)置為static
          ????@YzLogWrite(value?=?18,msgPrefix?=?"記錄Baldwin的年齡:")
          ????static?int?age;
          ????public?static?void?main(String[]?args)?{
          ????????StartWork.doWork();
          ????????System.out.println(age);
          ????}
          }
          執(zhí)行結(jié)果

          首先看控制臺,顯示注入成功。

          /opt/java/jdk1.8.0_241/bin/java?-javaagent:/opt/jetbrains/idea-IU-193.6911.18/lib/idea_rt.jar=38115:/opt/jetbrains/idea-IU-193.6911.18/bin?-Dfile.encoding=UTF-8?-classpath?/opt/java/jdk1.8.0_241/jre/lib/charsets.jar:/opt/java/jdk1.8.0_241/jre/lib/deploy.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/cldrdata.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/dnsns.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/jaccess.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/jfxrt.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/localedata.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/nashorn.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/sunec.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/sunjce_provider.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/sunpkcs11.jar:/opt/java/jdk1.8.0_241/jre/lib/ext/zipfs.jar:/opt/java/jdk1.8.0_241/jre/lib/javaws.jar:/opt/java/jdk1.8.0_241/jre/lib/jce.jar:/opt/java/jdk1.8.0_241/jre/lib/jfr.jar:/opt/java/jdk1.8.0_241/jre/lib/jfxswt.jar:/opt/java/jdk1.8.0_241/jre/lib/jsse.jar:/opt/java/jdk1.8.0_241/jre/lib/management-agent.jar:/opt/java/jdk1.8.0_241/jre/lib/plugin.jar:/opt/java/jdk1.8.0_241/jre/lib/resources.jar:/opt/java/jdk1.8.0_241/jre/lib/rt.jar:/root/IdeaProjects/LogUtil/target/classes?cn.yzstu.tt.Demo

          18
          Process?finished?with?exit?code?0
          然后再看我們的/opt文件夾下有么有日志文件,日志成功寫入。

          查看日志文件,注解聲明內(nèi)容啟用。

          2020-04-06 00:17:30:記錄Baldwin的年齡::18

          總結(jié)

          目前為止,我們的一個簡單的日志記錄的輪子已經(jīng)造好了,我們可以把他打成JAR包引入到我們的項目中去,只需要在項目初始化時啟用我們的功能即可。

          5.1.思想
          思想:給予用戶配置權(quán)限
          框架是拿給別人用的,一定要給予用戶自主配置的權(quán)限。
          思想:默認配置
          很多時候,我們的用戶可能沒有配置需要配置的信息,而且注解中也沒有聲明,那么就要求我們存在默認的配置來填補這些空缺,從而避免由于空配置導(dǎo)致的錯誤。
          思想:聲明大于配置
          如果我們在注解中聲明了一些用到的信息,但是配置文件中也有這些信息,我們應(yīng)該有限選用注解中聲明的信息。
          思想:自定義掃描路徑
          我們應(yīng)當給予用戶權(quán)限去讓他自己規(guī)定自己注解使用的包
          思想:多態(tài)分發(fā)
          盡量讓我們的隊列能夠處理不同種類的消息,我們在獲取到隊列中的消息之后,應(yīng)當有一個對消息類型的判斷,并將不同類型的消息分發(fā)到不同方法中的操作
          5.2.關(guān)于本項目
          作者是一個正在編程路上匍匐前進的萌新,這篇實例僅提供給新手入門使用,如果有錯誤,還請大佬不吝指點。
          項目代碼:http://gitee.com/dikeywork/LogUtil
          5.3.個人總結(jié)
          完成項目時遇到了許多的困難,本來打算一天完事兒,但是真正寫完這篇文章卻用了整整兩天,仍需進步。
          我是Baldwin,一個25歲的程序員,致力于讓學(xué)習(xí)變得更有趣,如果你也真正喜愛編程,真誠的希望與你交個朋友,一起在編程的海洋里徜徉!
          原文鏈接:
          http://blog.csdn.net/shouchenchuan5253/java/article/details/105256723
          往期熱門文章:

          1、笑死!程序員延壽指南開源了
          2、用 Dubbo 傳輸文件?被老板一頓揍!
          3、45 個 Git 經(jīng)典操作場景,專治不會合代碼!
          4、@Transactional 注解失效的3種原因及解決辦法
          5、小學(xué)生們在B站講算法,網(wǎng)友:我只會阿巴阿巴
          6、Spring爆出比Log4j2還大的漏洞?
          7、Objects.equals 有坑!!!
          8、Redis 官方可視化工具,功能真心強大!
          8、xxl-job 和 ElasticJob比,誰牛?
          10、推薦好用的 Spring Boot 內(nèi)置工具類

          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操你啦人人操 | 天堂伊人成人在线 | 日小嫩逼视频 | 亚洲无码视频在线观看免费 | 激情深爱五月天 |