底层之Spring.net AOP

        在我么一直依靠这面向对象来让我们的程序变的复用性高的时候,我们是否发现了,即使这么牛的面向对象,有时候还是让我们看起来非常的累赘。如果你不能理解我这句话,那么请根据我的问题,看一下下边这段代码,问题是:我有学生类和实现类,都要去实现登陆的功能。

       OOP

        学生类

public class Student
{
    public void Login()
    {
       验证安全性
       //执行前记录日志;

       DoSomething();

       保存逻辑运算后的数据;
       执行结束记录日志;
    }
}

       教师类:

public class Teacher
{
    public void Login()
    {
       验证安全性
       执行前记录日志;

       DoSomething();

       保存逻辑运算后的数据;
       执行结束记录日志;
    }
}
      通过上边的代码大家可以发现,如果我要实现登陆功能,那么我就要验证安全性,然后事前记录,事后记录日志。。。等等的工作,关键是这些工作我再每一个类里边都是这么复制粘贴的实现的,如果类多的话我们发现我们的工作又是重复了。可是我们明明是按照面向对象的思想去做的呀,怎么会出问题呢,所以咱们就再给大家一个新的概念,AOP(Aspect Oriented Programming),面向切面编程。

       AOP

       所谓的面向切面编程,就是把一些和类没有非常重要的关系的方法给抽象出来,什么是不是非常重要的呢,就是权限验证,日志记录这些,他们和业务逻辑没有什么关系,却必须在每个类里边协商这么几个方法,不觉的很多余吗,但是运用AOP的思想,我们把他们取出来,然后用的时候给他切进去,所以叫做面向切面编程,如下图。

技术分享

       那么说了这么多给大家看一个小小的Demo

       我们要拦截的方法

       接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Service
{
    public interface IService
    {
        string FindAll();

        void Save(object entity);
    }
}

       实现类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Service
{
    public class SaveMessageService:IService
    {

        public string FindAll()
        {
            return "123";
        }

        public void Save(object entity)
        {
           
            Console.WriteLine("name " + entity);
        }
    }
}

       AOP的切面:

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);
            Console.WriteLine("结束时间: " + DateTime.Now.ToString());
            string message = invocation.TargetType.Name + "." + invocation.Method.Name;
            message += DateTime.Now.ToString();
            //向文本文档中添加记录
            InputTxt(message);
            return result;
        }
}

      客户端:

class Program
    {
        static void Main(string[] args)
        {
            IApplicationContext ctx = ContextRegistry.GetContext();
            IDictionary speakerDictionary = ctx.GetObjectsOfType(typeof(IService));
            foreach (DictionaryEntry entry in speakerDictionary)  
            {
                string name = (string)entry.Key;
                IService service = (IService)entry.Value;
                Console.WriteLine(name + " 拦截: ");

                service.FindAll();

                Console.WriteLine();

                service.Save("数据");
                
                Console.WriteLine();
            }


            Console.ReadLine();
        }

          配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <spring>

    <context>
      <resource uri="config://spring/objects" />
    </context>

    <objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
      <description>配置实现AOP</description>
      
      <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>

      <object id="aroundAdvice" type="Common.AroundAdvice, Common"/>
      <object id="saveMessageService" type="Service.SaveMessageService, Service"/>
    </objects>

  </spring>

</configuration>
          其实这个过程也是非常的简单,aroundAdvice是一个拦截器,用来拦截方法,至于那些方法,我们根据XML文件的配置,设置拦截的方法和类名称,这样我们的拦截器就可以知道我拦截的名表的名称,至于日志记录的方法,我们不需要关心,我们只写好自己的业务逻辑就可以。其他的交给AOP和Ioc容器来管理。

       现在我们根据上边的实现了AOP的一个思想的例子,来解释一下AOP的一些名词。

       Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。程序里的切面就是AroundAdvise类的实现部分。

       joinpoint(连接点):所谓连接点是指那些被拦截到的点。在Spring.NET中,连接点指的是方法,因为Spring.NET只支持方法类型的连接点,实际上joinpoint(连接点)还可以是字段或类构造器。程序里的连接点就是拦截到的方法,如SaveMessageService类的Save方法。

        Advice(通知或增强):所谓通知是指拦截到joinpoint(连接点)之后所要做的事情就是Advice.通知或增强分为前置Advice,后置Advice,异常Advice,环绕Advice。AroundAdvise继承AopAlliance.Intercept.IMethodInterceptor 接口,程序里使用的是环绕通知。

      Target(目标对象):代理的目标对象。程序里的目标对象就是SaveMessageService类,我们通过ProxyFactory factory = new ProxyFactory(new SaveMessageService() );这句代码确定了目标对象是SaveMessageService。

      AOP代理(AOP proxy):由AOP框架在将通知应用于目标对象后创建的对象。程序里通过GetProxy()方法创建出的代理对象。
      Introduction(引入):在不修改类代码的前提下,Introduction(引入):可以在运行期为类动态地添加一些方法或字段。程序里在没有修改OrderService类,而是在运行期把判断权限的功能通过ProxyFactory的AddAdvice方法动态的增加进去。
  这些术语不属于Spring.NET,而属于整个AOP编程。所谓AOP,我的理解就是应该是这样一个过程,首先需要定义一个切面,这个切面是一个类,里面的方法就是关注点(也是通知),或者说里面的方法就是用来在执行目标对象方法时需要执行的前置通知,后置通知,异常通知,最终通知,环绕通知等等。有了切面和通知,要应用到目标对象,就需要定义这些通知的切入点,换句话说就是需要对哪些方法进行拦截,而这些被拦截的方法就是连接点,所谓连接点也就是在动态执行过程,被织入切面的方法(至少在Spring.NET中只能对方法进行拦截)。因此,在动态过程中通知的执行就属于织入过程,而被织入这些通知的对象就是目标对象了。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。