Spring.NET学习笔记12——面向切面编程(基础篇) Level 300

  AOP面向切面编程(Aspect Oriented Programming的缩写),是OOP(面向对象编程)的一种延续形式。是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,它从一个不同于OOP的角度来看待程序的结构:OOP将应用程序分解为一系列表现为继承关系的对象;AOP 则把程序分解为一系列方面(aspects)或者关注点(concerns)。AOP将诸如事务管理等本来横向分布在多个对象中的关注点进行了模块化处理(这些关注点也常称为横切(crosscutting)关注点)。在Spring.NET中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

  下面我举个例子来说明这一切:

  场景:业务类CompanyManager在调用Save方法的时候需要调用SecurityManager类判断权限是否足够(图1)。

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300图1

 

  准备条件:

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public class CompanyDao
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public void Save()
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            Console.WriteLine(
"保存数据");
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public interface ICompanyManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
string UserName getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
void Save();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public interface ISecurityManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
bool IsPass(string userName);
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public class SecurityManager : ISecurityManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
/// <summary>
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
/// 判断权限
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
/// </summary>
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
/// <param name="userName"></param>
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
/// <returns></returns>

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        public bool IsPass(string userName)
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
return userName == "admin";
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

  第一种实现方式,我们通常会这样做:直接在CompanyManager类中调用ISecurityManager接口的IsPass方法判断权限。

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300public class SimpleCompanyManager : ICompanyManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
#region 可通过外部注入的属性
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public string UserName getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public CompanyDao Dao getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
#endregion

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public void Save()
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//判断权限
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
            ISecurityManager security = new SecurityManager();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
if (security.IsPass(UserName))
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
//执行业务方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
//Spring.NET学习笔记12——面向切面编程(基础篇) Level 300Spring.NET学习笔记12——面向切面编程(基础篇) Level 300.
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
//调用DAO层方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
                Dao.Save();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
else
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
//执行其它业务方法Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
                Console.WriteLine("您没有该权限");
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

  这样CompanyManager类与ISecurityManagerSecurityManager会发生业务性耦合。聪明的朋友会发现在GOF(设计模式)中有一种模式(代理模式)可以解除这种耦合。

  第二种实现方式,代理模式(Proxy Pattern):什么是代理模式?是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入(图2)。
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300图2

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public class CompanyManager : ICompanyManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
#region 可通过外部注入的属性
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public string UserName getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public CompanyDao Dao getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
#endregion

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public void Save()
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//执行业务方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//Spring.NET学习笔记12——面向切面编程(基础篇) Level 300Spring.NET学习笔记12——面向切面编程(基础篇) Level 300.
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//调用DAO层方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
            Dao.Save();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public class CompanyProxyManager : ICompanyManager
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public string UserName getset; }
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
private ICompanyManager target = new CompanyManager();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public void Save()
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//判断权限
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
            ISecurityManager security = new SecurityManager();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
if (security.IsPass(UserName))
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
//调用目标对象Save方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
                target.Save();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
else
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                Console.WriteLine(
"您没有该权限");
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

  这样,CompanyManager类就不必与判断权限的类SecurityManager耦合,但是这种方式实现起来比较麻烦。
 

  第三种实现方式,Spring.NET提供的AOPAopAlliance.Intercept.IMethodInterceptor接口和ProxyFactory类的组合。

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    public class AroundAdvice : IMethodInterceptor
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
//权限系统类(可外部注入)
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
        private ISecurityManager manager = new Service.SecurityManager();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
public object Invoke(IMethodInvocation invocation)
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
//拦截Save方法
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
            if (invocation.Method.Name == "Save")
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                ICompanyManager target 
= (ICompanyManager)invocation.Target;
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
return manager.IsPass(target.UserName) ? invocation.Proceed() : null;
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
else
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300                
return invocation.Proceed();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    class Program
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
static void Main(string[] args)
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        
{
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            ICompanyManager target 
= new CompanyManager() { Dao = new CompanyDao(), UserName = "admin" };
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            ProxyFactory factory 
= new ProxyFactory(target);
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            factory.AddAdvice(
new AroundAdvice());
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            ICompanyManager manager 
= (ICompanyManager)factory.GetProxy();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            manager.Save();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300            Console.ReadLine();
Spring.NET学习笔记12——面向切面编程(基础篇) Level 300        }

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300    }

 

  输出:保存数据
  

 

  Spring.NET利用System.Reflection.Emit命名空间下的类在运行时动态创建IL代码来生成AOP代理。这使得代理(的创建)非常高效,并且不受任何继承层次的限制。

 

  参考:Spring.NET中文手册

  李会军博客代理模式http://www.cnblogs.com/terrylee/archive/2006/05/18/403382.html

 

  代码下载
 

 

  返回目录

作者:刘冬.NET 博客地址:http://www.cnblogs.com/GoodHelper/ 欢迎转载,但须保留版权