首页 文章 精选 留言 我的

精选列表

搜索[aop],共1636篇文章
优秀的个人博客,低调大师

阿里巴巴正式开源自研动态非侵入AOP解决方案:JVM-Sandbox

写在前面 随着软件部署规模的扩大,系统的功能的细化,系统间耦合度和链路复杂度不断加强。若要继续保持现规模系统的稳定性,需要实现并完善监控体系、故障定位分析、流量录制回放、强弱依赖检测、故障演练等支撑工具平台。出于对服务器规模和业务稳定性的考量,这些配套工具平台要具备对目标应用具有无侵入、实时生效、动态可插拔的特点。 要实现这些,多少都会触及到一块底层技术——动态字节码增强。如果每个工具都自己实现一套字节码增强逻辑,前期实现的门槛与后期维护成本高,且不同工具间相互影响造成不可预知的风险。如何屏蔽字节码增强技术的高门槛,降低研发运维成本,同时又能支持上层多个工具平台功能的快速实现和动态管理,成为阿里集团的目标。从去年开始潜心修行,创新的研发了一套实时无侵入的字节码增强框架。 于是 JVM-Sandbox 诞生了! 应用场景 JVM-Sandbo

优秀的个人博客,低调大师

(7)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- 利用Polly+AOP+依赖注入封装的降级框架

创建简单的熔断降级框架 要达到的目标是:参与降级的方法参数要一样,当HelloAsync执行出错的时候执行HelloFallBackAsync方法。 public class Person { [HystrixCommand("HelloFallBackAsync")] public virtual async Task<string> HelloAsync(string name) { Console.WriteLine("hello"+name); return "ok"; } public async Task<string> HelloFallBackAsync(string name) { Console.WriteLine("执行失败"+name); return "fail"; }} 1、编写 HystrixCommandAttribute using AspectCore.DynamicProxy; using System; using System.Threading.Tasks; namespace hystrixtest1 { //限制这个特性只能标注到方法上 [AttributeUsage(AttributeTargets.Method)] public class HystrixCommandAttribute : AbstractInterceptorAttribute { public HystrixCommandAttribute(string fallBackMethod) { this.FallBackMethod = fallBackMethod; } public string FallBackMethod { get; set; } public override async Task Invoke(AspectContext context, AspectDelegate next) { try { await next(context);//执行被拦截的方法 } catch (Exception ex) { //context.ServiceMethod被拦截的方法。context.ServiceMethod.DeclaringType被拦截方法所在的类 //context.Implementation实际执行的对象p //context.Parameters方法参数值 //如果执行失败,则执行FallBackMethod //调用降级方法 //1.调用降级的方法(根据对象获取类,从类获取方法) var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); //2.调用降级的方法 Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); //3.把降级方法的返回值返回 context.ReturnValue = fallBackResult; } } } } 2、编写类 public class Person//需要public类 { [HystrixCommand(nameof(HelloFallBackAsync))] public virtual async Task<string> HelloAsync(string name)//需要是虚方法 { Console.WriteLine("hello"+name); String s = null; // s.ToString(); return "ok"; } public async Task<string> HelloFallBackAsync(string name) { Console.WriteLine("执行失败"+name); return "fail"; } [HystrixCommand(nameof(AddFall))] public virtual int Add(int i,int j) { String s = null; //s.ToArray(); return i + j; } public int AddFall(int i, int j) { return 0; } } 3、创建代理对象 ProxyGeneratorBuilder proxyGeneratorBuilder = new ProxyGeneratorBuilder(); using (IProxyGenerator proxyGenerator = proxyGeneratorBuilder.Build()) { Person p = proxyGenerator.CreateClassProxy<Person>(); Console.WriteLine(p.HelloAsync("yzk").Result); Console.WriteLine(p.Add(1, 2)); } 上面的代码还支持多次降级,方法上标注[HystrixCommand]并且virtual即可: public class Person//需要public类 { [HystrixCommand(nameof(Hello1FallBackAsync))] public virtual async Task<string> HelloAsync(string name)//需要是虚方法 { Console.WriteLine("hello" + name); String s = null; s.ToString(); return "ok"; } [HystrixCommand(nameof(Hello2FallBackAsync))] public virtual async Task<string> Hello1FallBackAsync(string name) { Console.WriteLine("Hello降级1" + name); String s = null; s.ToString(); return "fail_1"; } public virtual async Task<string> Hello2FallBackAsync(string name) { Console.WriteLine("Hello降级2" + name); return "fail_2"; } [HystrixCommand(nameof(AddFall))] public virtual int Add(int i, int j) { String s = null; s.ToString(); return i + j; } public int AddFall(int i, int j) { return 0; } } 细化框架 上面明白了了原理,然后直接展示写好的更复杂的HystrixCommandAttribute,讲解代码。 这是杨中科老师维护的开源项目 github最新地址 https://github.com/yangzhongke/RuPeng.HystrixCore Nuget地址:https://www.nuget.org/packages/RuPeng.HystrixCore 重试:MaxRetryTimes表示最多重试几次,如果为0则不重试,RetryIntervalMilliseconds 表示重试间隔的毫秒数; 熔断:EnableCircuitBreaker是否启用熔断,ExceptionsAllowedBeforeBreaking表示熔断前出现允许错误几次,MillisecondsOfBreak表示熔断多长时间(毫秒); 超时:TimeOutMilliseconds执行超过多少毫秒则认为超时(0表示不检测超时) 缓存:CacheTTLMilliseconds 缓存多少毫秒(0 表示不缓存),用“类名+方法名+所有参数值ToString拼接”做缓存Key(唯一的要求就是参数的类型ToString对于不同对象一定要不一样)。 用到了缓存组件:Install-Package Microsoft.Extensions.Caching.Memory using System; using AspectCore.DynamicProxy; using System.Threading.Tasks; using Polly; namespace RuPeng.HystrixCore { [AttributeUsage(AttributeTargets.Method)] public class HystrixCommandAttribute : AbstractInterceptorAttribute { /// <summary> /// 最多重试几次,如果为0则不重试 /// </summary> public int MaxRetryTimes { get; set; } = 0; /// <summary> /// 重试间隔的毫秒数 /// </summary> public int RetryIntervalMilliseconds { get; set; } = 100; /// <summary> /// 是否启用熔断 /// </summary> public bool EnableCircuitBreaker { get; set; } = false; /// <summary> /// 熔断前出现允许错误几次 /// </summary> public int ExceptionsAllowedBeforeBreaking { get; set; } = 3; /// <summary> /// 熔断多长时间(毫秒) /// </summary> public int MillisecondsOfBreak { get; set; } = 1000; /// <summary> /// 执行超过多少毫秒则认为超时(0表示不检测超时) /// </summary> public int TimeOutMilliseconds { get; set; } = 0; /// <summary> /// 缓存多少毫秒(0表示不缓存),用“类名+方法名+所有参数ToString拼接”做缓存Key /// </summary> public int CacheTTLMilliseconds { get; set; } = 0; //由于CircuitBreaker要求同一段代码必须共享同一个Policy对象。 //而方法上标注的Attribute 对于这个方法来讲就是唯一的对象,一个方法对应一个方法上标注的Attribute对象。 //一般我们熔断控制是针对一个方法,一个方法无论是通过几个 Person 对象调用,无论是谁调用,只要全局出现ExceptionsAllowedBeforeBreaking次错误,就会熔断,这是框架的实现,你如果认为不合理,自己改去。 //我们在Attribute上声明一个Policy的成员变量,这样一个方法就对应一个Policy对象。 private Policy policy; private static readonly Microsoft.Extensions.Caching.Memory.IMemoryCache memoryCache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions()); /// <summary> /// /// </summary> /// <param name="fallBackMethod">降级的方法名</param> public HystrixCommandAttribute(string fallBackMethod) { this.FallBackMethod = fallBackMethod; } public string FallBackMethod { get; set; } public override async Task Invoke(AspectContext context, AspectDelegate next) { //一个HystrixCommand中保持一个policy对象即可 //其实主要是CircuitBreaker要求对于同一段代码要共享一个policy对象 //根据反射原理,同一个方法就对应一个HystrixCommandAttribute,无论几次调用, //而不同方法对应不同的HystrixCommandAttribute对象,天然的一个policy对象共享 //因为同一个方法共享一个policy,因此这个CircuitBreaker是针对所有请求的。 //Attribute也不会在运行时再去改变属性的值,共享同一个policy对象也没问题 lock (this)//因为Invoke可能是并发调用,因此要确保policy赋值的线程安全 { if (policy == null) { policy = Policy.NoOpAsync();//创建一个空的Policy if (EnableCircuitBreaker) //先保证熔断 { policy = policy.WrapAsync(Policy.Handle<Exception>().CircuitBreakerAsync(ExceptionsAllowedBeforeBreaking, TimeSpan.FromMilliseconds(MillisecondsOfBreak))); } if (TimeOutMilliseconds > 0) //控制是否超时 { policy = policy.WrapAsync(Policy.TimeoutAsync(() => TimeSpan.FromMilliseconds(TimeOutMilliseconds), Polly.Timeout.TimeoutStrategy.Pessimistic)); } if (MaxRetryTimes > 0) //如果出错等待MaxRetryTimes时间在执行 { policy = policy.WrapAsync(Policy.Handle<Exception>().WaitAndRetryAsync(MaxRetryTimes, i => TimeSpan.FromMilliseconds(RetryIntervalMilliseconds))); } Policy policyFallBack = Policy .Handle<Exception>() //出错了报错 如果出错就尝试调用降级方法 .FallbackAsync(async (ctx, t) => { //这里拿到的就是ExecuteAsync(ctx => next(context), pollyCtx);这里传的 pollyCtx AspectContext aspectContext = (AspectContext)ctx["aspectContext"]; var fallBackMethod = context.ServiceMethod.DeclaringType.GetMethod(this.FallBackMethod); Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); //不能如下这样,因为这是闭包相关,如果这样写第二次调用Invoke的时候context指向的 //还是第一次的对象,所以要通过Polly的上下文来传递AspectContext //context.ReturnValue = fallBackResult; aspectContext.ReturnValue = fallBackResult; }, async (ex, t) => { }); policy = policyFallBack.WrapAsync(policy); } } //把本地调用的AspectContext传递给Polly,主要给FallbackAsync中使用,避免闭包的坑 Context pollyCtx = new Context();//Context是polly中通过Execute给FallBack、Execute等回调方法传上下文对象使用的 pollyCtx["aspectContext"] = context;//context是aspectCore的上下文 //Install-Package Microsoft.Extensions.Caching.Memory if (CacheTTLMilliseconds > 0) { //用类名+方法名+参数的下划线连接起来作为缓存key string cacheKey = "HystrixMethodCacheManager_Key_" + context.ServiceMethod.DeclaringType + "." + context.ServiceMethod + string.Join("_", context.Parameters); //尝试去缓存中获取。如果找到了,则直接用缓存中的值做返回值 if (memoryCache.TryGetValue(cacheKey, out var cacheValue)) { context.ReturnValue = cacheValue; } else { //如果缓存中没有,则执行实际被拦截的方法 await policy.ExecuteAsync(ctx => next(context), pollyCtx); //存入缓存中 using (var cacheEntry = memoryCache.CreateEntry(cacheKey)) { cacheEntry.Value = context.ReturnValue;//返回值放入缓存 cacheEntry.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMilliseconds(CacheTTLMilliseconds); } } } else//如果没有启用缓存,就直接执行业务方法 { await policy.ExecuteAsync(ctx => next(context), pollyCtx); } } } } 框架不是万能的,不用过度框架,过度框架带来的复杂度陡增,从人人喜欢变成人人恐惧。 结合asp.net core依赖注入 在asp.net core项目中,可以借助于asp.net core的依赖注入,简化代理类对象的注入,不用再自己调用ProxyGeneratorBuilder 进行代理类对象的注入了。 Install-Package AspectCore.Extensions.DependencyInjection 修改Startup.cs的ConfigureServices方法,把返回值从void改为IServiceProvider using AspectCore.Extensions.DependencyInjection; public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSingleton<Person>(); return services.BuildAspectCoreServiceProvider(); } 其 中 services.AddSingleton<Person>(); 表 示 把Person注 入 。 BuildAspectCoreServiceProvider是让aspectcore接管注入。 在Controller中就可以通过构造函数进行依赖注入了: public class ValuesController : Controller { private Person p; public ValuesController(Person p) { this.p = p; } } 通过反射扫描所有Service类,只要类中有标记了CustomInterceptorAttribute的方法都算作服务实现类。为了避免一下子扫描所有类,所以 RegisterServices 还是手动指定从哪个程序集中加载。 public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); RegisterServices(this.GetType().Assembly, services); return services.BuildAspectCoreServiceProvider(); } private static void RegisterServices(Assembly asm, IServiceCollection services) { //遍历程序集中的所有public类型 foreach (Type type in asm.GetExportedTypes()) { //判断类中是否有标注了CustomInterceptorAttribute的方法 bool hasCustomInterceptorAttr = type.GetMethods().Any(m => m.GetCustomAttribute(typeof(CustomInterceptorAttribute)) != null); if (hasCustomInterceptorAttr) { services.AddSingleton(type); } } } 注:此文章是我看杨中科老师的.Net Core微服务第二版和.Net Core微服务第二版课件整理出来的 现在的努力只是为了更好的将来,将来你一定不会后悔你现在的努力。一起加油吧!!! C#/.NetCore技术交流群:608188505欢迎加群交流 如果您认为这篇文章还不错或者有所收获,您可以点击右下角的【推荐】按钮精神支持,因为这种支持是我继续写作,分享的最大动力!

优秀的个人博客,低调大师

轻量级 ioc/aop 框架 loveqq,支持 ioc 容器全量热刷新,可通过接口实现实时热更新类实现

全量刷新上下文代码示例: package com.kfyty.demo; import com.kfyty.loveqq.framework.boot.K; import com.kfyty.loveqq.framework.boot.context.ContextRefresher; import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired; import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication; import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component; import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnProperty; import com.kfyty.loveqq.framework.core.autoconfig.env.PropertyContext; import com.kfyty.loveqq.framework.core.utils.IOC; import com.kfyty.loveqq.framework.web.core.annotation.GetMapping; import com.kfyty.loveqq.framework.web.core.annotation.RestController; import com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc; import lombok.extern.slf4j.Slf4j; @Slf4j @EnableWebMvc @RestController @BootApplication public class Main { public static void main(String[] args) throws Exception { K.run(Main.class, args); } @Autowired private UserService userService; @Autowired private PropertyContext propertyContext; /** * 调用接口方法 */ @GetMapping public String sayHello() { return userService.hello(); } /** * 通过可刷新的配置属性切换 UserService 实现类 * * @param impl 条件配置属性 */ @GetMapping public String switchUserImpl(String impl) { // 设置可刷新的属性,刷新上下文时不会丢失 propertyContext.setRefreshProperty("user.service.impl", impl); // 全量刷新上下文,由于类已加载,刷新过程会很快 ContextRefresher.refresh(IOC.getApplicationContext()); // 刷新是异步的,这里返回页面提示 return "ok"; } /** * 接口定义 */ public interface UserService { String hello(); } /** * 扩展实现 */ @Component @ConditionalOnProperty(value = "user.service.impl", havingValue = "extension") public static class ExtensionUserService extends DefaultUserService { @Override public String hello() { return "internal"; } } /** * 默认实现 */ @Component @ConditionalOnProperty(value = "user.service.impl", havingValue = "default", matchIfMissing = true) public static class DefaultUserService implements UserService { @Override public String hello() { return "default"; } } } 上述代码启动 main 方法后: 先访问:http://localhost:8080/sayHello,将返回 default 然后访问:http://localhost:8080/switchUserImpl?impl=internal,此时将进行ioc容器的全量刷新 然后再访问:http://localhost:8080/sayHello,将返回 internal,原因是条件注解生效,实现类变化了! 从而实现了热更新类实现,这是 @RefreshScope 注解所无法实现的效果。 并且由于是热更新,所以ioc容器的刷新很快完成(ms 级别),相比重新启动耗时更短。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册