一、引言 在前面一专题介绍到,要让缓存生效还需要实现对AOP(面向切面编程)的支持。所以本专题将介绍了网上书店案例中AOP的实现。关于AOP的概念,大家可以参考文章:http://www.cnblogs.com/jin-yuan/p/3811077.html。这里我简单介 ...
一、引言
在前面一专题介绍到,要让缓存生效还需要实现对AOP(面向切面编程)的支持。所以本专题将介绍了网上书店案例中AOP的实现。关于AOP的概念,大家可以参考文章:http://www.cnblogs.com/jin-yuan/p/3811077.html。这里我简单介绍下AOP:AOP可以理解为对方法进行截获,这样就可以在方法调用前或调用后插入需要的逻辑。例如可以在方法调用前,加入缓存查找逻辑等。这里缓存查找逻辑就在方法调用前被执行。通过对AOP的支持,每个方法就可以分为3部分了,方法调用前逻辑->具体需要调用的方法->方法调用后的逻辑。也就是在方法调用的时候“切了一刀”。
二、网上书店AOP的实现
你可以从零开始去实现AOP,但是目前已经存在很多AOP框架了,所以在本案例中将直接通过Unity的AOP框架(Unity.Interception)来实现网上书店对AOP的支持。通常AOP的实现放在基础设施层进行实现,因为可能其他所有层都需要加入对AOP的支持。本案例中将对两个方面的AOP进行实现,一个是方法调用前缓存的记录或查找,另一个是方法调用后异常信息的记录。在实现具体代码之前,我们需要在基础设施层通过Nuget来引入Unity.Interception包。添加成功之后,我们需要定义两个类分别去实现AOP框架中IInterceptionBehavior接口。由于本案例中需要对缓存和异常日志功能进行AOP实现,自然就需要定义CachingBehavior和ExceptionLoggingBehavior两个类去实现IInterceptionBehavior接口。首先让我们看看CachingBehavior类的实现,具体实现代码如下所示:
// 缓存AOP的实现 public class CachingBehavior : IInterceptionBehavior { private readonly ICacheProvider _cacheProvider; public CachingBehavior() { _cacheProvider = ServiceLocator.Instance.GetService<ICacheProvider>(); } // 生成缓存值的键值 private string GetValueKey(CacheAttribute cachingAttribute, IMethodInvocation input) { switch (cachingAttribute.Method) { // 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除 case CachingMethod.Remove: return null; // 如果是Get或者Update,则需要产生一个针对特定参数值的键名 case CachingMethod.Get: case CachingMethod.Update: if (input.Arguments != null && input.Arguments.Count > 0) { var sb = new StringBuilder(); for (var i = 0; i < input.Arguments.Count; i++) { sb.Append(input.Arguments[i]); if (i != input.Arguments.Count - 1) sb.Append("_"); } return sb.ToString(); } else return "NULL"; default: throw new InvalidOperationException("无效的缓存方式。"); } } #region IInterceptionBehavior Members public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { // 获得被拦截的方法 var method = input.MethodBase; var key = method.Name; // 获得拦截的方法名 // 如果拦截的方法定义了Cache属性,说明需要对该方法的结果需要进行缓存 if (!method.IsDefined(typeof (CacheAttribute), false)) return getNext().Invoke(input, getNext); var cachingAttribute = (CacheAttribute)method.GetCustomAttributes(typeof (CacheAttribute), false)[0]; var valueKey = GetValueKey(cachingAttribute, input); switch (cachingAttribute.Method) { case CachingMethod.Get: try { // 如果缓存中存在该键值的缓存,则直接返回缓存中的结果退出 if (_cacheProvider.Exists(key, valueKey)) { var value = _cacheProvider.Get(key, valueKey); var arguments = new object[input.Arguments.Count]; input.Arguments.CopyTo(arguments, 0); return new VirtualMethodReturn(input, value, arguments); } else // 否则先调用方法,再把返回结果进行缓存 { var methodReturn = getNext().Invoke(input, getNext); _cacheProvider.Add(key, valueKey, methodReturn.ReturnValue); return methodReturn; } } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } case CachingMethod.Update: try { var methodReturn = getNext().Invoke(input, getNext); if (_cacheProvider.Exists(key)) { if (cachingAttribute.IsForce) { _cacheProvider.Remove(key); _cacheProvider.Add(key, valueKey, methodReturn.ReturnValue); } else _cacheProvider.Update(key, valueKey, methodReturn); } else _cacheProvider.Add(key, valueKey, methodReturn.ReturnValue); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } case CachingMethod.Remove: try { var removeKeys = cachingAttribute.CorrespondingMethodNames; foreach (var removeKey in removeKeys) { if (_cacheProvider.Exists(removeKey)) _cacheProvider.Remove(removeKey); } // 执行具体截获的方法 var methodReturn = getNext().Invoke(input, getNext); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } default: break; } return getNext().Invoke(input, getNext); } public bool WillExecute { get { return true; } } #endregion }
原标题:[.NET领域驱动设计实战系列]专题九:DDD案例:网上书店AOP和站点地图的实现
关键词:.NET
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:
admin#shaoqun.com
(#换成@)。