特性attribute,声明和使用attribute,应用attribute,AOP面向切面,多种方式实现AOP

时间:2021-12-14 04:58:48

1 特性attribute,和注释有什么区别
2 声明和使用attribute
3 应用attribute
4 AOP面向切面
5 多种方式实现AOP

           ------------------------------Anker_张 (博客园)

文件下载    链接: http://pan.baidu.com/s/1o8kctGe 密码: q6yh

特性是一个继承或者间接继承Attribute的类

通常用attribute结尾,那么在使用的时候,可以去掉这个结尾

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class TableAttribute : Attribute
{
private string _TableName = null; public TableAttribute(string tableName)
{
this._TableName = tableName;
} public string GetTableName()
{
return this._TableName;
} }
[AttributeUsage(AttributeTargets.Property)]
public class IntValidateAttribute : Attribute
{ private int _Min = ;
private int _Max = ; public IntValidateAttribute(int min, int max)
{
this._Min = min;
this._Max = max;
} public bool Validate(int num)
{
return num > this._Min && num < this._Max;
} }
 [Table("User")]

    public class UserModel
{
//public string TableName = "User"; [IntValidateAttribute(, )]
//[IntValidateAttribute(2, 5000)]
public int Id { get; set; } }
       /// <summary>
/// 根据类型获取表名称 扩展方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static string GetTableName<T>(this T t) where T : new()
{
Type type = t.GetType();
object[] oAttributeList = type.GetCustomAttributes(true);
foreach (var item in oAttributeList)
{
if (item is TableAttribute)
{
TableAttribute attribute = item as TableAttribute;
return attribute.GetTableName();
}
}
return type.Name;
}
/// <summary>
/// 校验而且保存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public static void Save<T>(T t)
{
bool isSafe = true; Type type = t.GetType(); foreach (var property in type.GetProperties())
{
object[] oAttributeList = property.GetCustomAttributes(true);
foreach (var item in oAttributeList)
{
if (item is IntValidateAttribute)
{
IntValidateAttribute attribute = item as IntValidateAttribute;
isSafe = attribute.Validate((int)property.GetValue(t));
}
}
if (!isSafe)
break;
} if (isSafe)
Console.WriteLine("保存到数据库");
else
Console.WriteLine("数据不合法");
}
class Program
{
static void Main(string[] args)
{
try
{
UserModel user = new UserModel();
user.Id = ;
string name = user.GetTableName<UserModel>(); BaseDAL.Save<UserModel>(user);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}

AOP面向切面,横向扩展,AOP原理规划图

特性attribute,声明和使用attribute,应用attribute,AOP面向切面,多种方式实现AOP

把每个相同逻辑方法处理前共同的动作和结尾共同处理的动作,封装在特性里面,例如用户验证日志处理,在方法上添加特性就可享有动作

多种方式实现AOP

    public class User  //先定义模型
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}

装饰器模式实现静态代理

      public interface IUserProcessor
{
void RegUser(User user);
}
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
}
}
        /// <summary>
/// 装饰器的模式去提供一个AOP功能 AOP 在方法前后增加自定义的方法
/// </summary>
public class UserProcessorDecorator : IUserProcessor
{
private IUserProcessor UserProcessor { get; set; }
public UserProcessorDecorator(IUserProcessor userprocessor)
{
this.UserProcessor = userprocessor;
} public void RegUser(User user)
{
PreProceed(user);
try
{
this.UserProcessor.RegUser(user);
}
catch (Exception)
{ throw;
}
PostProceed(user);
} public void PreProceed(User user)
{
Console.WriteLine("方法执行前");
} public void PostProceed(User user)
{
Console.WriteLine("方法执行后");
}
}

及调用Show()方法 采用装饰器模式实现AOP,这个比较好理解

        public static void Show()
{
User user = new User() { Name = "Anker_张", Password = "" };
IUserProcessor processor = new UserProcessor();
processor = new UserProcessorDecorator(processor);
processor.RegUser(user);
}

使用.Net Remoting/RealProxy 实现动态代理 

        public interface IUserProcessor
{
void RegUser(User user);
}
    //必须要继承 MarshaByRefObject
public class UserProcessor : MarshalByRefObject, IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。用户名称{0} Password{1}", user.Name, user.Password);
}
}
        public class MyRealProxy<T> : RealProxy
{
private T tTarget;
public MyRealProxy(T target)
: base(typeof(T))
{
this.tTarget = target;
} public override IMessage Invoke(IMessage msg)
{
PreProceede(msg);
IMethodCallMessage callMessage = (IMethodCallMessage)msg;
object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);
PostProceede(msg);
return new ReturnMessage(returnValue, new object[], , null, callMessage);
}
public void PreProceede(IMessage msg)
{
Console.WriteLine("方法执行前");
}
public void PostProceede(IMessage msg)
{
Console.WriteLine("方法执行后");
}
}
        public static class TransparentProxy
{
public static T Create<T>()
{
T instance = Activator.CreateInstance<T>();
MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
T transparentProxy = (T)realProxy.GetTransparentProxy();
return transparentProxy;
}
}
    /// <summary>
/// 使用.Net Remoting/RealProxy 实现动态代理 启动Show
/// </summary>
public class Proxy
{
public static void Show()
{
User user = new User() { Name = "Anker_张", Password = "" };
UserProcessor processor = new UserProcessor();
processor.RegUser(user);
UserProcessor userprocessor = TransparentProxy.Create<UserProcessor>();
userprocessor.RegUser(user);
}
}

使用EntLib\PIAB Unity 实现动态代理

首先用NuGet 引用Unity

特性attribute,声明和使用attribute,应用attribute,AOP面向切面,多种方式实现AOP

 #region 特性对应的行为
public class UserHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[] as User;
if (user.Password.Length < )
{
return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
}
Console.WriteLine("参数检测无误"); IMethodReturn methodReturn = getNext.Invoke().Invoke(input, getNext); //Console.WriteLine("已完成操作"); return methodReturn;
}
} public class LogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
return getNext()(input, getNext);
}
}
public class ExceptionHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
if (methodReturn.Exception == null)
{
Console.WriteLine("无异常");
}
else
{
Console.WriteLine("异常:{0}", methodReturn.Exception.Message);
}
return methodReturn;
}
} public class AfterLogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
User user = input.Inputs[] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
return methodReturn;
}
}
#endregion 特性对应的行为
#region 特性
public class UserHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
ICallHandler handler = new UserHandler() { Order = this.Order };
return handler;
}
} public class LogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler() { Order = this.Order };
}
} public class ExceptionHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new ExceptionHandler() { Order = this.Order };
}
} public class AfterLogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new AfterLogHandler() { Order = this.Order };
}
}
#endregion 特性
 #region 业务
[UserHandlerAttribute(Order = )]
[ExceptionHandlerAttribute(Order = )]
[LogHandlerAttribute(Order = )]
[AfterLogHandlerAttribute(Order = )]
public interface IUserProcessor
{
void RegUser(User user);
User GetUser(User user);
} public class UserProcessor : IUserProcessor//MarshalByRefObject,
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。");
//throw new Exception("11");
} public User GetUser(User user)
{
return user;
}
}
#endregion 业务

根基 Order 执行顺序执行

public class UnityAOP
{
public static void Show()
{
User user = new User()
{
Name = "Anker_张",
Password = ""
}; IUnityContainer container = new UnityContainer();//声明一个容器
container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer并注册IUserProcessor container.AddNewExtension<Interception>().Configure<Interception>()
.SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor()); IUserProcessor userprocessor = container.Resolve<IUserProcessor>(); Console.WriteLine("********************");
userprocessor.RegUser(user);//调用
//userprocessor.GetUser(user);//调用
}
}

特性attribute,声明和使用attribute,应用attribute,AOP面向切面,多种方式实现AOP

AOP技术基础

2.1 AOP技术起源

AOP技术的诞生并不算晚,早在1990年开始,来自Xerox Palo Alto Research Lab(即PARC)的研究人员就对面向对象思想的局限性进行了分析。他们研究出了一种新的编程思想,借助这一思想或许可以通过减少代码重复模块从而帮助开发人员提高工作效率。随着研究的逐渐深入,AOP也逐渐发展成一套完整的程序设计思想,各种应用AOP的技术也应运而生。

AOP技术在Java平台下是最先得到应用的。就在PARC对于面向方面编程进行研究的同时,美国Northeastern University的博士生Cristina Lopes和其同事也开始了类似的思考。最终,美国国防先进技术研究计划署(Defense Advanced Research Projects Agency即DARPA)注意到了这项工作,并提供了科研经费,鼓励将二者的工作成果结合起来。他们通过定义一套Java语言的扩展系统,使开发者可以方便的进行面向方面的开发,这套扩展系统被称为AspectJ。之后,AspectJ在2002年被转让给Eclipse Foundation,从而成为在开源社区中AOP技术的先锋,也是目前最为流行的AOP工具。

AspectWerkz则是基于Java的动态的、轻量级AOP框架。AspectWerkz仍然是开源社区中的产品,由BEA System提供赞助,开发者则是BEA的两名员工Jonas Bonér和Alexandre Vasseur。最近版本是AspectWerkz 2.0。2005年1月,AspectJ和AspectWerkz达成协议,同意将二者的成果综合到一起,取其精华创建一个单一的工具。他们合作的第一个发布版本为AspectJ 5,它扩展了AspectJ语言,以支持基于Annotation开发风格而又支持类似AspectJ代码风格。AspectJ 5也为Java 5的语言特性提供完全的AOP支持。

在Java阵营中,商用软件制造商JBoss在其2004年推出的JBoss 4.0中,引入了AOP框架和组件。在JBoss 4.0中,用户可以在JBoss应用服务器外部单独使用JBoss AOP,该版本为JBoss AOP 1.0,是在2004年10月发布的。在2005年,JBoss AOP框架又发布了1.3.0版本,新版本对加载期织入(Weev)和切点(point cut)匹配的性能做了很大的优化,使应用程序的启动时间大大缩短。

作为轻型的Framework,Spring在开发轻量级的J2EE时,应用是非常广泛的。它通过IoC模式(Inversion of Control,控制反转模式)来实现AOP,通常被称为Spring AOP。在2004年,被作为Spring框架的扩展而发布,目前版本已更新到1.1.3。Spring AOP作为一种非侵略性的,轻型的AOP框架,开发者无需使用预编译器或其他的元标签,在Java程序中应用AOP。目前,AOP的功能完全集成到了Spring事务管理、日志和其他各种特性的上下文中。

在.Net的阵营中,AOP技术的应用远不如Java阵营对AOP的关注。2005年1月,微软发布的Enterprise Library提供了7种不同的“应用程序块(application blocks)”。有个别专家认为,这些组件可以被认为是方面。但该观点并未得到一致的认同。事实上,在.Net平台下,推动AOP技术发展的原动力并非微软,而是开源社区。虽然,微软的技术专家们亦然听到了在.Net Framework中增加AOP技术的群众呼声,但作为如此巨大的软件公司,要让它灵活地转变战略方向,显然是不太现实的。正因为此,才赐予了开源社区在AOP技术的研究与探索上一个巨大的发展空间。

与Java阵营中的AOP技术不同,目前在.Net平台下的各种AOP工具,基本上还停留在实验室阶段。但一些在技术上领先且逐渐成熟的AOP产品,也在开源社区中渐露峥嵘。这其中主要包括Aspect#,AspectDNG,Eos AOP等。

Aspect#是基于Castle动态代理技术来实现的。Castle源于Apache Avalon项目,其目的在于实现一个轻量级的IoC容器。Aspect#于2005年6月被收录为Castle的其中一个子项目。它是针对CLI(.Net和Mono)实现的AOP框架,利用了反射、代理等机制。目前的Aspect#版本为2.1.1。

AspectDNG目前的版本为0.7,仍然处于beta版的阶段。它的实现技术是基于rail的静态织入。Rail属于IL级别下的代码织入,它自定义的一套xml格式的ILML语言,能够将原有的程序集拆散成ILML格式,以便于对静态程序集进行修改和扩展,从而达到静态织入的目的。因为AspectDNG是属于IL级别下的代码织入,因此在.Net平台下,并不受具体的编程语言限制。

Eos AOP与AspectDNG一样,仍然采用静态织入的方式,但从语法定义上,它更近似于AspectJ关于AOP的实现。它扩展了C#语法,引入了aspect、introduce、before、after等关键字,并且提供了专用的Eos编译器。Eos项目是于2004年9月开始启动,2005年6月推出的0.3.3版本为最新版本,主要的开发人员为Hridesh Rajan和Kevin Sullivan。前者为Virginia大学计算机系的研究生,Eos项目最初是由Hridesh Rajan提出的;而后者则为该计算机系的副教授(Associate Professor)。所以自Eos诞生之初,就带有浓厚的学院派特色。

从AOP技术的整体发展来看,高性能、稳定、可扩展、易用的AOP框架是其趋势与目标。从上述对各种AOP技术的分析来看,AOP技术无疑是具有共同特点的,而各种实现技术就是围绕着这些共性深入与延伸。接下来,我将概要地介绍AOP的本质,以及它的技术要素。

2.2 AOP技术本质

2.2.1 技术概览

AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。然而殊途同归,实现AOP的技术特性却是相同的,分别为:

1、join point(连接点):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point。
2、point cut(切入点):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。
3、advice(通知):是point cut的执行代码,是执行“方面”的具体逻辑。
4、aspect(方面):point cut和advice结合起来就是aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。
5、introduce(引入):为对象引入附加的方法或属性,从而达到修改对象结构的目的。有的AOP工具又将其称为mixin。

上述的技术特性组成了基本的AOP技术,大多数AOP工具均实现了这些技术。它们也可以是研究AOP技术的基本术语。

2.2.2 横切技术

“横切”是AOP的专有名词。它是一种蕴含强大力量的相对简单的设计和编程技术,尤其是用于建立松散耦合的、可扩展的企业系统时。横切技术可以使得AOP在一个给定的编程模型中穿越既定的职责部分(比如日志记录和性能优化)的操作。

如果不使用横切技术,软件开发是怎样的情形呢?在传统的程序中,由于横切行为的实现是分散的,开发人员很难对这些行为进行逻辑上的实现或更改。例如,用于日志记录的代码和主要用于其它职责的代码缠绕在一起。根据所解决的问题的复杂程度和作用域的不同,所引起的混乱可大可小。更改一个应用程序的日志记录策略可能涉及数百次编辑——即使可行,这也是个令人头疼的任务。

在AOP中,我们将这些具有公共逻辑的,与其他模块的核心逻辑纠缠在一起的行为称为“横切关注点(Crosscutting Concern)”,因为它跨越了给定编程模型中的典型职责界限。