|
AOP
面向切面编程AOP的对面向对象编程OOP的一个补充,它的特点是将系统逻辑和业务逻辑采取《非侵入式》分离。我们把系统封装成一个一个的切面(单一职责)进行顺意编排组合,插入(织入)到业务逻辑的执行过程(织入点)。
系统逻辑:异常处理,身份认证,授权,mvc,数据校验,事务处理。
业务逻辑:就是我们的业务Service。
切面:用于封装系统逻辑,比如身份认证filter,或者中间件
切入点:就是管道的位置。名词
织入:就是插入到管道的切入点的过程。动词
AOP的特点:
1.非侵入式
2.低耦合
3.代码服用
4.单一职责
5.可插拔
实现方式:
1.管道链,比如aspnetcore的中间件,mvc中的Filter
2.静态代理:思考如何加强一个List,使得在插入时打印日志?
3.动态代理:Emit
4.三种模式都需要通过一些技术进行串联,实现链式调用,构成管道。静态代理通过接口进行串联,动态代理通过反射进行串联。管道通过接口获取委托进行串联。委托本质也是接口。
代理:就是增强,代理对象必须尽量实现目标对象的功能,在此基础上进行加强。比如vpn,你的电脑的网络就是目标对象,vpn就是代理服务,代理服务起码得实现联网功能吧,然后对网络进行加强,访问到一些你的本机网络访问不到的东西。
掌握了AOP技术我们可以实现很多好处,做到非侵入式的增强业务逻辑。- //侵入式方案,把这个看懂。后面就是围绕这个开展,高出非侵入式
- public static void A()
- {
- Console.WriteLine("A:开始");
- B();//A,B的调用关系强行绑定,有侵入性
- Console.WriteLine("A:结束");
- }
- public static void B()
- {
- Console.WriteLine("B:开始");
- C();
- Console.WriteLine("B:结束");
- }
- public static void C()
- {
- Console.WriteLine("Hello World");
- }
- public static void Dobasic()
- {
- A();
- }
复制代码 静态代理
1.代理就是实现目标对象的标准(接口),在目标方法执行之前和之后进行逻辑织入的过程。代理的目的就是为了加强。代理不负责实现接口,一般通过target来实现接口。即代理除了可以增强之外还能简化接口的实现。
2.静态代理就是在代理之前就已经确定了代理关系。需要自己实现标准并编写代理类。代理类中的逻辑只能代理一些标准(实现多个接口)。无法代理所有标准。
3.静态代理可以实现不改变目标对象的源码的情况下进行加强,完成目标对象的能力,并且在此基础之上进行加强。
4.可以简化实现的成本,不改变业务代码,只需要编写额外的增强逻辑。不需要关系具体的业务实现。
5.代理和代理直接通过接口可以进行互相代理,链式调用,顺意编排组合,实现系统的多样化。- /// <summary>
- /// 定义标准1
- /// </summary>
- public interface IPhoneService
- {
- string Mobile { get; set; }
- string Message { get; set; }
- void Send();
- }
- //实现标准-不是代理模式
- public class PhoneService : IPhoneService
- {
- public string Mobile { get; set; }
- public string Message { get; set; }
- public PhoneService(string mobile, string message)
- {
- Mobile = mobile;
- Message = message;
- }
- public virtual void Send()
- {
- Console.WriteLine($"已发送短信:{Message}到{Mobile}");
- }
- }
- //代理模式:
- //1.实现目标对象的标准
- //2.依赖目标对象(被代理对象)
- //3.业务织入
- public class PhoneServiceProxy : IPhoneService//实现标准
- {
- private readonly IPhoneService _target;
- public PhoneServiceProxy1(IPhoneService target)
- {
- _target = target;
- }
- public string Mobile { get => _target.Mobile; set => _target.Mobile = value; }
- public string Message { get => _target.Message; set => _target.Message = value; }
- /// <summary>
- /// 子类重写父类方法
- /// </summary>
- public void Send()
- {
- Console.WriteLine("Proxy1:已对手机号进行验证");
- _target.Send();
- Console.WriteLine("Proxy1:已确认对方已经收到");
- }
- }
复制代码 动态代理
Castle.Core
动态代理和静态代理的区别就是,代理类由工具生成,需要在运行时确认代理类已经代理关系。代理类中的逻辑写到拦截器里面,可以进行复用。缺点是性能差。里面涉及到大量反射技术。
Castle.Core:原理就是通过子类继承父类或者实现父类标准,通过Castle.Core自动帮你生成代理类,通过一个叫拦截器的东西编写代理类要执行的业务逻辑。Castle.Core会帮你生成代理类,并将拦截器织入到代理类中。
动态代理通过invocation进行串联,本质是反射。- /// <summary>
- /// 定义标准1
- /// </summary>
- public interface IPhoneService
- {
- string Mobile { get; set; }
- string Message { get; set; }
- void Send();
- }
- /// <summary>
- /// 定义标准2
- /// </summary>
- public interface IEmailService
- {
- string Email { get; set; }
- string Message { get; set; }
- void Send();
- }
- /// <summary>
- /// 业务逻辑1
- /// </summary>
- public class PhoneService : IPhoneService
- {
- public string Mobile { get; set; }
- public string Message { get; set; }
- public PhoneService(string mobile, string message)
- {
- Mobile = mobile;
- Message = message;
- }
- public virtual void Send()
- {
- Console.WriteLine($"已发送短信:{Message}到{Mobile}");
- }
- }
- /// <summary>
- /// 业务逻辑2
- /// </summary>
- public class EmailService : IEmailService
- {
- public string Email { get; set; }
- public string Message { get; set; }
- public EmailService(string email, string message)
- {
- Email = email;
- Message = message;
- }
- public virtual void Send()
- {
- Console.WriteLine($"已发送邮件:{Message}到{Email}");
- }
- }
- /// <summary>
- /// 代理1:任意标准
- /// </summary>
- public class ShareInterceptor1 : IInterceptor
- {
- public void Intercept(IInvocation invocation)
- {
- Console.WriteLine("Proxy1:已对接收方进行验证");
- invocation.Proceed();//执行下一个拦截器或者目标方法
- Console.WriteLine("Proxy1:已确认对方已经收到");
- }
- }
- /// <summary>
- /// 代理2:任意标准
- /// </summary>
- public class ShareInterceptor2 : IInterceptor
- {
- public void Intercept(IInvocation invocation)
- {
- Console.WriteLine("Proxy2:已开启加速通道");
- invocation.Proceed();//执行下一个拦截器或者目标方法
- Console.WriteLine("Proxy2:已关闭加速通道");
- }
- }
- //通过Castel生成代理类
- public static void TestDynamicProxy1()
- {
- //创建代理生成器
- var generator = new ProxyGenerator();
- var target1 = new PhoneService("10088", "你好啊!");
- var target2 = new EmailService("1123@116.com", "你好啊!");
- var interceptor1 = new ShareInterceptor1();//代理1,拦截器1,不需要去实现指定的标准
- var interceptor2 = new ShareInterceptor2();//代理2,拦截器2,不需要去实现指定的标准
- //使用代理1和代理2去代理手机的标准
- IPhoneService dynamicProxy1 = generator.CreateInterfaceProxyWithTarget<IPhoneService>(target1, interceptor1, interceptor2);
- dynamicProxy1.Send();
- //代理邮件的标准
- IEmailService dynamicProxy2 = generator.CreateInterfaceProxyWithTarget<IEmailService>(target2, interceptor1, interceptor2);
- dynamicProxy2.Send();
- }
复制代码 手写Castle.Core的代理类
思考:
generator创建的是什么类型的实列?显然不可能是已有的类型。因为它把拦截器织入进去了。而且没有修改我们的代码,站在面向对象的角度来看只能是实现了我们的接口,Emit动态实现了下面的代码
多个拦截器和目标对象(被代理者)通过Invocation进行串联。Invocation中的Arguments完成链式调用。
手动通过Invocation进行串联- //假设有三个拦截器
- //第一个拦截器invocation1:Proxy=interceptor2,Method=Intercept,argument=invocation2
- //第二个拦截器invocation2:Proxy=interceptor3,Method=Intercept,argument=invocation3
- //第三个拦截器invocation2:Proxy=target,Method=method,argument=arguments
- //手动实现
- public IInvocation GetInvocation(Stack<IInterceptor> stack, object target, Method method, objuect arguments)
- {
- var invocation1 = new Invocation()
- {
- Proxy = interceptor2,
- Method = typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept)),
- Arguments = new object[]
- {
- new Invocation()
- {
- Proxy = interceptor3,
- Method = typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept)),
- Arguments = new object[]
- {
- new Invocation()
- {
- Proxy = target,
- Method = method,
- Arguments = arguments
- }
- }
- }
- }
- }
- }
- //递归实现
- public IInvocation GetInvocation(Stack<IInterceptor> stack, object target, Method method, objuect arguments)
- {
- if(stack.Any())
- {
- var proxy = stack.Pop();
- return new Invocation()
- {
- Proxy = proxy,
- Method = typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept)),
- Agrumtns = GetInvocation(stack,method,argumtns)
- };
- }
- else
- {
- return new Invocation()
- {
- Proxy = target,
- Method = method,
- Agrumtns = arguments
- };
- }
- }
复制代码 EMIT实现
- //链路器
- public class EmitInvocation
- {
- private object? proxy;
- private MethodInfo? method;
- private object[]? arguments;
- public EmitInvocation(object? proxy, MethodInfo? method, object[]? arguments)
- {
- this.proxy = proxy;
- this.method = method;
- this.arguments = arguments;
- }
- public void Proceed()
- {
- method?.Invoke(proxy, arguments);
- }
- }
- //拦截器
- public interface IEmitInteceptor
- {
- void Intercept(EmitInvocation invocation);
- }
- //实现拦截器1
- public class EmitInteceptor1 : IEmitInteceptor
- {
- public void Intercept(EmitInvocation invocation)
- {
- Console.WriteLine("prox1:start");
- invocation.Proceed();
- Console.WriteLine("prox1:end");
- }
- }
- //实现拦截器1
- public class EmitInteceptor2 : IEmitInteceptor
- {
- public void Intercept(EmitInvocation invocation)
- {
- Console.WriteLine("prox2:start");
- invocation.Proceed();
- Console.WriteLine("prox2:end");
- }
- }
- //该工具类帮助我们少写emit代码
- public static class EmitProxyInvoker
- {
- public static EmitInvocation GetNextInvocation(Stack<IEmitInteceptor> stack, MethodInfo method, object target, object[] arguments)
- {
- if (stack.Any())
- {
- var next = stack.Pop();
- arguments = new object[]
- {
- //递归
- GetNextInvocation(stack, method, target, arguments)
- };
- return new EmitInvocation(next, typeof(IEmitInteceptor).GetMethod(nameof(IEmitInteceptor.Intercept)), arguments);
- }
- else
- {
- return new EmitInvocation(target, method, arguments);
- }
- }
- public static void Invoke(IEmitInteceptor[] interceptors, MethodInfo method, object target, object[] arguments)
- {
- var stack = new Stack<IEmitInteceptor>(interceptors.Reverse());
- if (stack.Any())
- {
- var item = stack.Pop();
- var invocation = GetNextInvocation(stack, method, target, arguments);
- item.Intercept(invocation);
- }
- else
- {
- method.Invoke(target, arguments);
- }
- }
- }
- //业务接口
- public interface IEmitService
- {
- void Send();
- }
- //将来要生成的代理类
- public class EmitServiceProxy : IEmitService
- {
- private object _target;
- private IEmitInteceptor[] _inteceptors;
- public EmitService()
- {
- }
- public void Send()
- {
- var method = _target.GetType().GetMethod(nameof(EmitService.Send));
- var arguments = new object[] { };
- EmitProxyInvoker.Invoke(_inteceptors, method, _target, new object[] { });
- }
- }
- public static class EmitProxyGenerator
- {
- static AssemblyBuilder _assemblyBuilder;
- static ModuleBuilder _moduleBuilder;
- static EmitProxyGenerator()
- {
- //创建一个程序集
- var assemblyName = new AssemblyName("DynamicProxies");
- _assemblyBuilder = AssemblyBuilder
- .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
- //创建一个模块
- _moduleBuilder = _assemblyBuilder.DefineDynamicModule("Proxies");
- }
- public static TInterface Create<TInterface>(object target, params IEmitInteceptor[] inteceptor)
- where TInterface : class
- {
-
- #region 定义类型
- //定义一个class,如果这个类型已定义直接返回,缓存
- var typeName = $"{target.GetType().Name}EmitProxy";
- var typeBuilder = _moduleBuilder.DefineType(
- typeName,
- TypeAttributes.Public,typeof(object),
- new Type[]
- {
- typeof(TInterface)
- });
- #endregion
- #region 定义字段
- //定义字段
- var targetFieldBuilder = typeBuilder.DefineField("target", typeof(object), FieldAttributes.Private);
- var inteceptorFieldBuilder = typeBuilder.DefineField("inteceptor", typeof(IEmitInteceptor[]), FieldAttributes.Private);
- #endregion
- #region 定义构造器
- //定义构造器
- var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.ExplicitThis, new Type[]
- {
- typeof(object),
- typeof(IEmitInteceptor[])
- });
- //获取IL编辑器
- var generator = constructorBuilder.GetILGenerator();
- generator.Emit(OpCodes.Ldarg_0);//加载this
- generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes) ?? throw new InvalidOperationException());
- generator.Emit(OpCodes.Nop);
- generator.Emit(OpCodes.Nop);
- // this.age = age;
- generator.Emit(OpCodes.Ldarg_0);//加载this
- generator.Emit(OpCodes.Ldarg_1);//加载target参数
- generator.Emit(OpCodes.Stfld, targetFieldBuilder);//加载target字段
- // this.name = name;
- generator.Emit(OpCodes.Ldarg_0);//加载this
- generator.Emit(OpCodes.Ldarg_2);//加载inteceptor参数
- generator.Emit(OpCodes.Stfld, inteceptorFieldBuilder);//加载inteceptor字段
- generator.Emit(OpCodes.Ret);
- #endregion
- #region 实现接口
- var methods = typeof(TInterface).GetMethods();
- foreach (var item in methods)
- {
- var parameterTypes = item.GetParameters().Select(s => s.ParameterType).ToArray();
- var methodBuilder = typeBuilder.DefineMethod(item.Name,
- MethodAttributes.Public| MethodAttributes.Final |MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.HideBySig,
- CallingConventions.Standard|CallingConventions.HasThis,
- item.ReturnType,
- parameterTypes);
- var generator1 = methodBuilder.GetILGenerator();
- //init
- var methodInfoLocal = generator1.DeclareLocal(typeof(MethodInfo));
- var argumentLocal = generator1.DeclareLocal(typeof(object[]));
- generator1.Emit(OpCodes.Nop);
- generator1.Emit(OpCodes.Ldarg_0);
- generator1.Emit(OpCodes.Ldfld, targetFieldBuilder);
- generator1.Emit(OpCodes.Callvirt, typeof(Type).GetMethod(nameof(Type.GetType),Type.EmptyTypes));
- generator1.Emit(OpCodes.Ldstr, item.Name);
- generator1.Emit(OpCodes.Callvirt, typeof(Type).GetMethod(nameof(Type.GetMethod), new Type[] { typeof(string) }));
- generator1.Emit(OpCodes.Stloc, methodInfoLocal);
- generator1.Emit(OpCodes.Ldc_I4_0);
- generator1.Emit(OpCodes.Newarr, typeof(object));
- generator1.Emit(OpCodes.Stloc, argumentLocal);
- generator1.Emit(OpCodes.Ldarg_0);
- generator1.Emit(OpCodes.Ldfld, inteceptorFieldBuilder);
- generator1.Emit(OpCodes.Ldloc_0);
- generator1.Emit(OpCodes.Ldarg_0);
- generator1.Emit(OpCodes.Ldfld, targetFieldBuilder);
- generator1.Emit(OpCodes.Ldc_I4_0);
- generator1.Emit(OpCodes.Newarr, typeof(object));
- generator1.Emit(OpCodes.Call, typeof(EmitProxyInvoker).GetMethod(nameof(EmitProxyUtil.Invoke)));
- generator1.Emit(OpCodes.Nop);
- generator1.Emit(OpCodes.Ret);
- }
- #endregion
- //创建:这个type可以用一个线程安全的字典缓存起来,第二次需要这个代理类的时候,就不需要在生成一次emit代码了。
- var type = typeBuilder.CreateType() ?? throw new ArgumentException();
- var instance = Activator.CreateInstance(type, target, inteceptor);
- return (TInterface)instance;
- }
- }
复制代码 容器支持
- public class DbContext
- {
-
- }
- public class AService
- {
- public DbContext DbContext { get; }
-
- public AService(DbContext context)
- {
- DbContext = context;
- }
- }
- public static void Test()
- {
- var services = new ServiceCollection();
- services.AddScoped<DbContext>();
- var generator = new ProxyGenerator();
- //泛型-不支持动态注入
- services.AddScoped(sp =>
- {
- //通过容器解析依赖
- var target = ActivatorUtilities.CreateInstance<AService>(sp);
- return generator.CreateClassProxyWithTarget(target);
- });
- //反射-可以扫描批量注入
- services.AddScoped(typeof(AService), sp =>
- {
- //通过容器解析依赖
- var target = ActivatorUtilities.CreateInstance(sp, typeof(AService));
- return generator.CreateClassProxyWithTarget(target);
- });
- }
复制代码 管道方式
委托方式
1.通过委托构建管道- public delegate Task RequestDelegate(HttpContext context);
- public class HttpContext
- {
- }
- public class ApplicationBuilder
- {
- private readonly List<Func<RequestDelegate, RequestDelegate>> _componen
- public void Use(Func<RequestDelegate, RequestDelegate> middleware)
- {
- _components.Add(middleware);
- }
- public void Use(Func<HttpContext, Func<Task>, Task> middleware)
- {
- _components.Add((next) =>
- {
- return async c =>
- {
- await middleware(c, () => next(c));
- };
- });
- }
- public void Use(Func<HttpContext, RequestDelegate, Task> middleware)
- {
- _components.Add((next) =>
- {
- return async c =>
- {
- await middleware(c, next);
- };
- });
- }
- public void Run(RequestDelegate handler)
- {
- _components.Add((next) =>
- {
- return async c =>
- {
- await handler(c);
- };
- });
- }
- //构建管道
- public RequestDelegate Build()
- {
- RequestDelegate app = c =>
- {
- throw new InvalidOperationException("无效的管道");
- };
- for (int i = _components.Count - 1; i > -1; i--)
- {
- app = _components[i](app);
- }
- return app;
- }
- }
复制代码 接口方式
2.通过接口构建管道
有点类型动态代理,动态代理是通过Invocation进行反射,而下面的方式是通过接口的方式。反射更加灵活,性能不行。- public interface IChain
- {
- Task NextAsync();
- }
- public class FilterChain : IChain
- {
- private readonly IFilter _filter;
- private readonly HttpContext _context;
- private readonly IChain _next;
- public FilterChain(IFilter filter, HttpContext context, IChain next)
- {
- _filter = filter;
- _context = context;
- _next = next;
- }
- public async Task NextAsync()
- {
- await _filter.InvokeAsync(_context, _next);
- }
- }
- public class ServletChain : IChain
- {
- private readonly IServlet _servlet;
- private readonly HttpContext _context;
- public ServletChain(IServlet servlet, HttpContext context)
- {
- _servlet = servlet;
- _context = context;
- }
- public async Task NextAsync()
- {
- await _servlet.DoPostAsync(_context);
- }
- }
- public interface IFilter
- {
- Task InvokeAsync(HttpContext context, IChain chain);
- }
- public class Filter1 : IFilter
- {
- public async Task InvokeAsync(HttpContext context, IChain chain)
- {
- Console.WriteLine("身份认证开始");
- await chain.NextAsync();
- Console.WriteLine("身份认证结束");
- }
- }
- public class Filter2 : IFilter
- {
- public async Task InvokeAsync(HttpContext context, IChain chain)
- {
- Console.WriteLine("授权认证开始");
- await chain.NextAsync();
- Console.WriteLine("授权认证结束");
- }
- }
- public interface IServlet
- {
- Task DoPostAsync(HttpContext context);
- }
- public class HelloServlet : IServlet
- {
- public Task DoPostAsync(HttpContext context)
- {
- Console.WriteLine("Hello World");
- return Task.CompletedTask;
- }
- }
- public class WebHost
- {
- private readonly List<IFilter> _filters = new List<IFilter>();
- public void AddFilter(IFilter filter)
- {
- _filters.Add(filter);
- }
- public void Exeucte(HttpContext context, IServlet servlet)
- {
- //自行处理filter为空的情况,就是直接执行serlvet就好了
- var stack = new Stack<IFilter>(_filters);
- var filter = stack.Pop();
- var chain = GetFilterChain(context, servlet,stack);
- filter.InvokeAsync(context, chain);
- }
- private IChain GetFilterChain(HttpContext context, IServlet servlet, Stack<IFilter> filters)
- {
- if (filters.Any())
- {
- var filter = filters.Pop();
- var chain = GetFilterChain(context, servlet, filters);
- return new FilterChain(filter, context, chain);
- }
- else
- {
- return new ServletChain(servlet, context);
- }
- }
- }
复制代码 AOP总结
1.代理分为静态代理和动态代理,静态代理需要自己编写代理类,动态代理由框架生成代理类。
2.代理和管道都需要通过接口(委托)进行链接,串联,形成链式调用。
3.动态代理慎用,因为涉及到反射技术,而且对异步支持不友好。
4.静态代理常用于加强已有类型,比如接口要求一个IList,我们已经拥有了一个list实列,我们需要在在list.Add方法时打印日志,此时我们可以不改变原有的list,通过静态代理实现IList接口来进行对原有的list加强。这个方法在更改框架的时候很有用。我们可以对原有的HttpContext,进行加强。
来源:https://www.cnblogs.com/chaeyeon/archive/2023/02/14/17119566.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|