1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        因?yàn)樵燧喿?我一個(gè)月就轉(zhuǎn)正了

        共 16413字,需瀏覽 33分鐘

         ·

        2022-04-28 21:57

        往期熱門文章:

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

        作者 |?Baldwin_KeepMind

        責(zé)編 | 伍杏玲

        出品 | CSDN博客


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

        輪子相關(guān)

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

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

        開工

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


        因?yàn)橹皇且粋€(gè)簡單的示例,所以有很多的內(nèi)容知識有思想,但是還沒有實(shí)現(xiàn)。
        3.2.一些常量
        主要保存在Constants.java文件中:

        public?interface?Constants?{

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

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

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

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

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

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

        ????//若未聲明某些信息,則使用以下默認(rèn)值

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

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

        ????//默認(rèn)的日志文件名(實(shí)際寫入時(shí)會在日志文件名后加上日期標(biāo)簽)

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

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

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

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

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

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

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

        }
        3.3.加載配置

        思想:給予用戶配置權(quán)限。
        框架是拿給別人用的,一定要給予用戶自主配置的權(quán)限,這里要加載的是那些引入我們輪子的項(xiàng)目的配置。
        某個(gè)項(xiàng)目在引入我們的輪子的時(shí)候,他自己是應(yīng)當(dāng)有權(quán)限去自己設(shè)置一些東西的,比如我們這里的文件處理路徑,是給了用戶權(quán)限去配置的。
        我們規(guī)定配置文件的文件名為yzlogconfig.xml,等下在代碼中也可以看到這個(gè)配置文件名的設(shè)置。
        ConfigurationUtil
        這個(gè)工具類主要用來加載配置信息,基礎(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.日志記錄功能實(shí)現(xiàn)

        這里算是核心功能的一部分了,需要的工具類有:DateUtil(獲取日期)、SystemUtil(獲取當(dāng)前系統(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";

        ????//?普通的當(dāng)前時(shí)間轉(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
        /**

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

        ?*@參數(shù)

        ?*@返回值

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

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

        ?*@修改人和其它信息

        ?*/


        public?class?SystemUtil?{


        ????/**

        ?????*?判斷系統(tǒng)時(shí)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

        思想:默認(rèn)配置
        很多時(shí)候,我們的用戶可能沒有配置需要配置的信息,而且注解中也沒有聲明,那么就要求我們存在默認(rèn)的配置來填補(bǔ)這些空缺,從而避免由于空配置導(dǎo)致的錯(cuò)誤。
        在這個(gè)類里面,我們主要進(jìn)行一些日志路徑和內(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)?{


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

        ????????try?{

        ????????????//傳了path,那我們直接用這個(gè)path

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

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

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

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

        ????????????????//沒有傳path或錯(cuò)誤使用默認(rèn)的路徑

        ????????????????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.日志消息

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

        ????????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.定義隊(duì)列

        實(shí)際情況中,我們的隊(duì)列里面會存在很多中類型的消息,在本示例中只存在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();

        ????}



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

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

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

        ????}

        }
        3.7.定義注解

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

        import?java.lang.annotation.*;

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

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

        思想:聲明大于配置
        如果我們在注解中聲明了一些用到的信息,但是配置文件中也有這些信息,我們應(yīng)該有限選用注解中聲明的信息。
        思想:自定義掃描路徑
        我們應(yīng)當(dāng)給予用戶權(quán)限去讓他自己規(guī)定自己注解使用的包。
        我們定義了注解,但是還需要進(jìn)行一些操作來完善注解的功能,在這一部分,我們要將值注入,并且將值信息發(fā)送到消息隊(duì)列中。
        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);
        ????????????????????//開始注入
        ????????????????????//強(qiáng)制訪問該成員變量
        ????????????????????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ā)
        盡量讓我們的隊(duì)列能夠處理不同種類的消息,我們在獲取到隊(duì)列中的消息之后,應(yīng)當(dāng)有一個(gè)對消息類型的判斷,并將不同類型的消息分發(fā)到不同方法中的操作。
        通過上面的操作,我們已經(jīng)把值注入并且把日志消息傳到隊(duì)列中去了,現(xiàn)在還要對隊(duì)列中的消息進(jìn)行處理。

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

        ????@Override
        ????public?void?run()?{
        ????????while?(MsgQueue.isFinash()){
        ????????????//多態(tài)
        ????????????//實(shí)際中,我們可以定義很多中msg,用type來區(qū)分,并通過不同的方法來處理
        ????????????//此處運(yùn)用了這種思想,但是沒有實(shí)現(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.提供入口

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

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

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

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



        測試


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

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

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

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

        public?class?Demo?{
        ????//因?yàn)闇y試用的main函數(shù)是static,所以此時(shí)將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é)

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

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

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

        瀏覽 26
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一边吃奶一边扎下边爽了动画开始播放 | 加勒比不卡AV | 奇米日日 | 撕开奶罩揉吃奶高潮av在线 | 久久露脸视频 | 四虎视频国产精品免费入口 | 白嫩在线77777777 | 成年人免费观看 | 亚洲影视一区二区三区 | 91久久爽无码人妻AⅤ精品蜜桃 |