Spring.Net AOP的通知类型及通知链

  首先介绍AOP通知的概念。

  通知(Advice):AOP框架在某个连接点(方法)中所采取的行为。在Spring.Net的通知类型分为环绕通知、前置通知、后置通知、异常通知。这四中通知类型以及这几通知综合运用形成的通知链。

  关于各种通知类型我实现的编程方式、配置方式两种给大家介绍。这一节主要说说上述通知类型中的后三种通知,前一种通知在上一节中已经做了说明,所以不作为本节的重点了,但是几种通知的应用大致是一样的。

  本节重点分如下两部分:

  一、AOP的四种通知类型。

  二、通知链的应用

  首先还是介绍一下开发环境以及软件版本:

  VS版本:VS2008 SP1、Spring版本:1.3.0。

  一、AOP四种通知类型介绍

  1、前置通知。我理解的前置通知是在目标对象连接点执行前的通知。

  编程方式实现。这种方式主要应用了程序集Spring.Net中Spring.Aop.Framework命名空间下的ProxyFactory(代理工厂)类和Spring.Aop命名控件下的IMethodBeforeAdvice接口。

目标对象的代码如下:  

代码
   
   
1 public interface ICommand
2 {
3 void Execute();
4 }
5
6 class ServiceCommand:ICommand
7 {
8 public void Execute()
9 {
10 Console.WriteLine( " ServiceCommand execute " );
11 }
12 }

通知的实现代码:

代码
   
   
1 class ConsoleLoggingBeforeAdvice:IMethodBeforeAdvice
2 {
3 public void Before(MethodInfo method, object [] args, object target)
4 {
5 Console.WriteLine( " Method name is :{0} " , method.Name);
6 if (args != null )
7 {
8 if (args.Length > 0 )
9 {
10 for ( int i = 0 ; i < args.Length; i ++ )
11 {
12 Console.WriteLine( " the {0} position argments in args is {1} " , i, args[i]);
13 }
14 }
15 }
16 else
17 {
18 Console.WriteLine( " args is null " );
19 }
20 Console.WriteLine( " the type target is {0} " ,target.GetType().ToString());
21 }
22 }

实现代码如下:

 

 

代码
   
   
1 ProxyFactory factory = new ProxyFactory( new ServiceCommand());
2 factory.AddAdvice( new ConsoleLoggingBeforeAdvice());
3 ICommand command = (ICommand)factory.GetProxy();
4 command.Execute();

运行结果图如下:

 

Spring.Net AOP的通知类型及通知链

  配置方式实现。配置代码如下:

 

代码
   
   
1 < objects xmlns = " http://www.springframework.net " xmlns:aop = " http://www.springframework.net/aop " >
2 < object id = " myServiceObject " type = " Spring.Aop.Framework.ProxyFactoryObject " >
3 < property name = " Target " >
4 < object type = " SpringBeforeAdvice.ServiceCommand " singleton = " 0 " ></ object >
5 </ property >
6 < property name = " InterceptorNames " >
7 < list >
8 < value > beforeAdvice </ value >
9 </ list >
10 </ property >
11 </ object >
12 < object id = " beforeAdvice " type = " SpringBeforeAdvice.ConsoleLoggingBeforeAdvice " ></ object >
13 </ objects >

实现代码如下:

代码
   
   
1 IApplicationContext context = ContextRegistry.GetContext();
2 ICommand command2 = (ICommand)context[ " myServiceObject " ];
3 command2.Execute();
4 IDictionary dic = context.GetObjectsOfType( typeof (ICommand));
5 foreach (DictionaryEntry item in dic)
6 {
7 Console.WriteLine( " key is :{0},value is :{1} " , item.Key, item.Value);
8 }

运行结果如下图:

 

Spring.Net AOP的通知类型及通知链

可以看到:出了运行连接点Execute执行运行的代码以外,还有通知采取的行为(Before的执行)。如果通过断点调试,可以看到在连接点执行前,Before执行了。

  2、后置通知。后置通知正好是前置通知相反,是在目标对象连接点执行后的通知。它是实现了Spring.Aop命名空间下的IAfterReturningAdvice接口。

  编程方式实现。

  目标对象的实现代码和前置通知实现方式相同,这里就不给出实现代码了。后置通知的实现代码是:

 

代码
   
   
1 class ConsoleLoggingAfterAdvice: IAfterReturningAdvice
2 {
3 public void AfterReturning( object returnValue, MethodInfo method, object [] args, object target)
4 {
5 if (returnValue != null )
6 {
7 Console.WriteLine( " the type of returnValue is :{0},returnValue is {1} " , returnValue.GetType().ToString(), returnValue);
8 }
9 Console.WriteLine( " method name is {0} " , method.Name);
10 if (args != null && args.Length > 0 )
11 {
12 foreach ( object obj in args)
13 {
14 Console.WriteLine(obj);
15 }
16 }
17 Console.WriteLine( " the type of target is :{0},returnValue is {1} " , target.GetType().ToString(), target);
18 }
19 }

使用代码:

代码
   
   
1 ICommand target = new ServiceCommand();
2 ProxyFactory factory = new ProxyFactory(target);
3 factory.AddAdvice( new ConsoleLoggingAfterAdvice());
4
5 ICommand command = (ICommand)factory.GetProxy();
6 command.Execute( " test string " );

运行结果如下图:

 

Spring.Net AOP的通知类型及通知链

  配置方式实现。配置文件如下:

 

代码
   
   
1 < objects xmlns = " http://www.springframework.net " xmlns:aop = " http://www.springframework.net/aop " >
2
3 < object id = " myServiceObject " type = " Spring.Aop.Framework.ProxyFactoryObject " >
4 < property name = " Target " >
5 < object type = " SpringAfterAdvice.ServiceCommand " ></ object >
6 </ property >
7 < property name = " InterceptorNames " >
8 < list >
9 < value > afterAdvice </ value >
10 </ list >
11 </ property >
12 </ object >
13
14 < object id = " afterAdvice " type = " SpringAfterAdvice.ConsoleLoggingAfterAdvice " ></ object >
15 </ objects >

实现代码:

 

  
  
1 IApplicationContext context = ContextRegistry.GetContext();
2 ICommand command2 = (ICommand)context[ " myServiceObject " ];
3 command2.Execute( " config string " );

运行结果如下图:

 

Spring.Net AOP的通知类型及通知链

  与前置通知相反,后置通知在目标对象连接点执行后再执行。

  3、异常通知。我理解的是当目标对象的连接点执行出现异常的时候执行。异常通知是实现了Spring.Aop命名空间下的IThrowingAdvice接口。

  编程方式实现:

  异常通知实现代码如下:
 

代码
    
    
1 public void AfterThrowing(FormatException ex)
2 {
3 Console.WriteLine("异常通知执行");
4 Console.WriteLine(ex.Message);
5 }
6
7
8 public void AfterThrowing(UnauthorizedAccessException ex)
9 {
10 Console.Out.WriteLine("Advised method threw this exception : " + ex);
11 }

  使用代码如下:

 

代码
   
   
1 ICommand target = new ServiceCommand();
2 ProxyFactory factory = new ProxyFactory(target);
3 factory.AddAdvice( new AroudAdvice());
4 factory.AddAdvice( new ConsoleLoggingThrowsAdvice());
5
6 ICommand command = (ICommand)factory.GetProxy();
7 command.Execute();

 

 

Spring.Net AOP的通知类型及通知链

 

  配置方式实现。配置文件如下:

代码
   
   
1 < objects xmlns = " http://www.springframework.net " xmlns:aop = " http://www.springframework.net/aop " >
2
3 < object id = " myServiceObject " type = " Spring.Aop.Framework.ProxyFactoryObject " >
4 < property name = " Target " >
5 < object type = " SpringExceptionAdvice.ServiceCommand " ></ object >
6 </ property >
7 < property name = " InterceptorNames " >
8 < list >
9 < value > aroundAdvice </ value >
10 < value > exceptionAdvice </ value >
11 </ list >
12 </ property >
13 </ object >
14
15 < object id = " exceptionAdvice " type = " SpringExceptionAdvice.ConsoleLoggingThrowsAdvice " ></ object >
16 < object id = " aroundAdvice " type = " SpringExceptionAdvice.AroudAdvice " ></ object >
17 </ objects >
使用代码如下:

  
  
1 IApplicationContext context = ContextRegistry.GetContext();
2 ICommand command2 = (ICommand)context[ " myServiceObject " ];
3 command2.Execute();
运行结果如下图:

Spring.Net AOP的通知类型及通知链

  注意:异常通知实现的IThrowsAdvice中没有任何方法。但是它的实现类中必须实现public void AfterThrowing方法。并且只有目标对象的连接点执行过程中发生异常类型与AfterThrowing方法的参数一样时,异常通知才会发生。当然,AfterThrowing可以有很多重载。

  二、通知链

  1、编程方式实现。各种通知的实现代码如下:

代码
   
   
1 // 前置通知
2   class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
3 {
4 public void Before(MethodInfo method, object [] args, object target)
5 {
6 Console.WriteLine( " 前置通知执行 " );
7 Console.WriteLine( " method name is {0} " ,method.Name);
8 if (args != null )
9 {
10 for ( int i = 0 ; i < args.Length; i ++ )
11 {
12 Console.WriteLine( " the {0} position args is :{1} " , i, args[i]);
13 }
14 }
15 Console.WriteLine( " type of target is :{0} " , target.GetType().ToString());
16
17 }
18 }
19
20   // 环绕通知
21   class ConsoleLoggingAroundAdvice:IMethodInterceptor
22 {
23 public object Invoke(IMethodInvocation invocation)
24 {
25 object obj = null ;
26 Console.WriteLine( " 环绕通知执行 " );
27 try
28 {
29 obj = invocation.Proceed();
30 }
31 catch
32 {
33 Console.WriteLine( " 目标方法执行异常 " );
34 }
35 return obj;
36 }
37 }
38
39 // 后置通知
40   class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
41 {
42 public void AfterReturning( object returnValue, MethodInfo method, object [] args, object target)
43 {
44 Console.WriteLine( " 后置通知执行 " );
45 if (returnValue != null )
46 {
47 Console.WriteLine( " returnValue is :{0} " ,returnValue);
48 }
49 Console.WriteLine( " method name is :{0} " , method.Name);
50 if (args != null )
51 {
52 for ( int i = 0 ; i < args.Length; i ++ )
53 {
54 Console.WriteLine( " the {0} position args is :{1} " ,i,args[i]);
55 }
56 }
57 Console.WriteLine( " type of target is :{0} " ,target.GetType().ToString());
58
59 }
60 }
61
62   // 异常通知
63   class ConsoleLoggingThrowsAdvice:IThrowsAdvice
64 {
65 public void AfterThrowing(FormatException ex)
66 {
67 Console.WriteLine( " 发生异常通知 " );
68 Console.WriteLine(ex.Message);
69 }
70 }
使用代码如下:

代码
   
   
1 ProxyFactory factory = new ProxyFactory( new ServiceCommand());
2
3 factory.AddAdvice( new ConsoleLoggingBeforeAdvice());
4 factory.AddAdvice( new ConsoleLoggingAroundAdvice());
5 factory.AddAdvice( new ConsoleLoggingAfterAdvice());
6 factory.AddAdvice( new ConsoleLoggingThrowsAdvice());
7
8 ICommand command = (ICommand)factory.GetProxy();
9 command.Execute( " spring advice link ---programming " );
运行结果如下:

Spring.Net AOP的通知类型及通知链

  注意织入方式,即factory.AddAdvice添加通知的顺序。我个人感觉应该按照前置--环绕--后置的方式来进行织入。如果我改成

    factory.AddAdvice(new ConsoleLoggingAroundAdvice());
            factory.AddAdvice(new ConsoleLoggingAfterAdvice());
            factory.AddAdvice(new ConsoleLoggingBeforeAdvice());

则运行结果如下图:

Spring.Net AOP的通知类型及通知链

  2、配置方式实现

  配置文件如下:

代码
   
   
1 < objects xmlns = " http://www.springframework.net " xmlns:aop = " http://www.springframework.net/aop " >
2 < object id = " myServiceObj " type = " Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop " >
3 < property name = " Target " >
4 < object id = " serviceCommand " type = " SpringAdviceLink.ServiceCommand " ></ object >
5 </ property >
6 < property name = " InterceptorNames " >
7 < list >
8 < value > beforAdvice </ value >
9 < value > aroundAdvice </ value >
10 < value > afterAdvice </ value >
11 < value > exceptionAdvice </ value >
12 </ list >
13 </ property >
14 </ object >
15
16 < object id = " beforAdvice " type = " SpringAdviceLink.ConsoleLoggingBeforeAdvice " ></ object >
17 < object id = " aroundAdvice " type = " SpringAdviceLink.ConsoleLoggingAroundAdvice " ></ object >
18 < object id = " afterAdvice " type = " SpringAdviceLink.ConsoleLoggingAfterAdvice " ></ object >
19 < object id = " exceptionAdvice " type = " SpringAdviceLink.ConsoleLoggingThrowsAdvice " ></ object >
使用方式如下:

  
  
1 IApplicationContext context = ContextRegistry.GetContext();
2 ICommand command2 = (ICommand)context[ " myServiceObj " ];
3 command2.Execute( " spring advice link ---config " );
运行结果如下图:

Spring.Net AOP的通知类型及通知链

  在配置方式实现中,也要注意<property name="InterceptorNames"/>中list列表中的中值的顺序,顺序不一样执行的结果也不一样。我个人觉得应该是前置--环绕--后置的方式进行配置,至于异常通知的配置由于是连接点执行异常时才执行,所以它的为位置关系不重要。

  总结:环绕通知实现的是AopAlliance.Intercept命名控件下的IMethodInterceptor接口前置通知、后置通知、异常通知分别实现的是Spring.Aop命名空间下的IMethodBeforeAdvice、IAfterReturningAdvice、IThrowsAdvice接口.IThrowsAdvice的实现类必须有AfterThrowing方法,并且AfterThrowing可以有各种异常类型作为参数的重载。

  参考文档Spring.Net参考框架.

  代码下载:代码Demo

 

 

 

 

 

你可能感兴趣的:(spring)