Castle AspectSharp 外部配置方式 测试分析

F:\开源项目\Dot Net\Castle.NET\Castle-src\Facilities\AspectSharp\AspectSharp.sln

1. ExternalConfigurationTestCase.cs 外部配置测试

using  System;

    
using  NUnit.Framework;

    
using  Castle.Model.Configuration;

    
using  Castle.Windsor;

    
using  Castle.Facilities.AspectSharp.Tests.Components;
    
using  Castle.Facilities.AspectSharp.Tests.Interceptors;

    
///   <summary>
    
///  Summary description for ExternalConfigurationTestCase.
    
///   </summary>
    [TestFixture]
    
public   class  ExternalConfigurationTestCase
    {
        [Test]
        
public   void  ExternalConfigurationUsage()
        {
            WindsorContainer container 
=   new  WindsorContainer(  " ../aop_castle_config.xml "  );

            container.AddFacility( 
" aspectsharp " new  AspectSharpFacility() );
            
            
//  Logger implementation
            container.AddComponent(  " logger " typeof (ILogger),  typeof (MemoryLogger) );

            
//  AopAlliance interceptors
            container.AddComponent(  " log4netinterceptor " typeof (LoggerTraceInterceptor) );
            
            
//  Protocol handlers
            container.AddComponent(  " protocolhandler.miranda "
                
typeof (IProtocolHandler),  typeof (MirandaProtocolHandler) );
            container.AddComponent( 
" protocolhandler.messenger "
                
typeof (IProtocolHandler),  typeof (MessengerProtocolHandler) );
            
            
//  using

//             ILogger logger = (ILogger) container[ typeof(ILogger) ];
//             Assert.AreEqual( 0, logger.Contents.Length );

            IProtocolHandler handler 
=  (IProtocolHandler) 
                container[ 
" protocolhandler.miranda "  ];
            handler.Handle( 
" contents "  );

            handler 
=  (IProtocolHandler) container[  " protocolhandler.messenger "  ];
            handler.Handle( 
" contents "  );

//             Assert.AreEqual( "Entering Handle Leaving Handle Entering Handle Leaving Handle ", 
//                 logger.Contents );
        }
    }

WindsorContainer 产生的 container 是 Castle 的 IoC 容器,用于动态产生类实例或根据接口动态产生类实例。也可以根据键值从容器中取出实例。

IProtocoHandler handler = (IProtocoHandler) container[ "protocolhandler.miranda" ] 这种调用在失败时会产生异常,

IProtocoHandler handler = container[ "protocolhandler.miranda" ] as IProtocoHandler 这种调用在失败时会使 handler 为 null 。

handler 是两个基于 IProtocolHandler 接口的业务级的例程,Handle(string) 是业务逻辑性质的方法体,没有现实的业务意义,只是用于演示。

2. 象征性的业务性质的 handler 例程 MirandaProtocolHandler.cs

using  System;

    
///   <summary>
    
///  Summary description for MirandaProtocolHandler.
    
///   </summary>
     public   class  MirandaProtocolHandler : IProtocolHandler
    {
        
public  MirandaProtocolHandler()
        {
        }

        
#region  IProtocolHandler Members

        
public   void  Handle(String contents)
        {
            Console.WriteLine(
" MirandaProtocolHandler is handling contents  " );
        
        }

        
#endregion
    }

MessengerProtocolHandler 与此一模一样,不同的只是 Handle 方法体的输出信息内容把 Miranda 改为 Messenger。

3. 『logger』,MemoryLogger.cs

这是 1. 中向 IoC container 使用 AddComponent 添加的第一个类

     using  System;
    
using  System.Text;

    
///   <summary>
    
///  Summary description for MemoryLogger.
    
///   </summary>
     public   class  MemoryLogger : ILogger
    {
        
private  StringBuilder _messages  =   new  StringBuilder();

        
public  MemoryLogger()
        {
        }

        
#region  ILogger Members

        
public   void  Trace(String content)
        {
            Console.WriteLine(
" Tracing  "   +  content  +   "   " );
        }

        
public   void  Enter(String name)
        {
            _messages.Append(
" Entering  "   +  name  +   "   " );
            Console.WriteLine(
" Entering  "   +  name  +   "   " );
        }

        
public   void  Leave(String name)
        {
            _messages.Append(
" Leaving  "   +  name  +   "   " );
            Console.WriteLine(
" Leaving  "   +  name  +   "   " );
        }

        
public  String Contents
        {
            
get  {  return  _messages.ToString(); }
        }

        
#endregion
    }

这是测试过程中需要用到的 logger 实例的类声明。实现了 ILogger 接口。

测试用例中只使用了 Enter 和 Leave 两个方法。假设如果成功的话,进入某个方法时会象征性输出日志“Entering....”而结束某方法时会象征性输出日志“Leaving....”

4. 『横切面拦截机』LoggerTraceInterceptor.cs

拦截机是 AOP 的精髓之一,面向方面编程(AOP)意义等同于面向『横切面』编程。在 Castle AspectSharp 的测试用例中展示的都是 AOP 中的 advice 机制,而且都是 around 的,可以自主选择在方法之前还是之后或者两者皆有的地方添加执行横切面性质的额外方法。

     using  System;

    
using  AopAlliance.Intercept;

    
using  Castle.Facilities.AspectSharp.Tests.Components;

    
///   <summary>
    
///  AopAlliance interceptor, however kept within the container
    
///   </summary>
     public   class  LoggerTraceInterceptor : IMethodInterceptor
    {
        
private  ILogger _logger;

        
public  LoggerTraceInterceptor(ILogger logger)
        {
            _logger 
=  logger;
        }

        
public   object  Invoke(IMethodInvocation invocation)
        {
            Console.WriteLine(
" \nLoggerTraceIntercepter stand by  \n " );

            _logger.Enter( invocation.Method.Name );

            
object  value  =  invocation.Proceed();

            _logger.Leave( invocation.Method.Name );

            
return  value;
        }
    }

注意
1) 继承了 IMethodInterceptor,告诉 AspectSharp 这是个方法级的拦截机,AspectSharp 还提供了 IConstructoriInterceptor 用于实现针对构造函数的拦截机。
2)这里需要预先注入 logger 实例, 构造式注入
3)object value = invocation.Proceed() 指示执行原本的业务方法
4)在 Invoke 方法体内声明了在执行原本的业务方法之前和之后各记录一条日志(Enter 和 Leave),这也就是拦截机的作用。
5)object value = .... 然后必须做 return value ,这是为了实现正常业务逻辑上的对象返回。当然,如果在 invocation.Proceed() 时产生了异常就不会执行 _logger.Leave 和 return value 了。
6) 注意 LoggerTraceInterceptor 在代码中是有(且需要)显式声明的,在 ExternalConfigurationTestCase.cs 中,这说明使用 拦截机需要『入侵』代码,而下面的 Mixin 混入不需要在代码中声明

5. 『Mixin(混入)』SecurityMixin.cs

using  AspectSharp.Core;


namespace  Castle.Facilities.AspectSharp.Tests.Components
{
    

    
using  System;

    
///   <summary>
    
///  Summary description for SecurityMixin.
    
///   </summary>
     public   class  SecurityMixin : IProxyAware
    {
        
public  SecurityMixin()
        {
        }

        
public   void  SetProxy( object  proxy)
        {
            Console.WriteLine(
" \nSecurityMixin setting proxy\n " );
            
        }
    }
}

这个 Mixin 没有出现在 ExternalConfigurationTestCase.cs 代码中,因为它在下面的 aop_castle_config.xml 中声明了,而且在初始化 WindsorContainer IoC 容器时已经载入了这个外部配置文件。

测试输出表明,这个 Mixin 优先于拦截机 Interceptor 执行,且对于每次执行 Handle() 方法仅在最开头时执行一次。

6. 外部配置文件 ..\aop_castle_config.xml

< configuration >

    
< facilities >
        
< facility  id ="aspectsharp" >
        
<![CDATA[
        import Castle.Facilities.AspectSharp.Tests.Components in Castle.Facilities.AspectSharp.Tests 
        import Castle.Facilities.AspectSharp.Tests.Interceptors in Castle.Facilities.AspectSharp.Tests 
        
        interceptors [ "key" : LoggerTraceInterceptor ] 
        mixins [ "key" : SecurityMixin  ] 

        aspect ProtocolHandlerLogger for [ assignableFrom(IProtocolHandler) ]  
            include "key" 

            pointcut method(*) 
                advice("key") 
            end 
        end 
        
]]>
        
</ facility >
    
</ facilities >

</ configuration >


import .... in .... 完整语法是 import OneNameSpace in OneAssembly 声明了从某个 .NET 程序集中引入命名空间

interceptors [ "key" : LoggerTraceInterceptor ]  声明拦截机,且把 LoggerTraceInterceptor 命名为 "key"
mixins [ "key" : SecurityMixin ] 声明混淆,且把 SecurityMixin 命名为 "key"

aspect ProtocolHandlerLogger 这个只是 aspect 的命名而已,就像类的命名一样

for [ assignableFrom(IProtocolHandler) ]  指示凡实现 IProtocolHandler 接口的类都适用于这个 aspect 过程

如果是 for MirandaProtocolHandler 则是只有 MirandaProtocolHandler 这个类适用于这个 aspect 过程

include "key" 引用之前声明命名为 "key" 的拦截机和混淆

advice("key") 执行名为 "key" 的拦截和混淆,测试输出标明 Mixin 优先于拦截机执行

7. 测试输出

------ Test started: Assembly: Castle.Facilities.AspectSharp.Tests.dll ------


SecurityMixin setting proxy...


LoggerTraceIntercepter stand by ...

Entering Handle
MirandaProtocolHandler is handling contents ...
Leaving Handle

SecurityMixin setting proxy...


LoggerTraceIntercepter stand by ...

Entering Handle
MessengerProtocolHandler is handling contents ...
Leaving Handle

1 passed, 0 failed, 0 skipped, took 1.64 seconds.



 


Links:

张老三的 Aspect# 文章

http://www.narchitecture.net/Articles/ArticleList.aspx?category=8

你可能感兴趣的:(Aspect)