自己实现简单的AOP(二)引入Attribute 为方法指定增强对象

时间:2022-11-01 09:28:14

话续前文 : 自己实现简单的AOP(一)简介

在前一篇文章中,对AOP的实现方式做了一个简单介绍。接下来,引入Attribute 为方法指定增强对象,由此实现一个简单的AOP。

注意:指定的是增强对象,“对象”,也就是说Attribute标记,标记的其实是一个对象。由此、使用多态便可轻松实现增强的扩展。

自定义的Attribute

    /// <summary>
/// 为方法标记指定的增强对象
/// <para>指定的增强,可通过代理 DelayProxy 织入</para>
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class AdviceAttribute : Attribute
{
/// <summary>
/// 增强对象
/// </summary>
public AdviceAbstract Advice { get; private set; } /// <summary>
/// 使用指定类型的默认增强对象
/// <para>如果类型为空 则不使用任何增强</para>
/// </summary>
/// <param name="type"></param>
public AdviceAttribute(Type type)
: this(type, string.Empty)
{ } /// <summary>
/// 使用公有静态方法名初始化指定类型的增强对象
/// <para>如果类型为空 则不使用任何增强</para>
/// </summary>
/// <param name="type">类型</param>
/// <param name="methodName">
/// 公有静态方法名
/// <para>如果方法名为空,调用默认构造函数</para>
/// </param>
public AdviceAttribute(Type type, string methodName)
{
// 如果类型为空 则不使用任何增强
if (type == null)
{
this.Advice = null;
return;
} if (string.IsNullOrWhiteSpace(methodName))
{
this.Advice = Activator.CreateInstance(type) as AdviceAbstract;
return;
} this.Advice = type.InvokeMember(
methodName,
System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Static,
null, null, null) as AdviceAbstract;
} #region 以下两种方式效果不是很好,不推荐使用,故 构造函数私有化 /// <summary>
/// 使用参数列表初始化指定类型的增强对象
/// </summary>
/// <param name="type">类型</param>
/// <param name="objs">参数列表</param>
private AdviceAttribute(Type type, params object[] objs)
{
this.Advice = Activator.CreateInstance(type, objs) as AdviceAbstract;
} /// <summary>
/// 使用命名参数初始化指定类型的增强对象
/// </summary>
/// <param name="namedParameter">
/// 以 冒号 和 分号 分割的形参的命名参数列表
/// <para>支持的数据类型有:string, int, bool 及 可通过静态方法Parse 反序列化的类型</para>
/// </param>
/// <param name="type"></param>
private AdviceAttribute(string namedParameter, Type type)
{
this.Advice = ReflectionUtil.InvokeConstructor(type, namedParameter) as AdviceAbstract;
} #endregion }

Attribute

增强的抽象类 和 自定义的增强

    /// <summary>
/// 抽象的增强类
/// </summary>
public abstract class AdviceAbstract
{
public abstract IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage);
} public class MyAdvice : AdviceAbstract
{
public override IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage)
{
this.BeforeInvoke(target); IMessage message = DelayProxyUtil.InvokeBeProxy(target, callMessage); this.AfterInvoke(target); return message;
} protected virtual void BeforeInvoke(MarshalByRefObject target)
{
Console.WriteLine("Before");
} protected virtual void AfterInvoke(MarshalByRefObject target)
{
Console.WriteLine("After");
} }

Advice

有了如上的两个组件,再借助代理类 DelayProxy<T>,将增强织入,简单的AOP就已经初具原形了。

    /// <summary>
/// 支持泛型、支持延迟初始化的代理类, 可为 MarshalByRefObject 的子类型提供代理
/// <para>在执行代理的过程中,获取 AdviceAttribute 所指定的增强,并织入该增强</para>
/// </summary>
public class DelayProxy<T> : RealProxy where T : MarshalByRefObject
{
private static object objLock = new object(); /// <summary>
/// 被代理的对象
/// </summary>
private T target; /// <summary>
/// 是否延迟初始化
/// <para>True:延迟, False: 不延迟</para>
/// </summary>
private readonly bool delay; public DelayProxy(T target, bool delay)
: base(typeof(T))
{
this.target = target;
this.delay = delay;
} /// <summary>
/// 调用被代理对象
/// <para>支持 out ref 参数</para>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public override IMessage Invoke(IMessage msg)
{
if (this.delay && this.target == null)
{
lock (objLock)
{
if (this.delay && this.target == null)
{
T instance = Activator.CreateInstance(typeof(T)) as T; // 自动装配属性
// 为属性对象启用代理,并延迟初始化被代理的对象
// DelayProxyUtil.AutowiredProperties(instance); this.target = instance;
}
}
} IMethodCallMessage callMessage = (IMethodCallMessage)msg; AdviceAttribute attri = ReflectionUtil.GetCustomAttribute<AdviceAttribute>(callMessage.MethodBase); if (attri != null && attri.Advice != null)
{
return attri.Advice.Invoke(this.target, callMessage);
} return DelayProxyUtil.InvokeBeProxy(this.target, callMessage);
} }

DelayProxy

附源码(MVC4的项目 没有packages文件夹):http://files.cnblogs.com/files/08shiyan/AOPDemo.zip

该源码中还实现了被代理对象的延迟初始化。

未完待续...