自己实现简单的AOP(二)引入Attribute 为方法指定增强对象
话续前文 : 自己实现简单的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
该源码中还实现了被代理对象的延迟初始化。
未完待续...
自己实现简单的AOP(二)引入Attribute 为方法指定增强对象的更多相关文章
- 自己实现简单的AOP(一)简介
AOP 和 OOP,在我看来是两种相辅相成的技术,作为OOP的补充,AOP 有着自己特殊的应用场景. 假设,我们需要在Service层实现以下几项基本功能: /// <para>1.自动管 ...
- aop学习总结二------使用cglib动态代理简单实现aop功能
aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...
- 从Unity中的Attribute到AOP(二)
上一篇文章我们初步了解了一下Attributes的含义,并且使用系统自带的Attributes写了点代码.在进一步解剖我们的代码之前,我觉得有个概念可能需要巩固一下:什么是元数据? 我们知道C#代码会 ...
- 动手造轮子:实现一个简单的 AOP 框架
动手造轮子:实现一个简单的 AOP 框架 Intro 最近实现了一个 AOP 框架 -- FluentAspects,API 基本稳定了,写篇文章分享一下这个 AOP 框架的设计. 整体设计 概览 I ...
- 自己实现简单的AOP(三) 实现增强四项基本功能
前面的两篇随笔,都是只是个铺垫,真正实现增强四项基本功能的重头戏,在本篇随笔中, 本文将通过AOP实现如下的四个基本功能: /// <para>1.自动管理数据库连接[可选]</pa ...
- 自己实现简单的AOP(四)自动初始化代理对象
前面三篇随笔,已经完成了AOP的核心功能,但 代理对象的初始化还是有些麻烦,本文将解决该问题. Demo 片段如下: public class HomeController : Controller ...
- spring---aop(9)---Spring AOP中引入增强
写在前面 Spring将introduction通知看作一种特殊类型的拦截通知.用Spring的行话来讲,对方法的增强叫做Wearing(织入),而对类的增强叫introduction(引入).Int ...
- 从头认识Spring-3.1 简单的AOP日志实现-某方法之前的前后记录日志
这一章节我们引入简单的AOP日志实现. 1.domain 蛋糕类: package com.raylee.my_new_spring.my_new_spring.ch03.topic_1_1; pub ...
- 从头认识Spring-3.4 简单的AOP日志实现-扩展添加检查订单功能,以便记录并检測输入的參数
这一章节我们再上一个章节的基础上加上一个检查订单功能 1.domain 蛋糕类: package com.raylee.my_new_spring.my_new_spring.ch03.topic_1 ...
随机推荐
- 突破瓶颈,对比学习:Eclipse开发环境与VS开发环境的调试对比
曾经看了不少Java和Android的相关知识,不过光看不练易失忆,所以,还是写点文字,除了加强下记忆,也证明我曾经学过~~~ 突破瓶颈,对比学习: 学习一门语言,开发环境很重,对于VS的方形线条开发 ...
- c#开源消息队列中间件EQueue 教程
一.简介 EQueue是一个参照RocketMQ实现的开源消息队列中间件,兼容Mono,具体可以参看作者的文章<分享一个c#写的开源分布式消息队列equeue>.项目开源地址:https: ...
- 标准数据源访问库 - JayData
JayData 是一个标准的.跨平台的库和方法,用于访问和操作各种不同的数据源,最适合用于 JavaScript 和 HTML5 应用. 官方网站:http://jaydata.org/ ASP.N ...
- HTML5- Canvas入门(二)
上篇文章我们了解了canvas的定义.获取和基础的绘图操作,其中的绘图功能我们讲解了线段绘制.上色.描边等方面知识点. 今天我们来讲讲矩形(Rectangle)和多边形的绘制. 矩形的绘制一共有两个口 ...
- 《CLR.via.C#第三版》第二部分第8,9章节读书笔记(四)
三种类型的构造方法: 实例构造器(引用类型):实例构造器永远不能被继承(所以方法前没有修饰符):如果类的修饰符为static(sealed和abstract),编译器根本不会在类的定义中生成一个默认构 ...
- 使用VS+VisualGDB编译调试Linux程序
Linux程序开发变得越来越多,越来越多的程序.产品需要跨平台,甚至有些开源项目只支持Linux平台,所以掌握Linux开发变得越来越重要. 但是对于习惯了Windows下的开发,使用了VS这个宇宙第 ...
- .NET陷阱之六:从枚举值持久化带来大量空间消耗谈起
好长时间没有写博文了,今天继续. 这次跟大家分享的内容起因于对一个枚举值列表的序列化,下面简化后的代码即能重现.为了明确起见,我显式指定了枚举的基础类型. // 定义一个枚举类型. public en ...
- maven package 知识(转载)
“打包“这个词听起来比较土,比较正式的说法应该是”构建项目软件包“,具体说就是将项目中的各种文件,比如源代码.编译生成的字节码.配置文件.文档,按照规范的格式生成归档,最常见的当然就是JAR包和WAR ...
- enum操作--获取枚举里的最大值
一个应用系统,如果程序里没有任何enum的使用,我认为它的可读性是有待商榷的. 求枚举里的最大/最小枚举值, 其实是对Array进行操作: enum EnumTest { ddd = , eee } ...
- sql的行转列(PIVOT)与列转行(UNPIVOT)
在做数据统计的时候,行转列,列转行是经常碰到的问题.case when方式太麻烦了,而且可扩展性不强,可以使用 PIVOT,UNPIVOT比较快速实现行转列,列转行,而且可扩展性强 一.行转列 1.测 ...