当前位置: 首页 > news >正文

PHP网站开发程序员招聘wordpress站点搬家

PHP网站开发程序员招聘,wordpress站点搬家,焦作网站开发,python语言编程入门点击上方蓝字关注我们0.简介Abp 框架为我们自带了审计日志功能#xff0c;审计日志可以方便地查看每次请求接口所耗的时间#xff0c;能够帮助我们快速定位到某些性能有问题的接口。除此之外#xff0c;审计日志信息还包含有每次调用接口时客户端请求的参数信息#xff0c;… 点击上方蓝字关注我们0.简介Abp 框架为我们自带了审计日志功能审计日志可以方便地查看每次请求接口所耗的时间能够帮助我们快速定位到某些性能有问题的接口。除此之外审计日志信息还包含有每次调用接口时客户端请求的参数信息客户端的 IP 与客户端使用的浏览器。有了这些数据之后我们就可以很方便地复现接口产生 BUG 时的一些环境信息。当然如果你脑洞更大的话可以根据这些数据来开发一个可视化的图形界面方便开发与测试人员来快速定位问题。PS:如果使用了 Abp.Zero 模块则自带的审计记录实现是存储到数据库当中的但是在使用 EF Core MySQL(EF Provider 为 Pomelo.EntityFrameworkCore.MySql) 在高并发的情况下会有数据库连接超时的问题这块推荐是重写实现自己采用 Redis 或者其他存储方式。如果需要禁用审计日志功能则需要在任意模块的预加载方法(PreInitialize()) 当中增加如下代码关闭审计日志功能。public class XXXStartupModule {public override PreInitialize(){// 禁用审计日志Configuration.Auditing.IsEnabled false;} } 1.启动流程审计组件与参数校验组件一样都是通过 MVC 过滤器与 Castle 拦截器来实现记录的。也就是说在每次调用接口/方法时都会进入 过滤器/拦截器 并将其写入到数据库表 AbpAuditLogs 当中。其核心思想十分简单就是在执行具体接口方法的时候先使用 StopWatch 对象来记录执行完一个方法所需要的时间并且还能够通过 HttpContext 来获取到一些客户端的关键信息。2.1 过滤器注入同上一篇文章所讲的一样过滤器是在 AddAbp() 方法内部的 ConfigureAspNetCore() 方法注入的。private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver) {// ... 其他代码//Configure MVCservices.ConfigureMvcOptions(mvcOptions {mvcOptions.AddAbp(services);});// ... 其他代码 } 而下面就是过滤器的注入方法internal static class AbpMvcOptionsExtensions {public static void AddAbp(this MvcOptions options, IServiceCollection services){// ... 其他代码AddFilters(options);// ... 其他代码}// ... 其他代码private static void AddFilters(MvcOptions options){// ... 其他过滤器注入// 注入审计日志过滤器options.Filters.AddService(typeof(AbpAuditActionFilter));// ... 其他过滤器注入}// ... 其他代码 } 2.2 拦截器注入注入拦截器的地方与 DTO 自动验证的拦截器的位置一样都是在 AbpBootstrapper 对象被构造的时候进行注册。public class AbpBootstrapper : IDisposable {private AbpBootstrapper([NotNull] Type startupModule, [CanBeNull] ActionAbpBootstrapperOptions optionsAction null){// ... 其他代码if (!options.DisableAllInterceptors){AddInterceptorRegistrars();}}// ... 其他代码// 添加各种拦截器private void AddInterceptorRegistrars(){ValidationInterceptorRegistrar.Initialize(IocManager);AuditingInterceptorRegistrar.Initialize(IocManager);EntityHistoryInterceptorRegistrar.Initialize(IocManager);UnitOfWorkRegistrar.Initialize(IocManager);AuthorizationInterceptorRegistrar.Initialize(IocManager);}// ... 其他代码 } 转到 AuditingInterceptorRegistrar 的具体实现可以发现他在内部针对于审计日志拦截器的注入是区分了类型的。internal static class AuditingInterceptorRegistrar {public static void Initialize(IIocManager iocManager){iocManager.IocContainer.Kernel.ComponentRegistered (key, handler) {// 如果审计日志配置类没有被注入则直接跳过if (!iocManager.IsRegisteredIAuditingConfiguration()){return;}var auditingConfiguration iocManager.ResolveIAuditingConfiguration();// 判断当前 DI 所注入的类型是否应该为其绑定审计日志拦截器if (ShouldIntercept(auditingConfiguration, handler.ComponentModel.Implementation)){handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(AuditingInterceptor)));}};}// 本方法主要用于判断当前类型是否符合绑定拦截器的条件private static bool ShouldIntercept(IAuditingConfiguration auditingConfiguration, Type type){// 首先判断当前类型是否在配置类的注册类型之中如果是则进行拦截器绑定if (auditingConfiguration.Selectors.Any(selector selector.Predicate(type))){return true;}// 当前类型如果拥有 Audited 特性则进行拦截器绑定if (type.GetTypeInfo().IsDefined(typeof(AuditedAttribute), true)){return true;}// 如果当前类型内部的所有方法当中有一个方法拥有 Audited 特性则进行拦截器绑定if (type.GetMethods().Any(m m.IsDefined(typeof(AuditedAttribute), true))){return true;}// 都不满足则返回 false,不对当前类型进行绑定return false;} } 可以看到在判断是否绑定拦截器的时候Abp 使用了 auditingConfiguration.Selectors 的属性来进行判断那么默认 Abp 为我们添加了哪些类型是必定有审计日志的呢通过代码追踪我们来到了 AbpKernalModule 类的内部在其预加载方法里面有一个 AddAuditingSelectors() 的方法该方法的作用就是添加了一个针对于应用服务类型的一个选择器对象。public sealed class AbpKernelModule : AbpModule {public override void PreInitialize(){// ... 其他代码AddAuditingSelectors();// ... 其他代码}// ... 其他代码private void AddAuditingSelectors(){Configuration.Auditing.Selectors.Add(new NamedTypeSelector(Abp.ApplicationServices,type typeof(IApplicationService).IsAssignableFrom(type)));}// ... 其他代码 } 我们先看一下 NamedTypeSelector 的一个作用是什么其基本类型定义由一个 string 和 FuncType, bool 组成十分简单重点就出在这个断言委托上面。public class NamedTypeSelector {// 选择器名称public string Name { get; set; }// 断言委托public FuncType, bool Predicate { get; set; }public NamedTypeSelector(string name, FuncType, bool predicate){Name name;Predicate predicate;} } 回到最开始的地方当 Abp 为 Selectors 添加了一个名字为 Abp.ApplicationServices 的类型选择器。其断言委托的大体意思就是传入的 **type ** 参数是继承自 IApplicationService 接口的话则返回 true,否则返回 false。这样在程序启动的时候首先注入类型的时候会首先进入上文所述的拦截器绑定类当中这个时候会使用 Selectors 内部的类型选择器来调用这个集合内部的断言委托只要这些选择器对象有一个返回 true,那么就直接与当前注入的 type 绑定拦截器。2.代码分析2.1 过滤器代码分析首先查看这个过滤器的整体类型结构一个标准的过滤器肯定要实现 IAsyncActionFilter 接口。从下面的代码我们可以看到其注入了 IAbpAspNetCoreConfiguration 和一个 IAuditingHelper 对象。这两个对象的作用分别是判断是否记录日志另一个则是用来真正写入日志所使用的。public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency {// 审计日志组件配置对象private readonly IAbpAspNetCoreConfiguration _configuration;// 真正用来写入审计日志的工具类private readonly IAuditingHelper _auditingHelper;public AbpAuditActionFilter(IAbpAspNetCoreConfiguration configuration, IAuditingHelper auditingHelper){_configuration configuration;_auditingHelper auditingHelper;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){// ... 代码实现}// ... 其他代码 } 接着看 AbpAuditActionFilter() 方法内部的实现进入这个过滤器的时候通过 ShouldSaveAudit() 方法来判断是否要写审计日志。之后呢与 DTO 自动验证的过滤器一样通过 AbpCrossCuttingConcerns.Applying() 方法为当前的对象增加了一个标识用来告诉拦截器说我已经处理过了你就不要再重复处理了。再往下就是创建审计信息执行具体接口方法并且如果产生了异常的话也会存放到审计信息当中。最后接口无论是否执行成功还是说出现了异常信息都会将其性能计数信息同审计信息一起通过 IAuditingHelper 存储起来。public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {// 判断是否写日志if (!ShouldSaveAudit(context)){await next();return;}// 为当前类型打上标识using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.Auditing)){// 构造审计信息(AuditInfo)var auditInfo _auditingHelper.CreateAuditInfo(context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(),context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo,context.ActionArguments);// 开始性能计数var stopwatch Stopwatch.StartNew();try{// 尝试调用接口方法var result await next();// 产生异常之后将其异常信息存放在审计信息之中if (result.Exception ! null !result.ExceptionHandled){auditInfo.Exception result.Exception;}}catch (Exception ex){// 产生异常之后将其异常信息存放在审计信息之中auditInfo.Exception ex;throw;}finally{// 停止计数并且存储审计信息stopwatch.Stop();auditInfo.ExecutionDuration Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds);await _auditingHelper.SaveAsync(auditInfo);}} } 2.2 拦截器代码分析拦截器处理时的总体思路与过滤器类似其核心都是通过 IAuditingHelper 来创建审计信息和持久化审计信息的。只不过呢由于拦截器不仅仅是处理 MVC 接口也会处理内部的一些类型的方法所以针对同步方法与异步方法的处理肯定会复杂一点。拦截器呢我们关心一下他的核心方法 Intercept() 就行了。public void Intercept(IInvocation invocation) {// 判断过滤器是否已经处理了过了if (AbpCrossCuttingConcerns.IsApplied(invocation.InvocationTarget, AbpCrossCuttingConcerns.Auditing)){invocation.Proceed();return;}// 通过 IAuditingHelper 来判断当前方法是否需要记录审计日志信息if (!_auditingHelper.ShouldSaveAudit(invocation.MethodInvocationTarget)){invocation.Proceed();return;}// 构造审计信息var auditInfo _auditingHelper.CreateAuditInfo(invocation.TargetType, invocation.MethodInvocationTarget, invocation.Arguments);// 判断方法的类型同步方法与异步方法的处理逻辑不一样if (invocation.Method.IsAsync()){PerformAsyncAuditing(invocation, auditInfo);}else{PerformSyncAuditing(invocation, auditInfo);} }// 同步方法的处理逻辑与 MVC 过滤器逻辑相似 private void PerformSyncAuditing(IInvocation invocation, AuditInfo auditInfo) {var stopwatch Stopwatch.StartNew();try{invocation.Proceed();}catch (Exception ex){auditInfo.Exception ex;throw;}finally{stopwatch.Stop();auditInfo.ExecutionDuration Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds);_auditingHelper.Save(auditInfo);} }// 异步方法处理 private void PerformAsyncAuditing(IInvocation invocation, AuditInfo auditInfo) {var stopwatch Stopwatch.StartNew();invocation.Proceed();if (invocation.Method.ReturnType typeof(Task)){invocation.ReturnValue InternalAsyncHelper.AwaitTaskWithFinally((Task) invocation.ReturnValue,exception SaveAuditInfo(auditInfo, stopwatch, exception));}else //TaskTResult{invocation.ReturnValue InternalAsyncHelper.CallAwaitTaskWithFinallyAndGetResult(invocation.Method.ReturnType.GenericTypeArguments[0],invocation.ReturnValue,exception SaveAuditInfo(auditInfo, stopwatch, exception));} }private void SaveAuditInfo(AuditInfo auditInfo, Stopwatch stopwatch, Exception exception) {stopwatch.Stop();auditInfo.Exception exception;auditInfo.ExecutionDuration Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds);_auditingHelper.Save(auditInfo); } 这里异步方法的处理在很早之前的工作单元拦截器就有过讲述这里就不再重复说明了。2.3 核心的 IAuditingHelper从代码上我们就可以看到不论是拦截器还是过滤器都是最终都是通过 IAuditingHelper 对象来储存审计日志的。Abp 依旧为我们实现了一个默认的 AuditingHelper 实现了其接口的所有方法。我们先查看一下这个接口的定义public interface IAuditingHelper {// 判断当前方法是否需要存储审计日志信息bool ShouldSaveAudit(MethodInfo methodInfo, bool defaultValue false);// 根据参数集合创建一个审计信息一般用于拦截器AuditInfo CreateAuditInfo(Type type, MethodInfo method, object[] arguments);// 根据一个参数字典类来创建一个审计信息一般用于 MVC 过滤器AuditInfo CreateAuditInfo(Type type, MethodInfo method, IDictionarystring, object arguments);// 同步保存审计信息void Save(AuditInfo auditInfo);// 异步保存审计信息Task SaveAsync(AuditInfo auditInfo); } 我们来到其默认实现 AuditingHelper 类型先看一下其内部注入了哪些接口。public class AuditingHelper : IAuditingHelper, ITransientDependency {// 日志记录器用于记录日志public ILogger Logger { get; set; }// 用于获取当前登录用户的信息public IAbpSession AbpSession { get; set; }// 用于持久话审计日志信息public IAuditingStore AuditingStore { get; set; }// 主要作用是填充审计信息的客户端调用信息private readonly IAuditInfoProvider _auditInfoProvider;// 审计日志组件的配置相关private readonly IAuditingConfiguration _configuration;// 在调用 AuditingStore 进行持久化的时候使用创建一个工作单元private readonly IUnitOfWorkManager _unitOfWorkManager;// 用于序列化参数信息为 JSON 字符串private readonly IAuditSerializer _auditSerializer;public AuditingHelper(IAuditInfoProvider auditInfoProvider,IAuditingConfiguration configuration,IUnitOfWorkManager unitOfWorkManager,IAuditSerializer auditSerializer){_auditInfoProvider auditInfoProvider;_configuration configuration;_unitOfWorkManager unitOfWorkManager;_auditSerializer auditSerializer;AbpSession NullAbpSession.Instance;Logger NullLogger.Instance;AuditingStore SimpleLogAuditingStore.Instance;}// ... 其他实现的接口 } 2.3.1 判断是否创建审计信息首先分析一下其内部的 ShouldSaveAudit() 方法整个方法的核心作用就是根据传入的方法类型来判定是否为其创建审计信息。其实在这一串 if 当中你可以发现有一句代码对方法是否标注了 DisableAuditingAttribute 特性进行了判断如果标注了该特性则不为该方法创建审计信息。所以我们就可以通过该特性来控制自己应用服务类控制里面的的接口是否要创建审计信息。同理我们也可以通过显式标注 AuditedAttribute 特性来让拦截器为这个方法创建审计信息。public bool ShouldSaveAudit(MethodInfo methodInfo, bool defaultValue false) {if (!_configuration.IsEnabled){return false;}if (!_configuration.IsEnabledForAnonymousUsers (AbpSession?.UserId null)){return false;}if (methodInfo null){return false;}if (!methodInfo.IsPublic){return false;}if (methodInfo.IsDefined(typeof(AuditedAttribute), true)){return true;}if (methodInfo.IsDefined(typeof(DisableAuditingAttribute), true)){return false;}var classType methodInfo.DeclaringType;if (classType ! null){if (classType.GetTypeInfo().IsDefined(typeof(AuditedAttribute), true)){return true;}if (classType.GetTypeInfo().IsDefined(typeof(DisableAuditingAttribute), true)){return false;}if (_configuration.Selectors.Any(selector selector.Predicate(classType))){return true;}}return defaultValue; } 2.3.2 创建审计信息审计信息在创建的时候就为我们将当前调用接口时的用户信息存放在了审计信息当中之后通过 IAuditInfoProvider 的 Fill() 方法填充了客户端 IP 与浏览器信息。public AuditInfo CreateAuditInfo(Type type, MethodInfo method, IDictionarystring, object arguments) {// 构建一个审计信息对象var auditInfo new AuditInfo{TenantId AbpSession.TenantId,UserId AbpSession.UserId,ImpersonatorUserId AbpSession.ImpersonatorUserId,ImpersonatorTenantId AbpSession.ImpersonatorTenantId,ServiceName type ! null? type.FullName: ,MethodName method.Name,// 将参数转换为 JSON 字符串Parameters ConvertArgumentsToJson(arguments),ExecutionTime Clock.Now};try{// 填充客户 IP 与浏览器信息等_auditInfoProvider.Fill(auditInfo);}catch (Exception ex){Logger.Warn(ex.ToString(), ex);}return auditInfo; } 2.4 审计信息持久化通过上一小节我们知道了在调用审计信息保存接口的时候实际上是调用的 IAuditingStore 所提供的 SaveAsync(AuditInfo auditInfo) 方法来持久化这些审计日志信息的。如果你没有集成 Abp.Zero 项目的话则使用的是默认的实现就是简单通过 ILogger 输出审计信息到日志当中。默认有这两种实现至于第一种是 Abp 的单元测试项目所使用的。这里我们就简单将一下 AuditingStore 这个实现吧其实很简单的就是注入了一个仓储在保存的时候往审计日志表插入一条数据即可。这里使用了 AuditLog.CreateFromAuditInfo() 方法将 AuditInfo 类型的审计信息转换为数据库实体用于仓储进行插入操作。public class AuditingStore : IAuditingStore, ITransientDependency {private readonly IRepositoryAuditLog, long _auditLogRepository;public AuditingStore(IRepositoryAuditLog, long auditLogRepository){_auditLogRepository auditLogRepository;}public virtual Task SaveAsync(AuditInfo auditInfo){// 向表中插入数据return _auditLogRepository.InsertAsync(AuditLog.CreateFromAuditInfo(auditInfo));} } 同样这里建议重新实现一个 AuditingStore存储在 Redis 或者其他地方。3. 后记前几天发现 Abp 的团队有开了一个新坑叫做 Abp vNext 框架该框架全部基于 .NET Core 进行开发而且会针对微服务项目进行专门的设计有兴趣的朋友可以持续关注。其 GitHub 地址为https://github.com/abpframework/abp/官方地址为https://abp.io/作者myzony出处https://www.cnblogs.com/myzony/p/9723531.html公众号“码侠江湖”所发表内容注明来源的版权归原出处所有无法查证版权的或者未注明出处的均来自网络系转载转载的目的在于传递更多信息版权属于原作者。如有侵权请联系笔者会第一时间删除处理扫描二维码获取更多精彩码侠江湖喜欢就点个在看再走吧
http://www.zqtcl.cn/news/169133/

相关文章:

  • 企业网站的意义公司网站建app
  • 网站设计模板免费国庆图片制作小程序
  • 包头焦点网站建设郑州包装设计公司
  • 建行官方网站首页做跨境电商亏死了
  • 河北智能网站建设平台卖链接的网站
  • 网站建设简单点的服装搭配网站建设策划书
  • 哪一个军事网站做的比较好今天第四针最新消息
  • 黄页网站推广app软件查企业公司用什么软件
  • 网站设计机构培训全自动网页制作系统源码
  • 外贸网站建设收益深圳建设厅官网
  • 跟网站开发有关的内容东莞市生态环境局
  • dw软件做的东西怎么在网站用网站备案抽查通过
  • 重庆建设集团网站首页wordpress主题inn
  • 对京东网站建设的总结湖北做网站的
  • 杭州网站开发后端招郑州工装定制
  • 网站搭建论文filetype ppt 网站建设
  • 个人做营利性质网站会怎么样如何引用网站上的资料做文献
  • 新网站制作市场泰安做网站哪家好
  • 常熟苏州网站建设flash如何制作网站
  • 电商网站都是用什么做的网站服务器维护方案
  • 简述企业网站建设的流程手机怎么自己做网页
  • 网站备案信息管理呼图壁网站建设
  • 网站建设学习资料开发一套软件需要多少钱
  • 大庆网站设计衡阳seo网站推广
  • 基层科普网站建设的现状自己做的网站怎样链接数据库
  • 网站建设工程师的职位要求化妆品行业网站开发
  • 做海报有什么素材网站知乎什么样的蓝色做网站做好看
  • 餐饮网站建设网站wordpress优酷视频插件下载
  • 什么网站做广告效果好wordpress中文cms
  • seo与网站优化广州洲聚网站开发