前言
     这几天在配置Spring.NET,配到AOP的时候发现自己现在还是没有理解到Spring AOP的实现,只是认识到了一个思想,以前配的时候,看的是给好的例子用,真正用的时候还是要想一下,所以写个笔记,深刻的认识一下。

初探AOP
    对AOP的初步理解是在《JAVA给力起飞》那一本书。当时一句话给我一种醍醐灌顶的感觉:AOP(面向切面编程),为什么要叫面向切面编程?把一个类看成一个树轮,在面向横切逻辑,也就是在开发中遇到的一些通用问题,比如性能检测,访问控制,事务管理以及日志记录等等,以前的解决办法是给每一个类里面都加上这些东西,这样就遇到一个问题:类于类之间强烈耦合,要新增修改删除这个功能你要在代码级别修改代码,
我们无法通过抽象父类消除上面说的 重复性代码,因为这些代码依附在业务逻辑中了。AOP独辟蹊径,不通过纵向架构,而是横向的看代码,把这些横向的逻辑代码抽取出来,做成一个独立的模块。
    抽取出来比较容易,但如何将这些独立的模块整合起来,这才是事情的关键,这也是AOP所要解决的问题。


                                        
   

AOP的相关术语
 
   参考




.NET中模拟代理

准备工作
1.
 public class CompanyDao
    {
        public void Save()
        {
            Console.WriteLine("保存数据");
        }
    }

2.
 public interface ICompanyManager
    {
        string UserName { get; set; }

        void Save();
    }
3.
    public interface ISecurityManager
    {
        bool IsPass(string userName);
    }


解释一下场景,这个是一个保存用户的模块,我们希望在保存用户前验证这个用户是否具有相应权限来做操作。我们通常会这样做:

4.
 public class SimpleCompanyManager : ICompanyManager
    {
        #region 可通过外部注入的属性

        public string UserName { get; set; }

        public CompanyDao Dao { get; set; }

        #endregion

        public void Save()
        {
            //判断权限
            ISecurityManager security = new SecurityManager();
            if (security.IsPass(UserName))
            {
                //执行业务方法
                //.......
                //调用DAO层方法
                Dao.Save();
            }
            else
            {
                //执行其它业务方法...
                Console.WriteLine("您没有该权限");
            }
        }
    }


这样就出现一个问题
SimpleCompanyManager 这个类依赖了
SecurityManager,发生了业务性的耦合。我们用代理模式来实现看看会发生什么。

什么是代理模式?是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。

将之前的业务逻辑分割出来。

 public class CompanyManager : ICompanyManager
    {
        #region 可通过外部注入的属性

        public string UserName { get; set; }

        public CompanyDao Dao { get; set; }

        #endregion

        public void Save()
        {
            //执行业务方法
            //.......
            //调用DAO层方法
            Dao.Save();
        }
    }


然后做一个代理类

public class CompanyProxyManager : ICompanyManager
    {
        public string UserName { get; set; }

        private ICompanyManager target = new CompanyManager();

        public void Save()
        {
            //判断权限
            ISecurityManager security = new SecurityManager();
            if (security.IsPass(UserName))
            {
                //调用目标对象Save方法
                target.Save();
            }
            else
            {
                Console.WriteLine("您没有该权限");
            }
        }
    }


CompanyManager类就不必与判断权限的类
SecurityManager耦合,相当于是加了一层,但这样实现起来比较麻烦这样,

下面我们看看Spring是怎么帮我们处理的

 
 
public class AroundAdvice : IMethodInterceptor
    {
        //权限系统类(可外部注入)
        private ISecurityManager manager = new Service.SecurityManager();

        public object Invoke(IMethodInvocation invocation)
        {
            //拦截Save方法
            if (invocation.Method.Name == "Save")
            {
                ICompanyManager target = (ICompanyManager)invocation.Target;

                return manager.IsPass(target.UserName) ? invocation.Proceed() : null;
            }
            else
            {
                return invocation.Proceed();
            }
        }
    }


class Program
    {
        static void Main(string[] args)
        {
            ICompanyManager target = new CompanyManager() { Dao = new CompanyDao(), UserName = "admin" };
            
            ProxyFactory factory = new ProxyFactory(target);
            factory.AddAdvice(new AroundAdvice());

            ICompanyManager manager = (ICompanyManager)factory.GetProxy();
            manager.Save();

            Console.ReadLine();
        }
    }

                            
和JAVA版的Spring如出一辙,在JAVA中,如果使用CGLIB的动态代理,那个代理类实现的是
MethodInterceptor这个接口(JDK的动态代理接口为
InvocationHandler,在
java.lang.reflect这个包里面)。.NET里的spring只是少了一个I!如此看来语言是相通的,特别对于统一框架而言:D。   (
其实实际的项目经常用的是@Aspectj注解,支持正则表达式,用起来更加方便)

有关CGLIB:利用CGLIB可以为任何类创建织入横切逻辑对象的代理创建器,CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。
CGLIB是一个强大的高性能的
代码生成
包。它广泛的被许多AOP的
框架
使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

其中Invoke的方法就是讲横切逻辑代码和业务逻辑代码编织到一起了,这里很像我们以前软件体系结构的作业,只是当时没想到这些 :(
Program里的代码很简单,先实例化出业务逻辑模块,这个就是目标对象,用来组装的,将其托管到
ProxyFactory,然后加入
Advice(通知,感觉叫增强更合适),最后使用
GetProxy获取代理,执行方法。



AOP的通知类型
    参考


Spring.Net的自动代理
    如果应用程序需要创建很多
AOP代理,比如当需要代理某个服务层的所有对象时,这种方法就会使配置文件变的相当庞大。为简化配置过程,Spring.NET提供了“
自动代理”的功能,可以根据条件自动创建
代理对象,也就是说,可以将多个对象分组以作为要代理的候选对象。
自动代理使用起来比较简单和方便.

1.对象名称切入点
    首先准备增强类

    public class AroundAdvice : IMethodInterceptor
    {
        public object Invoke(IMethodInvocation invocation)
        {
            Console.WriteLine("开始:  " + invocation.TargetType.Name + "." + invocation.Method.Name);
            object result = invocation.Proceed();
            Console.WriteLine("结束:  " + invocation.TargetType.Name + "." + invocation.Method.Name);
            return result;
        }
    }

配置对增强类的配置

      <object id="aroundAdvisor" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
        <property name="Advice" ref="aroundAdvice"/>
        <property name="Attribute"
                  value="ConfigAttribute.Attributes.ConsoleDebugAttribute, ConfigAttribute" />
      </object>
    <object id="aroundAdvice" type="Common.AroundAdvice, Common"/>

准备好要注入的目标类,也就是业务类

public class AttributeService : IService
    {
        [ConsoleDebug]
        public IList FindAll()
        {
            return new ArrayList();
        }

        public void Save(object entity)
        {
            Console.WriteLine("保存:" + entity);
        }
  }

<object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">


<property name="ObjectNames">
<list>
<value>*Service</value>
</list>
</property>


<property name="InterceptorNames">
<list>
<value>aroundAdvice</value>
</list>
</property>
</object>

<object id="aroundAdvice" type="Common.AroundAdvice, Common"/>

<object id="categoryService" type="Service.ProductService, Service"/>
<object id="productService" type="Service.ProductService, Service"/>



使用ObjectNameAutoProxyCreator经常需要对要拦截的方法进行筛选,这时到Spring.Aop.Support.NameMatchMethodPointcutAdvisor,稍微修改一下配置:

<object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
<property name="ObjectNames">
<list>
<value>*Service</value>
</list>
</property>
<property name="InterceptorNames">
<list>
<value>aroundAdvisor</value>
</list>
</property>
</object>

<object id="aroundAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="Advice" ref="aroundAdvice"/>
<property name="MappedNames">
<list>
<value>Find*</value>
</list>
</property>
</object>

<
objec
t id="aroundAdvice" type="Common.AroundAdvice, Common"/>


2.正则表达式切入点


<object id="aroundAdvisor" type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice" ref="aroundAdvice"/>
<property name="patterns">
<list>
<value>.*Find*.*</value>
</list>
</property>
</object>

<!--
必须让Spring.NET容器管理DefaultAdvisorAutoProxyCreator类
-->


<object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>

<object id="aroundAdvice" type="Common.AroundAdvice, Common"/>

<object id="categoryService" type="Service.ProductService, Service"/>
<object id="productService" type="Service.ProductService, Service"/>


以上配置相对复杂一点。使用SdkRegularExpressionMethodPointcut的配置就相对简单的多,而项目中SdkRegularExpressionMethodPointcut也经常用到。
SdkRegularExpressionMethodPointcut只需要简单的配置一下通知和切入点就完成了。

  1. <object id="advisor" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
  1. <property name="pattern" value="Service.*"/>
  2. </object>
  3.  
  4. <aop:config>
  5. <aop:advisor pointcut-ref="advisor" advice-ref="aroundAdvice"/>
  6. </aop:config>
  7.  
  8. <object id="aroundAdvice" type="Common.AroundAdvice, Common"/>
  9.  
  10. <object id="categoryService" type="Service.ProductService, Service"/>
  11. <object id="productService" type="Service.ProductService, Service"/>
  1.  
  1. 是不是和JAVASpring XML配置完全一样?:D
  1.  
  1. 3.属性切入点
  1.  
  1. public
  2.  
  3. class ConsoleDebugAttribute : Attribute
  4.  
  5. {
  6.  
  7. }
  8.  
  9. public
  10.  
  11. class AttributeService : IService
  12.  
  13. {
  14.  
  15. [ConsoleDebug]
  16.  
  17. public IList FindAll()
  18.  
  19. {
  20.  
  21. return
  22.  
  23. new ArrayList();
  24.  
  25. }
  26.  
  27. public
  28.  
  29. void Save(object entity)
  30.  
  31. {
  32.  
  33. Console.WriteLine("保存:"
  34.  
  35. + entity);
  36.  
  37. }
  38.  
  39. }
  1.  
  1. JAVA版的是注解,下面是配置文件
  1.  
  1. <object id="aroundAdvisor" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop">
  2. <property name="Advice" ref="aroundAdvice"/>
  3. <property name="Attribute"
  4. value="ConfigAttribute.Attributes.ConsoleDebugAttribute, ConfigAttribute" />
  5. </object>
  6.  
  7. <object id="proxyFactoryObject" type="Spring.Aop.Framework.ProxyFactoryObject">
  8. <property name="Target">
  9. <object type="ConfigAttribute.Service.AttributeService, ConfigAttribute" />
  10. </property>
  11. <property name="InterceptorNames">
  12. <list>
  13. <value>aroundAdvisor</value>
  14. </list>
  15. </property>
  16. </object>
  17.  
  18. <object id="aroundAdvice" type="Common.AroundAdvice, Common"/>
  1. 以上所有源码下载
  1.  
  1.  

对Spring.Net的AOP一些思考及应用的更多相关文章

  1. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  2. Spring中的AOP

    什么是AOP? (以下内容来自百度百科) 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种 ...

  3. Spring Boot2(六):使用Spring Boot整合AOP面向切面编程

    一.前言 众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转.本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理. 二.何为aop ​ aop全称Aspec ...

  4. Spring 3.0 AOP (一)AOP 术语

    关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...

  5. Spring系列之AOP实现的两种方式

    AOP常用的实现方式有两种,一种是采用声明的方式来实现(基于XML),一种是采用注解的方式来实现(基于AspectJ). 首先复习下AOP中一些比较重要的概念: Joinpoint(连接点):程序执行 ...

  6. Spring MVC 线程安全问题的思考

    Spring MVC 线程安全问题的思考 在读一些博文的时候发现有些文章对SpringMVC的Controller线程安全的验证并不正确,比如没有探究controller线程不安全的具体原因,比如将请 ...

  7. springMVC+MyBatis+Spring 整合(4) ---解决Spring MVC 对AOP不起作用的问题

    解决Spring MVC 对AOP不起作用的问题 分类: SpringMVC3x+Spring3x+MyBatis3x myibaits spring J2EE2013-11-21 11:22 640 ...

  8. Spring核心框架 - AOP的原理及源码解析

    一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置A ...

  9. Spring IOC及AOP学习总结

    一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...

随机推荐

  1. fmri的图像数据在matlab中显示,利用imagesc工具进行显示,自带数据集-by 西南大学xulei教授

    这里包含了这样一个数据集:slice_data.mat. 这个数据集中包含的mri数据是:64*64*25.共有25个slice.每个slice的分辨率是64*64. 程序非常简短: load sli ...

  2. Java中String为什么是final

    final概念: 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父亲被继承.因此,一个类不能既被声明为abstract,又被声明为final. 将变量或方法声明为final,可以 ...

  3. dynamic_cast

    作为四个内部类型转换操作符之一的dynamic_cast和传统的C风格的强制类型转换有着巨大的差别.除了dynamic_cast以外的转换,其行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转 ...

  4. Linux下的Memcache安装

    Linux下Memcache服务器端的安装服务器端主要是安装memcache服务器端,目前的最新版本是 memcached-1.3.0 .下载:http://www.danga.com/memcach ...

  5. Ext.Loader

    Ext.Loader是Ext JS4动态加载的核心,等价于Ext.require简写. Ext.Loader支持异步和同步加载的方法. 异步 优点: 1.跨域 2.不需要web服务器 3.调试方便(可 ...

  6. cppunit使用详解

    cppunit使用详解 第一步:如何安装 (我的运行环境: fc7 Linux, gcc4)    cppunit 的安装是相当标准的linux的安装过程    a. 下载cppunit的源文件    ...

  7. 关于div居中

    margin : 100px; margin-left: auto; margin-right: auto; 这样子设置css样式就可以实现一个div居中

  8. [Papers]NSE, $u$, Lorentz space [Bjorland-Vasseur, JMFM, 2011]

    $$\bex \int_0^T\frac{\sen{\bbu}_{L^{q,\infty}}^p}{\ve+\ln \sex{e+\sen{\bbu}_{L^\infty}}}\rd s<\in ...

  9. JDBC数据源(DataSource)的简单实现

    数据源技术是Java操作数据库的一个很关键技术,流行的持久化框架都离不开数据源的应用.   数据源提供了一种简单获取数据库连接的方式,并能在内部通过一个池的机制来复用数据库连接,这样就大大减少创建数据 ...

  10. Java并发编程-synchronized

    多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题.同步机制可以使用synchronized关键字实现.synchronized关 ...