引言
AOP的意思是面向方面编程,英文全称是Aspect Oriented Programming,它的作用是讲彼此先和在一起的功能分离开,简单来说就是解耦和。
原理:
我们编写应用程序时,通常包含两种代码:一种是和业务系统有关的代码,一是和业务系统关系不大的代码,例如日志、权限、异常处理、事务处理等。以前编写代码时,这两种代码基本是写在一起的,这样在程序中,到处充满着相同或类似的代码,例如日志信息的输出,每个方法都要写日志的输出,不利于程序的维护。而AOP就是使这两种代码分离的思想。使用AOP,就不用在业务逻辑中实现与业务功能关系不大的代码,从而降低了两种代码的耦合性,达到易于维护和重用的目的。
当然我觉得,现在我们使用AOP已经不仅仅满足于日志、权限、异常处理、事务处理,可以将一些经常公用的代码抽出来作为切面,这个时候,当我们那个系统用就可以调用这个切面。当然我觉得这面也可以有跟业务有关的方法,同样可以作为切面使用。
AOP的简单解释:基本上每个方法都要用日志进行记录,那么如果按照面向对象的思路来说,就是每个对象都有记录日志这样一个行为。要在每个方法里添加日志的信息,必然会产生大量的重复代码,但可以将记录日志看作是一个横切面,所有对这些方法的调用都要经过这个横切面,然后在这个横切面进行记录日志的操作,这样就达到代码重用和易于维护的目的了,这就是AOP的思想。
实现:
AOP的两种方法:
1、作为构造器参数,通过参数将对象注入到另外一个对象中。
2、我们可以将依赖对象交给外部容器负责创建。就是依赖注入,依赖注入就是指在运行期,由外部容器动态地将依赖对象注入到组件中。
我们现在只用第2种方法实现:
实现方法:通过XML文件进行依赖注入,将方法拦截,拦截的方法通过三种方式来将切面切入方法中。
实现代码:
1、MVC中建立的架构:
2、然后IService.cs类:
<span style="font-family:SimSun;font-size:18px;">using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebDemo
{
public interface IService
{
IList FindAll();
void Save(object entity);
void AddString(string entity);
void DeleteString(object entity);
}
}</span>
CategoryService.cs类集成了IService类:
<span style="font-family:SimSun;font-size:18px;">using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebDemo.Models;
namespace WebDemo
{
public class CategoryService : IService
{
public IList FindAll()
{
return new ArrayList();
}
public void Save(object entity)
{
Console.WriteLine("保存:" + entity);
}
public void AddString(string entity)
{
//Console.WriteLine("添加:" + entity);
SchoolDbContext dbContext = new SchoolDbContext();
UserInfo user = new UserInfo() { UName = entity, UPwd = "123" };
MemcacheHelper.Set(entity, user, DateTime.Now.AddMinutes(20));
dbContext.UserInfo.Add(user);
dbContext.SaveChanges();
}
public void DeleteString(object entity)
{
//Console.WriteLine("删除:" + entity);
}
}
}</span>
在ProduciService.cs类,该类继承了IService:
<span style="font-family:SimSun;font-size:18px;">using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebDemo.Models;
using ITOO.Library.Core.Memcache;
namespace WebDemo
{
public class ProductService : IService
{
public IList FindAll()
{
return new ArrayList();
}
public void Save(object entity)
{
Console.WriteLine("保存:" + entity);
}
public void AddString(string entity)
{
//Console.WriteLine("添加:" + entity);
string connectionString = "Data Source=192.168.24.233;user id=sa;password=123456;persist security info=True;database=" + entity;
SchoolWoeDbContext dbContext1 = new SchoolWoeDbContext(connectionString);
UserInfo m2 = new UserInfo();
UserInfo m1 = (UserInfo)ITOO.Library.Core.Memcache.MemcacheHelper.GetObject(m2, entity);
dbContext1.UserInfo.Add(m1);
dbContext1.SaveChanges();
}
public void DeleteString(object entity)
{
//Console.WriteLine("删除:" + entity);
}
}
}</span>
3、Advice中的三个类的代码为:
AfterAdvice类:
<span style="font-family:SimSun;font-size:18px;">using AopAlliance.Intercept;
using Spring.Aop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebDemo
{
public class AfterAdvice : IAfterReturningAdvice
{
public void AfterReturning(object returnValue, System.Reflection.MethodInfo method, object[] args, object target)
{
Console.WriteLine("开始: " + method.Name);
}
}
}</span>
AroundAdvice类:
<span style="font-family:SimSun;font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AopAlliance.Intercept;
namespace WebDemo
{
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;
}
}
}</span>
BeforeAdvice类:
<span style="font-family:SimSun;font-size:18px;">using AopAlliance.Intercept;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebDemo
{
public class BeforeAdvice : Spring.Aop.IMethodBeforeAdvice,IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
object result = invocation.Proceed();
Console.WriteLine("前置开始: " + invocation.TargetType.Name + "." + invocation.Method.Name);
Console.WriteLine("前置结束: " + invocation.TargetType.Name + "." + invocation.Method.Name);
return result;
}
public void Before(System.Reflection.MethodInfo method, object[] args, object target)
{
Console.WriteLine("前置结束: " + method.Name );
}
}
}
</span>
3、配置XML节点:
在<configSections>节点中添加节点:
<span style="font-family:SimSun;font-size:18px;"> <sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup></span>
在<configuration>中添加:
<span style="font-family:SimSun;font-size:18px;"> <spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
<description>配置实现AOP</description>
<!--必须要写的,不让不能拦截,对象名切入点:ObjectNameAutoProoxyCreateor-->
<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>beforeAdvisor</value>-->
<!--<value>afterAdvisor</value>-->
<value>AroundAdvisor</value>
</list>
</property>
</object>
<!--加载 外部方法-->
<!--<object id="afterAdvice" type="Common.AfterAdvice, Common"/>-->
<object id="AroundAdvice" type="WebDemo.AroundAdvice, WebDemo"/>
<!--<object id="beforeAdvice" type="Common.BeforeAdvice, Common"/>-->
<!--配置 要拦截的类-->
<object id="categoryService" type="WebDemo.ProductService, WebDemo"/>
<object id="productService" type="WebDemo.ProductService, WebDemo"/>
<!--必须要写的,不让不能拦截,对象名切入点:ObjectNameAutoProoxyCreateor-->
<!--拦截使用的方法-->
<!--<object id="beforeAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">-->
<!--<object id="afterAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="Advice" ref="afterAdvice"/>-->
<object id="AroundAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="Advice" ref="AroundAdvice"/>
<property name="MappedNames">
<list>
<!--方法名的匹配-->
<!--<value>*</value>-->
<!--<value>Find*</value>-->
<!--<value>Save*</value>
<value>del*</value>
<value>query*</value>-->
<value>Add*</value>
<value>Del*</value>
</list>
</property>
</object>
<!--<object id="beforeAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
<property name="Advice" ref="beforeAdvice"/>
<property name="MappedNames">
<list>
-->
<!--方法名成的匹配-->
<!--
<value>Find*</value>
<value>Save*</value>
</list>
</property>
</object>-->
</objects>
</spring>
</span>
上面的配置就是我将所有的categoryService和productService中的Add和Del开头的方法全部拦截,之后通过AroundAdvice方法进行切入。这个时候,其实我们可以通过Memcached来讲所有的变量进行传递,这样就可以实现方法与方法之间的参数传递了。
4、测试方法:
在AOPController中:
<span style="font-family:SimSun;font-size:18px;">using Spring.Context;
using Spring.Context.Support;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebDemo.Models;
namespace WebDemo.Controllers
{
public class AOPController : Controller
{
//
// GET: /AOP/
public ActionResult Index()
{
return View();
}
public String Search(string item)
{
IApplicationContext ctx = ContextRegistry.GetContext();
IDictionary speakerDictionary = ctx.GetObjectsOfType(typeof(IService));//把所有的实现IService接口的类都加载出来
foreach (DictionaryEntry entry in speakerDictionary)
{
string name = (string)entry.Key; //获取类的方法名称
IService service = (IService)entry.Value; //获取该类
Console.WriteLine(name + " 拦截: ");
service.AddString("qmx"); //需要通过AOP拦截的方法
}
return "123";
}
}
}</span>
在Index.cshtml文件中:
<span style="font-family:SimSun;font-size:18px;">@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<input type="button" id="button" value="拦截Add" οnclick="add()" />
<script type="text/javascript">
function add() {
var item = "qmx";
$.get("/AOP/Search/", { item: item }, function (string) {
alert("添加成功!");
});
}
</script></span>
这样一个简单的AOP就做出来了。
总结:
AOP是一种思想,不是一种技术,这种思想通过容器的思想,以依赖注入的形式,将业务与业务之间进行了解耦,在很大程度上减少了我们的代码量。AOP的实现还有很多,但是大体上的本质是不会变的,变的可能就实现AOP的方式了。