我的项目实际
微服务架构中,二次浅封装实际分布式我的项目中,选型与依赖治理一、背景简介我的项目中日志的治理是根底性能之一,不同的用户和场景下对日志都有特定的需要,从而须要用不同的策略进行日志采集和治理,如果是在分布式的我的项目中,日志的体系设计更加简单。
日志类型:业务操作、信息打印、申请链路;角色需要:研发端、用户端、服务级、零碎级;
用户与需要
用户端:外围数据的增删改,业务操作日志;研发端:日志采集与管理策略,异样日志监控;服务级:要害日志打印,问题发现与排查;零碎级:分布式我的项目中链路生成,监控体系;不同的场景中,须要选用不同的技术手段去实现日志采集治理,例如日志打印、操作记录、ELK体系等,留神要防止日志治理导致程序异常中断的状况。
越是简单的零碎设计和业务场景,就越依赖日志的输入信息,在大规模的架构中,通常还会搭建独立的日志平台,提供日志数据的采集、存储、剖析等整套解决方案。
二、Slf4j组件1、外观模式日志的组件恪守外观设计模式,Slf4j作为日志体系的外观对象,定义标准日志的规范,日志能力的具体实现交由各个子模块去实现;Slf4j明确日志对象的加载办法和性能接口,与客户端交互提供日志治理性能;
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Impl.class) ;通常禁止间接应用Logback、Log4j等具体实现组件的API,防止组件替换带来不必要的麻烦,能够做到日志的对立保护。
2、SPI接口从Slf4j和Logback组件交互来看,在日志的应用过程中,根本的切入点即应用Slf4j的接口,辨认并加载Logback中的具体实现;SPI定义的接口标准,通常作为第三方(内部)组件的实现。
上述SPI作为两套组件的连接点,通过源码大抵看下加载过程,追溯LoggerFactory的源码即可:
public final class org.slf4j.LoggerFactory { private final static void performInitialization() { bind(); } private final static void bind() { try { StaticLoggerBinder.getSingleton(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"."); } } }}此处只贴出了几行示意性质的源码,在LoggerFactory中执行初始化绑定关联的时候,如果没有找到具体的日志实现组件,是会报告出相应的异样信息,并且采纳的是System.err输入谬误提醒。
三、自定义组件1、性能封装对于日志(或其余)罕用性能,通常会在代码工程中封装独立的代码包,作为公共依赖,对立治理和保护,对于日志的自定义封装能够参考之前的文档,这里通常波及几个外围点:
starter加载:封装包配置成starter组件,能够被框架扫描和加载;aop切面编程:通常在相干办法上增加日志注解,即可自动记录动作;annotation注解:定义日志记录须要标记的外围参数和解决逻辑;至于如何组装日志内容,适配业务语义,以及后续的治理流程,则依据具体场景设计相应的策略即可,比方日志怎么存储、是否实时剖析、是否异步执行等。
2、对象解析在自定义注解中,会波及到对象解析的问题,即在注解中放入要从对象中解析的属性,并且把值拼接到日志内容中,能够加强业务日志的语义可读性。
import org.springframework.expression.Expression;import org.springframework.expression.spel.standard.SpelExpressionParser;public class Test { public static void main(String[] args) { // Map汇合 HashMap<String,Object> infoMap = new HashMap<>() ; infoMap.put("info","Map的形容") ; // List汇合 ArrayList<Object> arrayList = new ArrayList<>() ; arrayList.add("List-00"); arrayList.add("List-01"); // User对象 People oldUser = new People("Wang",infoMap,arrayList) ; People newUser = new People("LiSi",infoMap,arrayList) ; // 包装对象 WrapObj wrapObj = new WrapObj("WrapObject",oldUser,newUser) ; // 对象属性解析 SpelExpressionParser parser = new SpelExpressionParser(); // objName Expression objNameExp = parser.parseExpression("#root.objName"); System.out.println(objNameExp.getValue(wrapObj)); // oldUser Expression oldUserExp = parser.parseExpression("#root.oldUser"); System.out.println(oldUserExp.getValue(wrapObj)); // newUser.userName Expression userNameExp = parser.parseExpression("#root.newUser.userName"); System.out.println(userNameExp.getValue(wrapObj)); // newUser.hashMap[info] Expression ageMapExp = parser.parseExpression("#root.newUser.hashMap[info]"); System.out.println(ageMapExp.getValue(wrapObj)); // oldUser.arrayList[1] Expression arr02Exp = parser.parseExpression("#root.oldUser.arrayList[1]"); System.out.println(arr02Exp.getValue(wrapObj)); }}@Data@AllArgsConstructorclass WrapObj { private String objName ; private People oldUser ; private People newUser ;}@Data@AllArgsConstructorclass People { private String userName ; private HashMap<String,Object> hashMap ; private ArrayList<Object> arrayList ;}留神下面应用的SpelExpressionParser解析器,即Spring框架的原生API;业务中遇到的很多问题,倡议都优先从外围依赖(Spring+JDK)中寻找解决形式,多花工夫相熟零碎中外围组件的全貌,对开发视线和思路会有极大的帮忙。
...