在.NET 中实现 AOP
软件工程中的大多数思想都是集中在管理复杂度上面的--
结构化编程尝试通过粗粒度的代码与设计划分来降低复杂度;
面向对象编程尝试通过建立结合状态与行为的抽象体来降低复杂度;
基于组件的软件尝试通过基于抽象接口和协议划分应用程序模块来降低复杂度。
基于组件的软件的梦想是构造一个世界,让水平一般的程序员就能使用高级语言和工具将组件组装起来。这当然假设这个世界里面的问题域能被分解成相互之间通过简单的方法调用进行交互的各种离散组件。
基于组件的软件的前提却忽略了这样一个事实,一个程序的特定方面倾向于分散到一个应用的多个部分。安全性就是这样的一个方面,线程管理也是,并发控制也是,这个列表会很长。
不可避免地,一个应用趋于被众多处理那些不是问题域中心的程序方面的代码片断污染。通常,这些方面又倾向于跨问题域,因此需要可复用的解决方案。致力提供机制来解决这类问题的就是AOP(面向方面编程),一个在1997年先后被Gregor Kiczales,和Xeros PARC 提出来的术语。
CLR的AOP机制基本上就是将方法调用看作消息交换。
下面用代码说明这个机制:
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Contexts;
using System.Threading;
using System.Diagnostics;
namespace MsgAsMethodCalls
{
public interface ICaculator
{
double Add(double x, double y);
double Multiply(double x, double y);
}
public class MyProxy : RealProxy
{
public MyProxy() : base(typeof(ICaculator)) { }
public override IMessage Invoke(IMessage msg)
{
if (msg as IMethodCallMessage != null)
{
IMessage response = Program.ProcessMessage(msg as IMethodCallMessage);
return response;
}
return null;
}
}
public class PriorityProxy : RealProxy
{
readonly MarshalByRefObject target;
readonly ThreadPriority level;
public PriorityProxy(MarshalByRefObject target,
Type type,
ThreadPriority level)
: base(type)
{
this.target = target;
this.level = level;
}
public override IMessage Invoke(IMessage request)
{
IMethodCallMessage call = (IMethodCallMessage)request;
Program.WireTap(call);
// step 1: adjust priority
Thread here = Thread.CurrentThread;
ThreadPriority old = here.Priority;
here.Priority = level;
// step 2: forward call
IMessage response = null;
IConstructionCallMessage ctor = call as IConstructionCallMessage;
if (ctor != null)
{
// we are holding a TP, so grab its RP
RealProxy defaultProxy = RemotingServices.GetRealProxy(target);
// as intermediatoe RP to invoke constructor
defaultProxy.InitializeServerObject(ctor);
// get OUR TP
MarshalByRefObject tp = (MarshalByRefObject)this.GetTransparentProxy();
// return a message containing our TP as the result of the constuctor call
response = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
}
else
{
response = RemotingServices.ExecuteMessage(target, call);
}
// step 3: restore old priority
here.Priority = old;
// step 4: return response message to TP
return response;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class PriorityProxyAttribute : ProxyAttribute
{
ThreadPriority level;
public PriorityProxyAttribute(ThreadPriority level)
{
this.level = level;
}
public override MarshalByRefObject CreateInstance(Type t)
{
// note that we delegate to our base to get an
// uninitialized instance!
MarshalByRefObject target = base.CreateInstance(t);
PriorityProxy rp = new PriorityProxy(target, t, level);
return (MarshalByRefObject)rp.GetTransparentProxy();
}
}
public class PriorityProperty : IContextProperty
{
ThreadPriority level;
public ThreadPriority Level { get { return level; } }
internal PriorityProperty(ThreadPriority level)
{ this.level = level; }
// IContextProperty members
public string Name { get { return "ThreadPriority"; } }
public bool IsNewContextOK(Context ctx)
{
return true;
}
public void Freeze(Context ctx) { }
}
public class PriorityAttribute : Attribute, IContextAttribute
{
ThreadPriority level;
internal PriorityAttribute(ThreadPriority level)
{ this.level = level; }
// IContextAttribute members
public bool IsContextOK(Context current,
IConstructionCallMessage ctor)
{
// Our property must be present!
object prop = current.GetProperty("ThreadPriority");
if (prop == null) return false;
// and its level must match the attribute's
PriorityProperty pp = (PriorityProperty)prop;
return pp.Level == this.level;
}
public void GetPropertiesForNewContext(
IConstructionCallMessage ctor)
{
// create new properties
IContextProperty prop = new PriorityProperty(this.level);
// associate property with constructor call
ctor.ContextProperties.Add(prop);
ctor.ContextProperties.Add(new TimingProperty());
ctor.ContextProperties.Add(new BoostProperty());
ctor.LogicalCallContext.SetData("clientpriority", new EnvoyData(Thread.CurrentThread.Priority));
}
}
public abstract class DefaultSink : IMessageSink
{
readonly protected IMessageSink next;
public DefaultSink(IMessageSink next)
{
this.next = next;
}
public IMessageSink NextSink { get { return next; } }
public virtual IMessage SyncProcessMessage(IMessage request)
{
IMessage response = next.SyncProcessMessage(request);
return response;
}
public virtual IMessageCtrl AsyncProcessMessage(IMessage request,
IMessageSink upcall)
{
IMessageCtrl ctrl = next.AsyncProcessMessage(request, upcall);
return ctrl;
}
}
public class ServerTimingSink : DefaultSink
{
public ServerTimingSink(IMessageSink next)
: base(next)
{ }
[ContextStatic]
static internal long totalTicks = 0;
public override IMessage SyncProcessMessage(IMessage r)
{
long start = DateTime.Now.Ticks;
IMessage p = next.SyncProcessMessage(r);
long end = DateTime.Now.Ticks;
totalTicks += end - start;
return p;
}
}
public class ClientTimingSink : DefaultSink
{
public ClientTimingSink(IMessageSink next)
: base(next)
{ }
public override IMessage SyncProcessMessage(IMessage r)
{
long start = DateTime.Now.Ticks;
IMessage p = next.SyncProcessMessage(r);
long end = DateTime.Now.Ticks;
ServerTimingSink.totalTicks += end - start;
return p;
}
}
public class TimingProperty
: IContextProperty,
IContributeClientContextSink,
IContributeServerContextSink
{
IContributeClientContextSink Members#region IContributeClientContextSink Members
public IMessageSink GetClientContextSink(IMessageSink nextSink)
{
return new ClientTimingSink(nextSink);
}
#endregion
IContributeServerContextSink Members#region IContributeServerContextSink Members
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new ServerTimingSink(nextSink);
}
#endregion
IContextProperty Members#region IContextProperty Members
public void Freeze(Context newContext)
{
}
public bool IsNewContextOK(Context newCtx)
{
return true;
}
public string Name
{
get { return "TimingProperty"; }
}
#endregion
}
internal class EnvoyData : ILogicalThreadAffinative
{
internal ThreadPriority clientPriority;
internal EnvoyData(ThreadPriority level)
{
this.clientPriority = level;
}
}
public class PriorityEnvoySink : DefaultSink
{
public PriorityEnvoySink(IMessageSink next) : base(next) { }
public override IMessage SyncProcessMessage(IMessage request)
{
IMethodCallMessage call = (IMethodCallMessage)request;
ThreadPriority p = Thread.CurrentThread.Priority;
EnvoyData ed = new EnvoyData(p);
call.LogicalCallContext.SetData("clientpriority", ed);
return next.SyncProcessMessage(call);
}
}
public class PriorityServerSink : DefaultSink
{
public PriorityServerSink(IMessageSink next) : base(next) { }
public override IMessage SyncProcessMessage(IMessage request)
{
// grab caller's priority from call context
IMethodCallMessage call = (IMethodCallMessage)request;
LogicalCallContext cc = call.LogicalCallContext;
EnvoyData ed = (EnvoyData)cc.GetData("clientpriority");
cc.FreeNamedDataSlot("clientpriority");
// proceed to boost-dispatch-unboost
Thread here = Thread.CurrentThread;
ThreadPriority old = here.Priority;
if (ed.clientPriority != ThreadPriority.Highest)
here.Priority = ed.clientPriority + 1;
IMessage resp = next.SyncProcessMessage(call);
if (ed.clientPriority != ThreadPriority.Highest)
here.Priority = old;
return resp;
}
}
public class BoostProperty :
IContextProperty,
IContributeServerContextSink,
IContributeEnvoySink
{
IContextProperty Members#region IContextProperty Members
public void Freeze(Context newContext)
{
}
public bool IsNewContextOK(Context newCtx)
{
return true;
}
public string Name
{
get { return "Boost"; }
}
#endregion
IContributeServerContextSink Members#region IContributeServerContextSink Members
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new PriorityServerSink(nextSink);
}
#endregion
IContributeEnvoySink Members#region IContributeEnvoySink Members
public IMessageSink GetEnvoySink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new PriorityEnvoySink(nextSink);
}
#endregion
}
public class MyCalc : ContextBoundObject, ICaculator
{
public static MyCalc Create(ThreadPriority level)
{
MyCalc target = new MyCalc();
PriorityProxy rp = new PriorityProxy(target, typeof(MyCalc), level);
return (MyCalc)rp.GetTransparentProxy();
}
private MyCalc() { }
public double Add(double x, double y) { return x + y; }
public double Multiply(double x, double y) { return x * y; }
}
[PriorityProxy(ThreadPriority.Highest)]
public class MyCalc3 : ContextBoundObject, ICaculator
{
public double Add(double x, double y) {
Console.WriteLine(Thread.CurrentThread.Priority);
return x + y;
}
public double Multiply(double x, double y) { return x * y; }
}
[Priority(ThreadPriority.Highest)]
public class MyCalc5 : ContextBoundObject, ICaculator
{
public double Add(double x, double y) {
// grab the object's context
Context here = Thread.CurrentContext;
// fecth the priority property
IContextProperty p = here.GetProperty("ThreadPriority");
PriorityProperty pp = (PriorityProperty)p;
Debug.Assert(pp.Level == ThreadPriority.Highest);
Console.WriteLine(Thread.CurrentThread.Priority);
return x + y;
}
public double Multiply(double x, double y) { return x * y; }
}
class Program
{
public static void WireTap(IMethodMessage msg){
IMethodCallMessage call = (IMethodCallMessage)msg;
Console.WriteLine("<{0}>",call.MethodName);
for(int i=0;i<call.ArgCount;++i)
Console.WriteLine("<{0}>{1}</{0}>",
call.GetArgName(i),
call.GetArg(i));
Console.WriteLine("</{0}>",call.MethodName);
}
public static IMethodReturnMessage ProcessMessage(IMethodCallMessage request)
{
switch (request.MethodName)
{
case "Add":
{
double x = (double)request.GetInArg(0);
double y = (double)request.GetInArg(1);
double result = x + y;
return new ReturnMessage(result, null, 0, null, request);
}
case "Multiply":
{
double x = (double)request.GetInArg(0);
double y = (double)request.GetInArg(1);
double result = x * y;
return new ReturnMessage(result, null, 0, null, request);
}
default:
{
string exm = string.Format("{0} not implemented",
request.MethodName);
Exception ex = new NotImplementedException(exm);
return new ReturnMessage(ex, request);
}
}
}
static void Main(string[] args)
{
// isinst
MyProxy rp = new MyProxy();
object tp = rp.GetTransparentProxy();
ICaculator calc = tp as ICaculator;
Debug.Assert(calc != null);
double result = calc.Add(3, 4);
Debug.Assert(result == 7);
// factory method
calc = MyCalc.Create(ThreadPriority.Highest);
result = calc.Add(3, 4);
Debug.Assert(result == 7);
// ProxyAttribute
calc = new MyCalc3();
result = calc.Add(3, 4);
Debug.Assert( result == 7);
// ContextProperty
calc = new MyCalc5();
result = calc.Add(3, 4);
Debug.Assert(result == 7);
}
}
}
转载于:https://www.cnblogs.com/mahope/archive/2006/03/29/361379.html
在.NET 中实现 AOP相关推荐
- 一文读懂Spring中的AOP机制
一.前言 这一篇我们来说一下 Spring 中的 AOP 机制,为啥说完注解的原理然后又要说 AOP 机制呢? 1.标记日志打印的自定义注解 @Target({ElementType.METHOD}) ...
- 动态代理——》AOP —— Spring 中的 AOP||AOP 相关术语||学习 spring 中的 AOP 要明确的事
AOP 概述 什么是 AOP AOP:全称是 Aspect Oriented Programming 即:面向切面编程 AOP 的作用及优势 作用: 在程序运行期间,不修改源码对已有方法进 ...
- Spring Boot中使用AOP统一处理Web请求日志
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...
- 【springboot中使用aop的具体步骤和示例】
1.依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spri ...
- Spring中的AOP(三)——基于Annotation的配置方式(一)
为什么80%的码农都做不了架构师?>>> AspectJ允许使用注解用于定义切面.切入点和增强处理,而Spring框架则可以识别并根据这些注解来生成AOP代理.Spring只是 ...
- spring中的aop术语和细节
Spring中AOP的细节 说明 我们学习spring的aop,就是通过配置的方式 AOP相关术语 Joinpoint(连接点): 所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法, ...
- 手动实现SPring中的AOP(1)
Spring中的AOP是基于JDK的API动态的在内存中创建代理对象的.所以这里先介绍一些设计模式之----代理模式: a) 代理模式的定义:代理(Proxy)模式是一种提供对目标对象 ...
- .Net中的AOP系列之《方法执行前后——边界切面》
返回<.Net中的AOP>系列学习总目录 本篇目录 边界切面 PostSharp方法边界 方法边界 VS 方法拦截 ASP.NET HttpModule边界 真实案例--检查是否为移动端用 ...
- 【转】在.Net中关于AOP的实现
原文地址:http://www.uml.org.cn/net/201004213.asp 一.AOP实现初步 AOP将软件系统分为两个部分:核心关注点和横切关注点.核心关注点更多的是Domain Lo ...
- 在Controller中使用AOP
转:http://usherlight.iteye.com/blog/1306111 在Controller中使用AOP的问题主要在于如何让Controller能够被检测到. Controller和 ...
最新文章
- 谈谈虚拟化及其安全性
- 已解决:Ubuntu16.4和Windows10创建共享文件夹
- [HOW TO]-ubuntu20.10搭建openjrok服务指南
- 坦克大战java_清华毕业大佬用一个坦克大战项目讲完了23种设计模式
- P4619 [SDOI2018]旧试题
- 三类基于贪心思想的区间覆盖问题
- 在vivado里用rtl描述_如何利用Vivado HLS处理许多位准确或任意精度数据类型
- 1.2_配置Python基本环境
- 《机器学习实战》KNN算法实现
- 一文搞懂Java泛型到底是什么东东
- Docker详解(五)——Docker基本使用
- 说你呢,装着JDK8,却孜孜不倦的写着 JDK6 的代码,写了3年了,JDK8的特性都没用过......
- Unsafe与CAS
- 学习笔记一 线性代数
- 教你如何用python获得中国气象数据网的API数据并且导入数据库(附源码)
- 基于STM32WIFI远程监控电压电流表(二)电流检测电路
- 如何编写外挂 制作外挂 外挂教程
- 滴滴2023秋招笔试 老张的美数课 (C++ DP)
- 前端校招该考察什么?一个面试官的思考
- ddl是什么(ddl是什么软件)
热门文章
- 在资源管理器中使鼠标右键增加一个命令,运行cmd,同时使得当前路径为资源管理器当前的目录...
- 如何将分表汇总到总表_总表输入数据,自动拆分到分表,你会吗?
- ebpf深入理解和应用介绍
- Nginx之rewrite配置
- MapReduce之join操作
- ZYNQ PS端输出不准确时钟供PL使用
- word2vec实例详解python_在python下实现word2vec词向量训练与加载实例
- STM32F407ZGT6 fatfs出现挂载成功,但是文件读写失败的原因
- boost::filesystem 库的简单使用
- 单片机中volatile的应用