利用C#的RealProxy实现AOP


发表于 修改于 后端随手写写 522 字 3 分钟

效果

原类(必须是MarshalByRefObject的派生类)

public class Person : MarshalByRefObject {
public string Say(string word) {
return $"Hello,{word}!";
}
}

切片类

public class PersonAspect {
[Around(typeof(string))]
public void Say(JoinPoint joinPoint) {
var args = joinPoint.args;
Console.WriteLine("调用之前:收到了" + args[0]);
var result = joinPoint.Procced();
Console.WriteLine("调用之后:结果是" + result);
}
}

使用

static void Main(string[] args) {
Person p = (Person) new AopRealProxy(typeof(Person), null, typeof(PersonAspect), null).GetTransparentProxy();
p.Say("World");
Console.Read();
}

输出结果

调用之前:收到了World
调用之后:结果是Hello,World!

实现

定义JoinPoint(切点类)

using System;
using System.Runtime.Remoting.Messaging;
namespace KanameFramework.Core.Aop {
/// <summary>
/// 切点
/// </summary>
public class JoinPoint {
public object[] args;
private Func<IMethodReturnMessage> procced;
public IMethodReturnMessage MethodReturnMessage { get; private set; }
public JoinPoint(object[] args, Func<IMethodReturnMessage> procced) {
this.args = args;
this.procced = procced;
}
/// <summary>
/// 执行原方法
/// </summary>
public object Procced() {
MethodReturnMessage = procced.Invoke();
return MethodReturnMessage.ReturnValue;
}
}
}

定义Attribute

using System;
namespace KanameFramework.Core.Aop.Attributes {
/// <summary>
/// 标记此方法为环绕通知
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AroundAttribute: Attribute {
/// <summary>
/// 方法的参数列表,用于寻找(重载的)方法
/// </summary>
public Type[] ArgTypes { get; private set; }
public AroundAttribute() {
ArgTypes = new Type[0];
}
public AroundAttribute(params Type[] argTypes) {
ArgTypes = argTypes;
}
}
}

继承RealProxy,并实现基本功能

using KanameFramework.Core.Aop.Attributes;
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Security.Permissions;
namespace KanameFramework.Core.Aop {
/// <summary>
/// 提供动态代理的基本功能
/// </summary>
public class AopRealProxy : RealProxy {
private string URI;
private Type aspectType;
private object aspectInstance;
/// <summary>
/// 组合目标类和切面类
/// </summary>
/// <param name="type">目标类</param>
/// <param name="typeIns">目标类实例</param>
/// <param name="aspectType">切面类</param>
/// <param name="aspectIns">切面类实例</param>
[PermissionSet(SecurityAction.LinkDemand)]
public AopRealProxy(Type type,object typeIns,Type aspectType, object aspectIns) : base(type) {
this.aspectType = aspectType;
this.aspectInstance = aspectIns??Activator.CreateInstance(aspectType);
URI = RemotingServices.Marshal((MarshalByRefObject)(typeIns??Activator.CreateInstance(type))).URI;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
public override IMessage Invoke(IMessage message) {
//获取参数值
var properties = message.Properties;
var methodName = (string)properties["__MethodName"];
var argTypes = (Type[])properties["__MethodSignature"];
var args = (object[])properties["__Args"];
//切面类匹配到的的方法
var matchAspectMethods = aspectType.GetMethods(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance).Where(m=> {
if (!m.Name.Equals(methodName)) return false;
var attr = m.GetCustomAttribute<AroundAttribute>();
if (attr == null) return false;
return attr.ArgTypes.SequenceEqual(argTypes);
});
//确定执行前设置uri
properties["__Uri"] = URI;
//切面类没有对应方法直接返回
if (matchAspectMethods.Count()<1)
return (IMethodReturnMessage)ChannelServices.SyncDispatchMessage(message);
//交给切面类执行
var joinPoint = new JoinPoint(args, () => (IMethodReturnMessage)ChannelServices.SyncDispatchMessage(message));
matchAspectMethods.First().Invoke(aspectInstance, new object[] { joinPoint });
return joinPoint.MethodReturnMessage;
}
}
}

评论