AOP简介:
AOP(Aspect Oriented Programming)“面向切面编程”,其实和OOP(Object Oriented Programming)“面向对象编程”一样是一种编程思路,而且个人以为翻译为“切面导向编程”更为妥当,OOP也应翻译为“对象导向编程”。因为正是有了“切面”和“对象”的想法和概念才产生了“Aspect Oriented Programming”和“Object Oriented Programming”这些编程方法,所以“导向”更为贴近些。
以下想法均为个人揣摩得出,具体官方概念请Google,Bing,Baidu.
AOP,个人以为是一种行为(Behavior)的注入,在不改变原有逻辑(original logic)的基础上,将一些可重用的其他逻辑(other logic)注入到原有逻辑(original logic)中。切面(Aspect)即为其他逻辑(other logic),是一些特殊的业务关注点,包括“事务处理”,“异常捕捉”,“日志记录”,“身份验证”等方面。
这种“切面”逻辑一般贯彻整个解决方案,AOP方式将这种切面提取出来,实现了解耦和代码简洁化。
简单例子:
下面举个简单的例子来说明为什么要使用AOP:
1)没有使用AOP的Castle ActiveRecord“事务处理”
代码
class
AOPTest
{
//
......
///
<summary>
///
Save the retire user info.
///
</summary>
///
<param name="site">
The user will be retire user.
</param>
public
void
SaveRetireUserInfo(User user)
{
using
(TransactionScope transaction
=
new
TransactionScope())
{
try
{
RetireUser retireUser
=
new
RetireUser();
retireUser.Name
=
user.Name;
retireUser.Department
=
user.Department;
//
...
user.Delete();
retireUser.Save();
transaction.VoteCommit();
//
完成事务
}
catch
(Exception ex)
{
Log.Write(ex.Message);
transaction.VoteRollBack();
//
事务回滚
}
}
}
//
......
}
2)使用AOP的Castle ActiveRecord“事务处理”, 里边使用了我自己写的精简AOP框架,与原来的文章一样,看不懂没关系,这里只是个宏观的概念。重点在demo分析。
代码
///
<summary>
///
The test class for AOP use attribute for transaction.
///
</summary>
[AOPProxy(Interception
=
typeof
(TransactionInterception))]
class
AOPTest : ContextBoundObject
{
//
......
///
<summary>
///
Save the retire user info.
///
</summary>
///
<param name="site">
The user will be retire user.
</param>
public
void
SaveRetireUserInfo(User user)
{
RetireUser retireUser
=
new
RetireUser();
retireUser.Name
=
user.Name;
retireUser.Department
=
user.Department;
//
...
user.Delete();
retireUser.Save();
}
//
......
}
///
<summary>
///
The interception of the AOP for trasaction.
///
</summary>
class
TransactionInterception : IInterception
{
private
TransactionScope transaction
=
null
;
#region
IInterception Members
public
void
ExceptionHandle()
{
transaction.VoteRollBack();
//
事务回滚
}
public
void
PostInvoke()
{
transaction.VoteCommit();
//
完成事务
}
public
void
PreInvoke()
{
transaction
=
new
TransactionScope();
//
初始化事务
}
#endregion
}
由以上可见,加入AOP后(AOPProxy Attribute实现),“其他逻辑”注入“原始逻辑”使得代码更加简洁,同时也将“切面”的逻辑和“业务”的逻辑分离开来,实现了解耦。TransactionInterception是拦截器,实现了“其他逻辑”,由AOPProxy Attribute通过type将其注入。在处理“原始逻辑”的时候会同时处理注入的“其他逻辑”。ExceptionHandle方法实现出现Exception时的“其他逻辑”注入;PreInvoke方法实现在调用“主题”方法前的“其他逻辑”注入;PostInvoke方法实现在调用“主题”方法后的“其他逻辑”注入。
简单来说执行流程如下:
1. PreInvoke();
2. 主题Method();
3.
if(调用"主题Method()"时出现Exception)
{
ExceptionHandle();
}
else
{
PostInvoke();
}
有下面的SaveRetireUserInfo方法可以看到“业务逻辑”变得简洁,在“业务逻辑”已经见不到扰乱代码可读性的“事务代码”和“try...catch...”语句块了,只需要给该类加上“AOPProxy”特性注入相应的“拦截器”并继承ContextBoundObject即可。
public void SaveRetireUserInfo(User user)
{
RetireUser retireUser = new RetireUser();
retireUser.Name = user.Name;
retireUser.Department = user.Department;
// ...
user.Delete();
retireUser.Save();
}
Proxy基础:
代理模式,说白了就是设置一个“中间层”(proxy),把对实际要操作的“主题”保护在里边,并且在操作时进行额外的操作,实现注入。对“主题”的操作均需要通过proxy来完成,就如同经济人。
比如:你是著名歌星SexyBaby,你有一个经纪人叫Underdog,你只负责唱歌,各种演唱会的举办和电视台对你邀请一律由Underdog负责,你SexyBaby就是“主题”而你的经纪人Underdog就是proxy。
具体的代理模式可以看我以前写的关于Dota的设计模式随笔和各种设计模式书籍。
下面介绍个简单的例子来了解下代理模式。
假设一个场景:IT界优秀人士均喜欢看AV,而由于为了保护我们国家未成年人幼小的心灵不受到不良网站侵害,国家屏蔽了AV站点,那我们这些IT界寂寞哥又有这样的需求,那该怎么办那?我们需要通过Online Web Proxy来解决这个问题,我们通过这样的“在线代理网站”(“在线代理网站”服务器放在不屏蔽AV站点的国家,由“在线代理网站”服务器间接访问AV站点。因为在线代理网站不直接提供AV信息,所以我们是可以访问的)来访问AV站点就可以了。这时我们是通过Proxy(“在线代理网站”)访问到“主题”(AV站点),对Proxy(“在线代理网站”)的操作和直接操作“主题”(AV站点)没有什么区别。
下面就开始我们的AV之旅吧,由于上次有同学说我代码里用中文,怪怪的,这次都用英文,顺便让大家复习下英文了:
1) 首先我们必须有一台链接到Internet的电脑“MyComputer”。
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
My PC.
///
</summary>
public
class
MyComputer
{
///
<summary>
///
Visit the site.
///
</summary>
///
<param name="site">
The site.
</param>
public
void
Visit(ISite site)
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
Site Url:{0}
"
, site.Url);
Console.ForegroundColor
=
ConsoleColor.White;
IFilter filter
=
new
ChinaDNSFilter();
//
Server in China, comply with the rule of China.
site
=
filter.Parse(site);
//
Parse the site.
Console.ForegroundColor
=
ConsoleColor.Gray;
site.ShowInformation();
//
Show the information of the site.
Console.ForegroundColor
=
ConsoleColor.White;
}
}
}
“MyComputer”有一个Visit方法,可以访问到传入的ISite(抽象出的站点接口),Visit方法流程如下:
1) 输出当前站点ISite的Url。下面的Code是ISite的定义。
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The interface of site.
///
</summary>
public
interface
ISite
{
///
<summary>
///
The url of site.
///
</summary>
string
Url
{
get
;
}
///
<summary>
///
Show the information about this site.
///
</summary>
void
ShowInformation();
}
}
另外我们设计了几个站点以供访问,代码如下:
首先是传说中的AVSite(http://www.avsite.com/),看看介绍多么吸引人“The site is so hot, all AV stars.”。
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The site contains AV information.
///
</summary>
public
class
AVSite : ISite
{
#region
ISite Members
///
<summary>
///
The url of site.
///
</summary>
public
string
Url
{
get
{
return
"
http://www.AVSite.com
"
; }
}
///
<summary>
///
Show the information about this site.
///
</summary>
public
void
ShowInformation()
{
Console.WriteLine(
"
The site is so hot, all AV stars.
"
);
}
#endregion
}
}
然后是我们经常上的博客园“http://www.cnblogs.com”,介绍“The technology site, the home of coders.”。
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The site of cnblogs.
///
</summary>
public
class
CnblogsSite : ISite
{
#region
ISite Members
///
<summary>
///
The url of site.
///
</summary>
public
string
Url
{
get
{
return
"
http://www.cnblogs.com
"
; }
}
///
<summary>
///
Show the information about this site.
///
</summary>
public
void
ShowInformation()
{
Console.WriteLine(
"
The technology site, the home of coders.
"
);
}
#endregion
}
}
下面该我们的主角出场了,“在线代理网站”“http://www.myproxy.com”。我们可以通过构造函数传入想要代理访问的站点地址,传入站点地址后会通过DNS解析访问到相应的网站。“在线代理网站”和“DNS(Domain Name Resolution)”的实现(执行“在线代理网站”的ShowInformation方法时实际是通过代理显示要代理网站(AV站点)的信息)。
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The online web proxy site.
///
</summary>
public
class
MyProxySite : ISite
{
private
ISite _site
=
null
;
public
MyProxySite(
string
url)
{
_site
=
DNS.GetSite(url);
}
#region
ISite Members
///
<summary>
///
The url of site.
///
</summary>
public
string
Url
{
get
{
return
"
http://www.myproxy.com
"
; }
}
///
<summary>
///
Show the information about this site.
///
</summary>
public
void
ShowInformation()
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
Proxy start!
"
);
Console.WriteLine(
"
Real url:{0}
"
, _site.Url);
Console.ForegroundColor
=
ConsoleColor.Gray;
IFilter filter
=
new
USADNSFilter();
//
Server in USA, comply with the rule of USA.
_site
=
filter.Parse(_site);
_site.ShowInformation();
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
Proxy end!
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
#endregion
}
}
DNS
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
Domain name resolution.
///
</summary>
class
DNS
{
///
<summary>
///
Get the site instance by the url.
///
</summary>
///
<param name="url">
The visited url.
</param>
///
<returns>
The site instance.
</returns>
public
static
ISite GetSite(
string
url)
{
ISite site
=
null
;
if
(url
==
"
http://www.AVSite.com
"
)
{
site
=
new
AVSite();
}
else
if
(url
==
"
http://www.cnblogs.com
"
)
{
site
=
new
CnblogsSite();
}
else
{
site
=
new
NullSite();
}
return
site;
}
}
}
另外当DNS中不包含传入的网址时要返回“NullSite”,用“MyComputer”直接访问“AVSite”时,会被“ChinaFilter”过滤,返回“WarnningSite”提醒访问者触犯法律。“NullSite”和“WarnningSite”实现如下。
NullSite:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The site with nothing.
///
</summary>
public
class
NullSite : ISite
{
#region
ISite Members
///
<summary>
///
The url of site.
///
</summary>
public
string
Url
{
get
{
return
String.Empty; }
}
///
<summary>
///
Show the information about this site.
///
</summary>
public
void
ShowInformation()
{
Console.WriteLine(
"
No site, please check the url.
"
);
}
#endregion
}
}
WarnningSite:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The site for the warnning of gov.
///
</summary>
public
class
WarnningSite : ISite
{
#region
ISite Members
///
<summary>
///
The url of site.
///
</summary>
public
string
Url
{
get
{
return
String.Empty; }
}
///
<summary>
///
Show the information about this site.
///
</summary>
public
void
ShowInformation()
{
Console.WriteLine(
"
For the gov rule, this site can't be visited.
"
);
}
#endregion
}
}
2) 根据中国法律由ISP(Internat Service Provider)服务器过滤网站,返回相应的站点对象。
过滤接口实现如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
The interface of the site visiting filter.
///
</summary>
public
interface
IFilter
{
///
<summary>
///
Parse the site.
///
</summary>
///
<param name="site">
The site.
</param>
///
<returns>
The new site.
</returns>
ISite Parse(ISite site);
}
}
中国过滤器,过滤掉AVSite,过滤后返回WarnningSite,实现如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
ISP(Internet Service Provider),filter the visited site information for comply the rule of China.
///
</summary>
public
class
ChinaDNSFilter : IFilter
{
#region
IFilter Members
///
<summary>
///
Parse the site.
///
</summary>
///
<param name="site">
The site.
</param>
///
<returns>
The new site.
</returns>
public
ISite Parse(ISite site)
{
//
For the children, no AV information.
ISite returnSite
=
site;
if
(site
is
AVSite)
{
returnSite
=
new
WarnningSite();
}
return
returnSite;
}
#endregion
}
}
美国过滤器,不过滤AVSite,直接返回AVSite,实现如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.ProxyPattern
{
///
<summary>
///
ISP(Internet Service Provider),filter the visited site information for comply the rule of USA.
///
</summary>
class
USADNSFilter : IFilter
{
#region
IFilter Members
///
<summary>
///
Parse the site.
///
</summary>
///
<param name="site">
The site.
</param>
///
<returns>
The new site.
</returns>
public
ISite Parse(ISite site)
{
//
Freedom, no filter.
return
site;
}
#endregion
}
}
3) 通过_site.ShowInformation显示站点信息。
虚拟Internat已经搭建起来,可以进行测试啦。
首先用“MyComputer”直接访问AVSite,返回WarnningSite:
MyComputer myComputer = new MyComputer();
ISite site = new AVSite();
myComputer.Visit(site); // Visit AV site will be return warning.
结果:
然后用“MyComputer”通过“MyProxySite”在线代理网站,代理访问AVSite,返回AVSite站点信息,偶也~~~~
site = new MyProxySite("http://www.avsite.com/"); // Use online web proxy.
myComputer.Visit(site);
结果:
最后看完AV,我们再会博客园逛一逛
site = new CnblogsSite();
myComputer.Visit(site);
结果:
花了很大的功夫说代理,现在该切入正题了,我们的AOP,分为代理模式实现和Attribute实现。
AOP框架实现
首先AOP实现了逻辑注入,即在调用方法之前进行了逻辑注入。我们使用System.Runtime.Remoting中呃Message机制来实现Message的截获和注入,有点像MFC框架中的钩子函数。
首先,为了实现逻辑注入,我们先要设计出逻辑注入的接口(IInterception)。为了简单起见逻辑注入我们只设计了3个Method,包括PreInvoke,PostInvoke和ExceptionHandle,分别用来注入“调用主题Method前的逻辑”,“调用主题Method后的逻辑”和“调用主题Method时发生Exception的逻辑”。具体实现如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
namespace
Landpy.AOP
{
///
<summary>
///
Description of IInterception.
///
</summary>
public
interface
IInterception
{
///
<summary>
///
Pre the method invoke.
///
</summary>
void
PreInvoke();
///
<summary>
///
Post the method invoke.
///
</summary>
void
PostInvoke();
///
<summary>
///
Handling the exception which occurs when the method is invoked.
///
</summary>
void
ExceptionHandle();
}
}
逻辑注入的接口(IInterception)永远不为null,根据Null Object模式设计了NullInterception(关于Null Object模式及其意义可以看我原来的文章),实现如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.AOP
{
///
<summary>
///
Null Object pattern for interception.
///
</summary>
public
class
NullInterception : IInterception
{
#region
IInterception Members
///
<summary>
///
Before invoke the real instance to do something.
///
</summary>
public
virtual
void
PreInvoke()
{
//
Do nothing.
}
///
<summary>
///
End invoke the real instance to do something.
///
</summary>
public
virtual
void
PostInvoke()
{
//
Do nothing.
}
///
<summary>
///
Handling the exception which occurs when the method is invoked.
///
</summary>
public
void
ExceptionHandle()
{
//
Do nothing.
}
#endregion
}
}
为了实现Message拦截,我们必须实现一个继承了“RealProxy”的类“AOPRealProxy”,这样我们就可以重写System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)方法来注入自己的逻辑。
有的时候代码能更清楚的表达,所以先将AOPRealProxy的实现附上:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Runtime.Remoting;
using
System.Runtime.Remoting.Proxies;
using
System.Runtime.Remoting.Messaging;
using
System.Runtime.Remoting.Services;
using
System.Runtime.Remoting.Activation;
namespace
Landpy.AOP
{
///
<summary>
///
RealProxy is a abstract class, which is a class in Framework to provide the function about base proxy.
///
The Invoke method like the hook of MFC, it intercept the message, inject the custom logic and generate a new message
///
for system to performance.
///
</summary>
class
AOPRealProxy : RealProxy, IProxyDI
{
private
MarshalByRefObject _target
=
null
;
private
IInterception _interception
=
null
;
public
AOPRealProxy(Type targetType, MarshalByRefObject target)
:
base
(targetType)
{
_target
=
target;
_interception
=
new
NullInterception();
}
///
<summary>
///
Overridden the method "Invoke" of the base class, invokes the method that is specified
//
in the provided System.Runtime.Remoting.Messaging.IMessage on the remote
//
object that is represented by the current instance.
///
</summary>
///
<param name="msg">
A System.Runtime.Remoting.Messaging.IMessage that contains a System.Collections.IDictionary
//
of information about the method call.
//
</param>
///
<returns>
The message returned by the invoked method, containing the return value and
//
any out or ref parameters.
//
</returns>
public
override
System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
{
IMethodReturnMessage methodReturnMessage
=
null
;
IMethodCallMessage methodCallMessage
=
msg
as
IMethodCallMessage;
//
Check whether the message is method call message.
if
(methodCallMessage
!=
null
)
{
IConstructionCallMessage constructionCallMessage
=
methodCallMessage
as
IConstructionCallMessage;
if
(constructionCallMessage
!=
null
)
//Constructor Method.
{
RealProxy defaultProxy
=
RemotingServices.GetRealProxy(_target);
defaultProxy.InitializeServerObject(constructionCallMessage);
methodReturnMessage
=
EnterpriseServicesHelper.CreateConstructionReturnMessage(constructionCallMessage, (MarshalByRefObject)GetTransparentProxy());
//Create the message about constructor.
}
else
//Other method except constructor method.
{
_interception.PreInvoke();
//Inject PreInvoke method.
try
{
methodReturnMessage
=
RemotingServices.ExecuteMessage(_target, methodCallMessage);
//Invoke subject method.
}
catch
{
}
if
(methodReturnMessage.Exception
!=
null
)
{
_interception.ExceptionHandle();
//Occur exception and then inject ExceptionHandle method.
}
else
{
_interception.PostInvoke();
//Inject PostInvoke method.
}
}
}
return
methodReturnMessage;
}
#region
IProxyDI Members
///
<summary>
///
Dependency injection the interception into proxy class.
///
</summary>
///
<param name="interception">
The interception.
</param>
public
void
InterceptionDI(IInterception interception)
{
_interception
=
interception;
//The pattern of interface inject, inject the interception.
}
#endregion
}
}
使用接口注入方式,将Interception“拦截器”注入到“AOPRealProxy”类。
注入接口“IProxyDI”设计如下:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.AOP
{
interface
IProxyDI
{
void
InterceptionDI(IInterception interception);
}
}
1) 实现Proxy模式AOP:
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Landpy.AOP
{
public
class
ProxyFactory
{
public
static
T CreateProxyInstance
<
T
>
(IInterception interception)
where
T :
new
()
{
Type serverType
=
typeof
(T);
MarshalByRefObject target
=
Activator.CreateInstance(serverType)
as
MarshalByRefObject;
AOPRealProxy aopRealProxy
=
new
AOPRealProxy(serverType, target);
aopRealProxy.InterceptionDI(interception);
return
(T)aopRealProxy.GetTransparentProxy();
}
}
}
实现了interception参数注入AOPRealProxy,将包装完成的传输代理类返回。此时返回的代理类对象操作起来如同直接操作“主题”。
2)实现Attribute模式AOP
代码
//
//
Authors:
//
Xiaoliang Pang (mailto:[email protected])
//
//
Copyright (c) 2010 Landpy Software
//
//
http://www.cnblogs.com/pangxiaoliang
//
using
System;
using
System.Runtime.Remoting.Proxies;
namespace
Landpy.AOP
{
///
<summary>
///
Description of AOPProxyAttribute.
///
</summary>
[AttributeUsage(AttributeTargets.Class)]
public
class
AOPProxyAttribute : ProxyAttribute
{
private
IInterception _interception;
public
Type Interception
{
get
{
return
_interception.GetType();
}
set
{
IInterception interception
=
Activator.CreateInstance(value)
as
IInterception;
_interception
=
interception;
}
}
public
AOPProxyAttribute()
{
_interception
=
new
NullInterception();
}
public
override
MarshalByRefObject CreateInstance(Type serverType)
{
MarshalByRefObject target
=
base
.CreateInstance(serverType);
AOPRealProxy aopRealProxy
=
new
AOPRealProxy(serverType, target);
aopRealProxy.InterceptionDI(_interception);
return
aopRealProxy.GetTransparentProxy()
as
MarshalByRefObject;
}
}
}
实现了interception的Attribute用type注入AOPRealProxy,将包装完成的传输代理类返回。此时返回的代理类对象操作起来如同直接操作“主题”。
测试AOP框架
(一)测试代理模式AOP。
// Proxy class to implement the AOP.
IInterception interception = new MyInterception();
AOPTestWithProxyClass aopTestTwo = ProxyFactory.CreateProxyInstance<AOPTestWithProxyClass>(interception) as AOPTestWithProxyClass;
aopTestTwo.Show();
首先实例化了一个MyInterception的拦截器,然后用ProxyFactory将Interception作为传入注入“主题”。
MyInterception实现如下:
代码
///
<summary>
///
The interception of the AOP.
///
</summary>
class
MyInterception : IInterception
{
#region
IInterception Members
///
<summary>
///
Before invoke the real instance to do something.
///
</summary>
public
void
PreInvoke()
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
===Pre MyInterception.===
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
///
<summary>
///
End invoke the real instance to do something.
///
</summary>
public
void
PostInvoke()
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
===Post MyInterception.===
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
///
<summary>
///
Handling the exception which occurs when the method is invoked.
///
</summary>
public
void
ExceptionHandle()
{
Console.ForegroundColor
=
ConsoleColor.Red;
Console.WriteLine(
"
There is a exception!
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
#endregion
}
AOPTestWithProxyClass实现如下:
代码
///
<summary>
///
The test class for AOP use proxy class.
///
</summary>
class
AOPTestWithProxyClass : ContextBoundObject
{
public
void
Show()
{
Console.ForegroundColor
=
ConsoleColor.Gray;
Console.WriteLine(
"
Hello, I am AOPTestTwo.
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
}
结果:
可见"===Pre MyInterception.==="和"===Post MyInterception.==="已经成功实现AOP注入。
(二)测试Attribute实现AOP。
// Attribute to implement the AOP.
AOPTestWithAttribute aopTest = new AOPTestWithAttribute();
aopTest.Show();
此时的代码要比Proxy实现更为简单,直接用类的构造函数实现类的实例化,不用ProxyFactory生成实例,Interception同样还是使用了MyInterception。
AOPTestWithAttribute类的实现如下:
代码
///
<summary>
///
The test class for AOP use attribute..
///
</summary>
[AOPProxy(Interception
=
typeof
(MyInterception))]
class
AOPTestWithAttribute : ContextBoundObject
{
public
void
Show()
{
Console.ForegroundColor
=
ConsoleColor.Gray;
Console.WriteLine(
"
Hello, I am AOPTest.
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
}
结果:
(三)测试Attribute实现AOP[事务的提交和回滚]。
AOPTestWithAttributForTrasaction aopTestWithAttributForTrasaction = new AOPTestWithAttributForTrasaction();
// Execute the transaction successfully.
aopTestWithAttributForTrasaction.ExecuteTransactionSuccessfully();
WriteSplitLine();
// Execute the transaction unsuccessfully.
try
{
aopTestWithAttributForTrasaction.ExecuteTransactionUnsuccessfully();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(ex.Message);
Console.ForegroundColor = ConsoleColor.Gray;
}
在ExecuteTransactionUnsuccessfully方法中加入throw Excetpion代码,实现执行不成功的情况。当执行ExecuteTransactionSuccessfully方法时实现事务的提交,当执行ExecuteTransactionUnsuccessfully实现事务的回滚,此时的例子可以对照前面所将的Castle ActiveRecord的事务实现AOP的例子。
AOPTestWithAttributForTrasaction实现如下:
代码
[AOPProxy(Interception
=
typeof
(TransactionInterception))]
class
AOPTestWithAttributForTrasaction : ContextBoundObject
{
public
void
ExecuteTransactionSuccessfully()
{
Console.WriteLine(
"
Execute the transaction successfully:)
"
);
}
public
void
ExecuteTransactionUnsuccessfully()
{
Console.WriteLine(
"
Execute the transaction unsuccessfully:(
"
);
throw
new
AOPNullException();
}
}
Interception使用了新的TransactionInterception,TransactionInterception的实现如下:
代码
///
<summary>
///
The interception of the AOP for trasaction.
///
</summary>
class
TransactionInterception : IInterception
{
#region
IInterception Members
public
void
ExceptionHandle()
{
Console.ForegroundColor
=
ConsoleColor.Red;
Console.WriteLine(
"
☆☆☆Rollback transaction☆☆☆
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
public
void
PostInvoke()
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
☆☆☆Commit transaction☆☆☆
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
public
void
PreInvoke()
{
Console.ForegroundColor
=
ConsoleColor.Green;
Console.WriteLine(
"
☆☆☆Begin transaction☆☆☆
"
);
Console.ForegroundColor
=
ConsoleColor.Gray;
}
#endregion
}
结果:
注意:在Debug下执行到“throw new AOPNullException();”时会停止,继续F5即可执行,如果非Debug状态(如直接双击exe执行),则可以执行到结束。
这是由Debug机制造成的,不必在意。
本人实现的AOP框架是基于ContextBoundObject,MarshalByRefObject的,在效率上会差一些,当然我们可以用反射的高级内容Emit直接生成IL注入原始程序逻辑来实现AOP,有空写篇文章介绍下:)
<<完整Demo下载>>