小言_互联网的博客

因为造轮子,我一个月就转正了 | 原力计划

419人阅读  评论(0)

作者 | Baldwin_KeepMind

责编 | 伍杏玲

出品 | CSDN博客

2019年6月,我通过社招入职现在所工作的公司,理论上应该有三个月时间的试用期,只有试用期表现良好我才有机会转正,但因为一次优化代码过程中造了一个轮子,我获得了一个月转正的机会。

我是一个懒人,又特别喜欢琢磨,在工作的过程中我发现有一个模块运行非常的慢,主要原因是在这个模块种需要大量的进行数据库操作,而目前公司业务扩大,在数据库中已经有上亿条数据,每次对这个表进行操作,都需要花费将近3S的时间,而实际上,整个流程走下来,程序也就花费4S的时间,所以我就特别想把这段代码优化一下,将代码的耗时降低下来,经过一个星期的努力,轮子的初版发布,同事们用完之后都觉得不错,然后老大就给我递交了提前转正申请,我工作一个月就顺利转正了。

现在将我当时造轮子的主要思路在这里写下来,希望能给你一点启发。

轮子相关

首先,我们现在所说的轮子可不是汽车上的轮子,之所以叫“轮子”,是为了更好的理解。

汽车轮子是圆的,这种圆形轮子已经被各界广泛认可是比较好的结构,我们无论怎么去做,也很难超越“圆轮子”,所以我们只能在“圆轮子”的基础上去<重复发明轮子>,即是所说的造轮子。但是有一句话叫做“不要重复造轮子”,因为无论我们怎么努力,也很难去超越以前已经有的轮子,那我们为什么还要去造轮子呢?

1.只有我们自己才懂得我们的需求,你在编程中无论用什么框架,总觉得跟业务不是很契合,甚至有时候框架很臃肿,但是因为要用到其中一个内容而不得不导入一个很大的框架。

2.已有的框架太复杂,我们完全没法掌握他的所有内容,出了bug后一头雾水解决不了问题。

3.公司要求,不可使用第三方框架(多见于数据保密的公司),但是程序中要反复使用某一组件功能。

4.找不到合适的轮子。

5.想装B。

如果遇到以上问题,或许自己造轮子才是一个好办法。

前期准备

本文所讲的,可能只是造轮子最基础的教程了,所以知识储备方面要求的不是很全面,如果有大佬看到这篇文章,请轻点喷,我绝对虚心接受批评。

2.1.基础知识

总从上次发了那篇关于阅读源码的文章,总是有朋友问我“你好,请问我现在刚大一,看不懂源码怎么办?”,每每遇到这种问题,我都很绝望,我在那篇文章中所讲的内容,都是建立在已经有一定编程基础的前提上,如果正在看这篇文章的你没有接触过编程,那现在可以先点一下关注,点赞,收藏,然后回去好好学习一下基础再看这篇文章。

我们想造一个轮子,最起码有一定的编程能力,如果要有一个标准,就是能够独自搭建一个项目。

本文中主要运用到的知识点有:注解、反射、多态。

2.2.了解源码

比如JDK源码和一些框架的源码,造轮子在某种层面上来说,就是写一个框架,我们在没有基础的情况下,先看一些大佬写好的框架源码是很有帮助的,在我们自己的轮子中,可以模仿他们框架的结构。

2.3.不怕失败

第一次造轮子绝对是一个艰难而又漫长的过程,你会一次次失败,你需要经受住失败带来的对你信心和耐心的打击,如果你无法坚持,还不如不要开始。

开工

如果你看到这里,相信你已经准备好了,那么现在就开始吧!

3.1.想好需求

既然是造轮子,那么总得先想好这个轮子的用途,我们我们假设一个需求:通过注解实现系统日志输出到文件。

具体需求如下:

1.记录注解注入的数据

2.日志记录应通过文件保存到系统中,路径可配置,若无配置则选用默认配置

3.日志记录需要添加时间标签

4.日志文件名可在注解中设置

5.引入队列传递日志MSG

3.2.创建项目

为了简化过程,我们可以直接创建一个Maven项目,在你对底层有更好的理解之后,就可以用更好的架构。

新建一个LogUtil项目,项目架构如下:

因为只是一个简单的示例,所以有很多的内容知识有思想,但是还没有实现。

3.2.一些常量

主要保存在Constants.java文件中:


   
  1. public  interface Constants {
  2.      //等下要引入的配置文件名
  3.     String CONFIG_FILE_NAME =  "yzlogconfig";
  4.      //配置文件中配置的日志路径
  5.     String CONFIG_LOG_PATH =  "logpath";
  6.      //配置文件中配置的要扫描的,可能存在我们注解的路径
  7.     String CONFIG_SACN_PATH =  "scanpath";
  8.      //若未声明某些信息,则使用以下默认值
  9.      //默认的我们的日志信息前缀,对日志信息做简单描述
  10.     String DEFAULT_CONTENT_PREFIX =  "注入值:";
  11.      //默认的日志文件名(实际写入时会在日志文件名后加上日期标签)
  12.     String DEFAULT_FILE_NAME =  "log";
  13.      //日志信息类型,处理消息时会用到
  14.     String MSG_TYPE_LOG =  "log";
  15.      //默认的Linux系统下的日志路径
  16.     String LINUX_LOG_PATH =  "/home/data/";
  17.      //默认的Windows系统下的日志路径
  18.     String WIN_LOG_PATH =  "D:/winLog/data/";
  19. }

3.3.加载配置

思想:给予用户配置权限。

框架是拿给别人用的,一定要给予用户自主配置的权限,这里要加载的是那些引入我们轮子的项目的配置。

某个项目在引入我们的轮子的时候,他自己是应当有权限去自己设置一些东西的,比如我们这里的文件处理路径,是给了用户权限去配置的。

我们规定配置文件的文件名为yzlogconfig.xml,等下在代码中也可以看到这个配置文件名的设置。

ConfigurationUtil

这个工具类主要用来加载配置信息,基础工具类,这里不再累述。


   
  1. import java.util.ResourceBundle;
  2. public  class ConfigurationUtil {
  3.      private  static Object lock =  new Object();
  4.      private  static ConfigurationUtil config =  null;
  5.      private  static ResourceBundle rb =  null;
  6.      private ConfigurationUtil(String filename) {
  7.         rb = ResourceBundle.getBundle(filename);
  8.     }
  9.      public  static ConfigurationUtil getInstance(String filename) {
  10.         synchronized (lock) {
  11.              if ( null == config) {
  12.                 config =  new ConfigurationUtil(filename);
  13.             }
  14.         }
  15.          return (config);
  16.     }
  17.      public String getValue(String key) {
  18.         String ret =  "";
  19.          if (rb.containsKey(key)) {
  20.             ret = rb.getString(key);
  21.         }
  22.          return ret;
  23.     }
  24. }

3.4.日志记录功能实现

这里算是核心功能的一部分了,需要的工具类有:DateUtil(获取日期)、SystemUtil(获取当前系统的类型)、FileUtil(创建日志文件)。

DataUtil


   
  1. import java.text.SimpleDateFormat;
  2. import java.util.Date;
  3. public  class DateUtil {
  4.      public  final  static String DATE_A =  "yyyy-MM-dd";
  5.      public  final  static String DATE_B =  "yyyy-MM-dd HH:mm:ss";
  6.      public  final  static String DATE_C =  "yyyyMMddHHmmss";
  7.      public  final  static String DATE_D =  "yyyyMMdd-HHmmss-SS";
  8.      public  final  static String DATE_E =  "M月d日";
  9.      public  final  static String DATE_F =  "MM-dd";
  10.      public  final  static String DATE_G =  "yyyyMMddHHmmss";
  11.      // 普通的当前时间转字符串方法,格式为yyyy-MM-dd
  12.      public  static String getDate() {
  13.         SimpleDateFormat sdf =  new SimpleDateFormat(DATE_A);
  14.          return sdf.format( new Date());
  15.     }
  16.      public  static String getDateTime() {
  17.         Date date =  new Date();
  18.         String datestr;
  19.         SimpleDateFormat sdf =  new SimpleDateFormat(DATE_B);
  20.         datestr = sdf.format(date);
  21.          return datestr;
  22.     }
  23. }

 SystemUtil


   
  1. /**
  2.  *@描述 用于判断当前系统
  3.  *@参数
  4.  *@返回值
  5.  *@创建人  Baldwin
  6.  *@创建时间  2020/4/4
  7.  *@修改人和其它信息
  8.  */
  9. public  class SystemUtil {
  10.      /**
  11.      * 判断系统时win还是linux
  12.      * @return
  13.      */
  14.      public  static boolean isLinux(){
  15.         String name = System.getProperty( "os.name");
  16.          if(name.toLowerCase().startsWith( "win"))
  17.              return  false;
  18.          else
  19.              return  true;
  20.     }
  21. }

FileUtil


   
  1. import java.io.BufferedWriter;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.OutputStreamWriter;
  5. public  class FileUtil {
  6.      // 在已经存在的文件后面追加写的方式
  7.      public  static boolean write(String path, String str) {
  8.         File f =  new File(path);
  9.         File fileParent = f.getParentFile();
  10.         BufferedWriter bw =  null;
  11.          try {
  12.              if(!fileParent.exists()){
  13.                 fileParent.mkdirs();
  14.             }
  15.              if(!f.exists()){
  16.                 f.createNewFile();
  17.             }
  18.              // new FileWriter(name,true)设置文件为在尾部添加模式,参数为false和没有参数都代表覆写方式
  19.             bw =  new BufferedWriter( new OutputStreamWriter( new FileOutputStream(path,  true),  "UTF-8"));
  20.             bw.write(str);
  21.         }  catch ( Exception e) {
  22.             e.printStackTrace();
  23.              return  false;
  24.         }  finally {
  25.              try {
  26.                  if(bw!= null)bw.close();
  27.             }  catch ( Exception e) {
  28.                 System.out.println( "FileUtil.write colse bw wrong:" + e);
  29.             }
  30.         }
  31.          return  true;
  32.     }
  33. }

LogUtil

思想:默认配置

很多时候,我们的用户可能没有配置需要配置的信息,而且注解中也没有声明,那么就要求我们存在默认的配置来填补这些空缺,从而避免由于空配置导致的错误。

在这个类里面,我们主要进行一些日志路径和内容的整理:


   
  1. import cn.yzstu.support.Constants;
  2. import cn.yzstu.support.DateUtil;
  3. import cn.yzstu.support.FileUtil;
  4. import cn.yzstu.support.SystemUtil;
  5. public  class LogUtil {
  6.      //日志写入操作
  7.      public  static void write2file(String path, String fileName, String content) {
  8.          //获取当前日期,我们的日志保存的文件夹名是自定义path+日期
  9.         String date = DateUtil.getDate()+ "/";
  10.          try {
  11.              //传了path,那我们直接用这个path
  12.              if ( null != path &&  0 != path.length()) {
  13.                  //写入
  14.                 FileUtil.write(path + date + fileName +  ".txt",
  15.                         DateUtil.getDateTime() +  ":" + content +  "\r\n");
  16.             }  else {
  17.                  //没有传path或错误使用默认的路径
  18.                  if (SystemUtil.isLinux()) {
  19.                     FileUtil.write(Constants.LINUX_LOG_PATH + date + fileName +  ".txt",
  20.                             DateUtil.getDateTime() +  ":" + content +  "\r\n");
  21.                 }  else {
  22.                     FileUtil.write(Constants.WIN_LOG_PATH + date + fileName +  ".txt",
  23.                             DateUtil.getDateTime() +  ":" + content +  "\r\n");
  24.                 }
  25.             }
  26.         }  catch ( Exception e) {
  27.             e.printStackTrace();
  28.         }
  29.     }
  30. }

3.5.日志消息

我们等一下要把日志消息放到队列里来处理,这里定义一个日志类的消息类型,方便后续处理,在本示例中,做了简化处理,实际上对于队列消息,我们需要定义一个统一接口,让所有的消息类型都实现他,这样如果我们的消息类型很多的时候,就能做一个统一的管理了。

我们为了方便处理,在构造函数中就让这个消息入列了,并且把他的MsgType直接设置成了logmsg。


   
  1. import cn.yzstu.core.MsgQueue;
  2. import cn.yzstu.support.Constants;
  3. public  class LogMsg {
  4.      private String path;
  5.      private String content;
  6.      private String fileName;
  7.      private String msgType;
  8.      public LogMsg(String path, String content, String fileName) {
  9.         this.path = path;
  10.         this.content = content;
  11.         this.fileName = fileName;
  12.         this.msgType =  "logmsg";
  13.          //在构造函数中就让这个消息入列
  14.         MsgQueue.push(this);
  15.     } 
  16.      public String getPath() {
  17.          return path;
  18.     }
  19.      public void setPath(String path) {
  20.         this.path = path;
  21.     }
  22.      public String getContent() {
  23.          return content;
  24.     }
  25.      public void setContent(String content) {
  26.         this.content = content;
  27.     }
  28.      public String getFileName() {
  29.          return fileName;
  30.     }
  31.      public void setFileName(String fileName) {
  32.         this.fileName = fileName;
  33.     }
  34.      public String getMsgType() {
  35.          return this.msgType;
  36.     }
  37.      public void setMsgType(String msgType) {
  38.         this.msgType = msgType;
  39.     }
  40.     @Override
  41.      public String toString() {
  42.          return  "LogMsg{" +
  43.                  "path='" + path +  '\'' +
  44.                  ", content='" + content +  '\'' +
  45.                  ", fileName='" + fileName +  '\'' +
  46.                  ", msgType='" + msgType +  '\'' +
  47.                  '}';
  48.     }
  49. }

3.6.定义队列

实际情况中,我们的队列里面会存在很多中类型的消息,在本示例中只存在logmsg。


   
  1. import cn.yzstu.beans.LogMsg;
  2. import java.util.Queue;
  3. import java.util.concurrent.ConcurrentLinkedDeque;
  4. public  class MsgQueue {
  5.      private  static Queue<LogMsg> queue =  new ConcurrentLinkedDeque<>();
  6.      //消息入列
  7.      public  static boolean push(LogMsg logMsg){
  8.          return queue.offer(logMsg);
  9.     }
  10.      //消息出列
  11.      public  static LogMsg poll(){
  12.          return queue.poll();
  13.     }
  14.      //消息队列是否已经处理完毕,处理完毕返回true
  15.      public  static boolean isFinash(){
  16.          return !queue.isEmpty();
  17.     }
  18. }

3.7.定义注解

在此我们定义一个名为YzLogWrite的注解类,它主要实现的功能是值注入及日志标记。

对于注解不是很了解的同僚可以看我的另一篇文章:想自己写框架?不了解注解可不行。

YzLogWrite


   
  1. import java.lang.annotation.*;
  2. //作用于字段
  3. @Target({ElementType.FIELD})
  4. //运行时生效
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. public @ interface YzLogWrite {
  8.      //需要注解的值
  9.     int value()  default  -1;
  10.      //默认是Linux系统,默认记录文件夹如下
  11.     String path()  default  "";
  12.      //文件名
  13.     String fileName()  default  "";
  14.      //内容
  15.     String msgPrefix()  default  "";
  16. }

3.8.注解逻辑实现

思想:声明大于配置

如果我们在注解中声明了一些用到的信息,但是配置文件中也有这些信息,我们应该有限选用注解中声明的信息。

思想:自定义扫描路径

我们应当给予用户权限去让他自己规定自己注解使用的包。

我们定义了注解,但是还需要进行一些操作来完善注解的功能,在这一部分,我们要将值注入,并且将值信息发送到消息队列中。

DealAnnotation


   
  1. import cn.yzstu.annotation.YzLogWrite;
  2. import cn.yzstu.beans.LogMsg;
  3. import cn.yzstu.support.Constants;
  4. import java.io.File;
  5. import java.lang.annotation.Annotation;
  6. import java.lang.reflect.Field;
  7. import java.net.URL;
  8. import java.util.ArrayList;
  9. import java.util. List;
  10. public  class DealAnnotation {
  11.      //配置文件中设置的log所在地址
  12.      private  static String LOG_PATH = ConfigurationUtil.getInstance(Constants.CONFIG_FILE_NAME).getValue(Constants.CONFIG_LOG_PATH);
  13.      //保存那些存在注解的class的类名
  14.      private  List<String> registyClasses =  new ArrayList<>();
  15.      public void injectAndMakeMsg() {
  16.          //需要扫描的注解可能存在的位置
  17.         String scanPath = ConfigurationUtil.getInstance(Constants.CONFIG_FILE_NAME).getValue(Constants.CONFIG_SACN_PATH);
  18.         doScanner(scanPath);
  19.          for (String className : registyClasses) {
  20.              try {
  21.                  Class clazz = Class.forName(className);
  22.                  Field[]  fields =  clazz. getDeclaredFields();
  23.                  for ( Field  field :  fields) {
  24.                      //获取类的所有注解
  25.                     Annotation[] annotations = field.getAnnotations();
  26.                      //没有注解或没有我们的注解,跳过
  27.                      if ( 0 == annotations.length || !field.isAnnotationPresent(YzLogWrite.class)) {
  28.                          continue;
  29.                     }
  30.                      //获取注解
  31.                     YzLogWrite yzLogWrite = field.getAnnotation(YzLogWrite.class);
  32.                      //提取注解中的值
  33.                      //声明大于配置
  34.                     String path =  null == yzLogWrite.path() || yzLogWrite.path().isEmpty() ? LOG_PATH : yzLogWrite.path();
  35.                     String content =  null == yzLogWrite.msgPrefix() || yzLogWrite.msgPrefix().isEmpty() ? Constants.DEFAULT_CONTENT_PREFIX : yzLogWrite.msgPrefix();
  36.                     String fileName =  null == yzLogWrite.fileName() || yzLogWrite.fileName().isEmpty() ? Constants.DEFAULT_FILE_NAME : yzLogWrite.fileName();
  37.                     int value = yzLogWrite.value();
  38.                      //新建logMsg,在构造函数中已入列
  39.                      new LogMsg(path, content +  ":" + value, fileName);
  40.                      //开始注入
  41.                      //强制访问该成员变量
  42.                     field.setAccessible( true);
  43.                      //注入int值
  44.                     field.setInt(Integer.class, value);
  45.                 }
  46.             }  catch (ClassNotFoundException | IllegalAccessException e) {
  47.                 e.printStackTrace();
  48.             }
  49.         }
  50.     }
  51.      private void doScanner(String scanPath) {
  52.         URL url = this.getClass().getClassLoader().getResource(scanPath.replaceAll( "\\.""/"));
  53.         File classPath =  new File(url.getFile());
  54.          for (File file : classPath.listFiles()) {
  55.              if (file.isDirectory()) {
  56.                  //如果是目录则递归调用,直到找到class
  57.                 doScanner(scanPath +  "." + file.getName());
  58.             }  else {
  59.                  if (!file.getName().endsWith( ".class")) {
  60.                      continue;
  61.                 }
  62.                 String className = (scanPath.replace( "/"".") +  "." + file.getName().replace( ".class"""));
  63.                 registyClasses.add(className);
  64.             }
  65.         }
  66.     }
  67. }

3.9.处理消息

思想:多态分发

尽量让我们的队列能够处理不同种类的消息,我们在获取到队列中的消息之后,应当有一个对消息类型的判断,并将不同类型的消息分发到不同方法中的操作。

通过上面的操作,我们已经把值注入并且把日志消息传到队列中去了,现在还要对队列中的消息进行处理。


   
  1. import cn.yzstu.beans.LogMsg;
  2. public  class DealMsg extends Thread{
  3.     @Override
  4.      public void run() {
  5.          while (MsgQueue.isFinash()){
  6.              //多态
  7.              //实际中,我们可以定义很多中msg,用type来区分,并通过不同的方法来处理
  8.              //此处运用了这种思想,但是没有实现具体操作
  9.             LogMsg logMsg = MsgQueue.poll();
  10.              switch (logMsg.getMsgType()){
  11.                  case  "logmsg" :
  12.                      //如果类型是logmsg,那就通过日志来处理
  13.                     dealLogMsg(logMsg);
  14.                      break;
  15.                  default:defaultMethod(logMsg);
  16.             }
  17.         }
  18.         this.interrupt();
  19.     }
  20.      private void defaultMethod(LogMsg logMsg) {
  21.         System.out.println( "no msg");
  22.     }
  23.      private void dealLogMsg(LogMsg logMsg) {
  24. LogUtil.write2file(logMsg.getPath(),logMsg.getFileName(),logMsg.getContent());
  25.     }
  26.     @Override
  27.      public synchronized void start() {
  28.         this.run();
  29.     }
  30. }

3.10.提供入口

我们的一个简单的实例基本上功能已经完成了,那如何引入呢?这里我采取的方法是留一个操作的方法来执行我们所有的功能。


   
  1. import cn.yzstu.annotation.YzLogWrite;
  2. public  class StartWork {
  3.      //程序入口
  4.      public  static void doWork(){
  5.          //处理:扫描注解、注入、发送日志消息到队列
  6.          new DealAnnotation().injectAndMakeMsg();
  7.          //创建线程来处理消息
  8.          new DealMsg().start();
  9.     }
  10. }

测试

我们以上已经完成了所有的功能,需要现在就来测试一下。

创建配置类

我们规定配置文件名为“yzlogconfig”,那么现在在resource文件夹下创建一个该配置文件。


   
  1. #logpath最后需要带/
  2. logpath = /opt/
  3. scanpath = cn/yzstu/tt

我们只配置了log日志路径和注解位置,用以测试默认参数是否生效

创建测试类

我们在上面配置文件中规定了我们注解使用的包,所以应当在该包下去使用注解,否则扫描不到我们的注解。


   
  1. import cn.yzstu.annotation.YzLogWrite;
  2. import cn.yzstu.core.StartWork;
  3. public  class Demo {
  4.      //因为测试用的main函数是static,所以此时将age设置为static
  5.     @YzLogWrite(value =  18,msgPrefix =  "记录Baldwin的年龄:")
  6.      static int age;
  7.      public  static void main(String[] args) {
  8.         StartWork.doWork();
  9.         System.out.println(age);
  10.     }
  11. }

执行结果

首先看控制台,显示注入成功。


   
  1. /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
  2. 18
  3. Process finished with  exit code  0

然后再看我们的/opt文件夹下有么有日志文件,日志成功写入。

查看日志文件,注解声明内容启用。

2020-04-06 00:17:30:记录Baldwin的年龄::18

总结

目前为止,我们的一个简单的日志记录的轮子已经造好了,我们可以把他打成JAR包引入到我们的项目中去,只需要在项目初始化时启用我们的功能即可。

5.1.思想

思想:给予用户配置权限

框架是拿给别人用的,一定要给予用户自主配置的权限。

思想:默认配置

很多时候,我们的用户可能没有配置需要配置的信息,而且注解中也没有声明,那么就要求我们存在默认的配置来填补这些空缺,从而避免由于空配置导致的错误。

思想:声明大于配置

如果我们在注解中声明了一些用到的信息,但是配置文件中也有这些信息,我们应该有限选用注解中声明的信息。

思想:自定义扫描路径

我们应当给予用户权限去让他自己规定自己注解使用的包

思想:多态分发

尽量让我们的队列能够处理不同种类的消息,我们在获取到队列中的消息之后,应当有一个对消息类型的判断,并将不同类型的消息分发到不同方法中的操作

5.2.关于本项目

作者是一个正在编程路上匍匐前进的萌新,这篇实例仅提供给新手入门使用,如果有错误,还请大佬不吝指点。

项目代码:https://gitee.com/dikeywork/LogUtil

5.3.个人总结

完成项目时遇到了许多的困难,本来打算一天完事儿,但是真正写完这篇文章却用了整整两天,仍需进步。

我是Baldwin,一个25岁的程序员,致力于让学习变得更有趣,如果你也真正喜爱编程,真诚的希望与你交个朋友,一起在编程的海洋里徜徉!

版权声明:本文为CSDN博主「Baldwin_KeepMind」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://blog.csdn.net/shouchenchuan5253/java/article/details/105256723

【END】

更多精彩推荐

看似毫不相干,哲学与机器学习竟有如此大的交集?

程序员会懂的冷笑话:各大编程语言的内心独白

打造金融科技银行,招行的底气源自……

5分钟!就能学会以太坊 JSON API 基础知识!

架构师前辈告诉你:代码该如何才能自己写得容易,别人看得也不痛苦

“我想玩游戏!” 大佬:玩啥游戏,教你做一个智能贪吃蛇游戏!

你点的每个“在看”,我都认真当成了喜欢


转载:https://blog.csdn.net/csdnnews/article/details/105743187
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场