1. 什么是MEF

    Git:https://github.com/MicrosoftArchive/mef

    MEF也是一款ioc框架,貌似历史比较悠久了。

    这里有一篇.net阵容里面主流ioc比较。

    https://www.cnblogs.com/liping13599168/archive/2011/07/17/2108734.html

     

  2. AOP

    引用百度。

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  3. 背景

    线上有个报表项目,最近监控发现有个报表查询比较频繁,导致db压力大,现需要对查询频次较多的报表进行缓存。

     

  4. 代码实现

    Nugget 引用Castle.Core

    1自定义ExportProved

public
class
AOPExportProvider : ExportProvider, IDisposable

{

private
CatalogExportProvider _exportProvider;

 

public AOPExportProvider(Func<ComposablePartCatalog> catalogResolver)

{

_exportProvider = new
CatalogExportProvider(catalogResolver(),true);

 

//support recomposition

_exportProvider.ExportsChanged += (s, e) => OnExportsChanged(e);

_exportProvider.ExportsChanging += (s, e) => OnExportsChanging(e);

}

 

 

public
ExportProvider SourceProvider

{

get

{

return _exportProvider.SourceProvider;

}

set

{

_exportProvider.SourceProvider = value;

}

}

 

 

protected
override
IEnumerable<Export> GetExportsCore(

ImportDefinition definition, AtomicComposition atomicComposition)

{

IEnumerable<Export> exports = _exportProvider.GetExports(definition, atomicComposition);

return exports.Select(export => new
Export(export.Definition, () => GetValue(export)));

}

 

private
object GetValue(Export innerExport)

{

var value = innerExport.Value;

IInterceptor[] attribs = value.GetType().GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();

if (attribs.Length == 0)

return value;

ProxyGenerator generator = new
ProxyGenerator();

object proxy = generator.CreateClassProxy(value.GetType(), attribs);

 

PropertyInfo[] propertyInfo= value.GetType().GetProperties();

Type proxyType = proxy.GetType().BaseType;

foreach (var item in propertyInfo)

{

PropertyInfo property = proxyType.GetProperty(item.Name);

if (property == null) continue;

property.SetValue(proxy, item.GetValue(value,null),null);

}

return proxy;

}

 

 

public
void Dispose()

{

_exportProvider.Dispose();

}

}

 

2 在web启动的时候 指定自定义exportprovide

public
static
class
MefConfig

{

public
static
void RegisterMef()

{

var container = ConfigureContainer();

ControllerBuilder.Current.SetControllerFactory(new
MefControllerFactory(container));

var dependencyResolver = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;

}

 

private
static
CompositionContainer ConfigureContainer()

{

Func<ComposablePartCatalog> catalogResolver = () =>

{

 

AggregateCatalog catalog = new
AggregateCatalog();

catalog.Catalogs.Add(new
DirectoryCatalog(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, "Mw*.dll"));

return catalog;

};

AOPExportProvider provider = new
AOPExportProvider(catalogResolver);

CompositionContainer container = new
CompositionContainer(provider);

provider.SourceProvider = container;

AppDomain.CurrentDomain.SetData("Container", container);

return container;

}

}

3 实现Interceptor

[Export(typeof(IInterceptor))]

public
class
CacheInterceptor : Attribute, IInterceptor

{

private
ICache _cacheProvider;

public CacheInterceptor(){

_cacheProvider = ((CompositionContainer)AppDomain.CurrentDomain.GetData("Container")).GetExportedValue<ICache>();

}

private
char _linkChar = ':';

public
void Intercept(IInvocation invocation)

{

var qCachingAttribute = this.GetQCachingAttributeInfo(invocation.MethodInvocationTarget ?? invocation.Method);

if (qCachingAttribute != null)

{

ProceedCaching(invocation, qCachingAttribute);

}

else

{

invocation.Proceed();

}

}

private
QCachingAttribute GetQCachingAttributeInfo(MethodInfo method)

{

return method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(QCachingAttribute)) as
QCachingAttribute;

}

private
void ProceedCaching(IInvocation invocation, QCachingAttribute attribute)

{

var cacheKey = attribute.Key;

if(string.IsNullOrEmpty(cacheKey))

cacheKey= GenerateCacheKey(invocation);

 

var cacheValue = _cacheProvider.Get(cacheKey, x => { return
null; });

if (cacheValue != null)

{

invocation.ReturnValue = cacheValue;

return;

}

 

invocation.Proceed();

 

if (!string.IsNullOrWhiteSpace(cacheKey))

{

_cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.AbsoluteExpiration));

}

}

private
string GenerateCacheKey(IInvocation invocation)

{

var typeName = invocation.TargetType.Name;

var methodName = invocation.Method.Name;

var methodArguments = this.FormatArgumentsToPartOfCacheKey(invocation.Arguments);

 

return
this.GenerateCacheKey(typeName, methodName, methodArguments);

}

//拼接缓存的键

private
string GenerateCacheKey(string typeName, string methodName, IList<string> parameters)

{

var builder = new
StringBuilder();

 

builder.Append(typeName);

builder.Append(_linkChar);

 

builder.Append(methodName);

builder.Append(_linkChar);

 

foreach (var param in parameters)

{

builder.Append(param);

builder.Append(_linkChar);

}

 

return builder.ToString().TrimEnd(_linkChar);

}

 

private
IList<string> FormatArgumentsToPartOfCacheKey(IList<object> methodArguments, int maxCount = 5)

{

return methodArguments.Select(this.GetArgumentValue).Take(maxCount).ToList();

}

//处理方法的参数,可根据情况自行调整

private
string GetArgumentValue(object arg)

{

if (arg is
int || arg is
long || arg is
string)

return arg.ToString();

 

if (arg is
DateTime)

return ((DateTime)arg).ToString("yyyyMMddHHmmss");

 

if (arg is
IQCachable)

return ((IQCachable)arg).CacheKey;

 

return
null;

}

}

4 定义拦截Attribute

[AttributeUsage(AttributeTargets.Method, Inherited = true)]

public
class
QCachingAttribute: Attribute

{

public
int AbsoluteExpiration { get; set; } = 30;

public
string Key { get; set; }

}

}

5配置使用Interceptor

[Export(typeof(ICompanyDaily))]

[CacheInterceptor]

public
class
CompanyDaily : ICompanyDaily

{

[Import]

public
ItbshopRepository _shopRepository { get; set; }

[QCaching(AbsoluteExpiration =60*60*8)]

public
virtual
DataTable GetSalesDetailStatistics(DateTime sellDateBegin, DateTime sellDateEnd, string sShopGUID, string mAreaId, int classify, string types)

{

string beginDate = sellDateBegin.ToString("yyyy-MM-dd");

string endDate = sellDateEnd.ToString("yyyy-MM-dd");

try

{

//dosomething

return dtChart;

}

catch (Exception exp)

{

throw exp;

}

}

Ps:拦截的方法必须是virtual

让MEF插上AOP的翅膀的更多相关文章

  1. 时序数据库(TSDB)-为万物互联插上一双翅膀

    本文由  网易云发布. 时序数据库(TSDB)是一种特定类型的数据库,主要用来存储时序数据.随着5G技术的不断成熟,物联网技术将会使得万物互联.物联网时代之前只有手机.电脑可以联网,以后所有设备都会联 ...

  2. 让Storm插上CEP的翅膀 - Siddhi调研和集成

    什么是 Siddhi? Siddhi 是一种 lightweight, easy-to-use, open source CEP(Complex Event Processing)引擎,由wso2公司 ...

  3. 插上腾飞的翅膀:为asp.net core添加protobuf支持

    没时间解释了,快上车. 通过NuGet获取Zaabee.AspNetCoreProtobuf Install-Package Zaabee.AspNetCoreProtobuf 在Startup.cs ...

  4. 给PLSQL插上飞翔的翅膀-PLSQL优化

    60-80% of database performance issues are related to poorly performing SQL,60-80%的数据库性能问题要归结于生产中糟糕的S ...

  5. 为Spring Cloud Config插上管理的翅膀

    最近一致在更新Spring Cloud Config的相关内容,主要也是为这篇埋个伏笔,相信不少调研过Spring Cloud Config的用户都会吐槽它的管理能力太弱.因此,就有了下面为讲推荐的这 ...

  6. 插上翅膀,让Excel飞起来——xlwings(二)

    在上一篇插上翅膀,让Excel飞起来——xlwings(一)中提到利用xlwings模块,用python操作Excel有如下的优点: xlwings能够非常方便的读写Excel文件中的数据,并且能够进 ...

  7. Spring Boot (六): 为 JPA 插上翅膀的 QueryDSL

    在前面的文章中,我们介绍了 JPA 的基础使用方式,<Spring Boot (三): ORM 框架 JPA 与连接池 Hikari>,本篇文章,我们由入门至进阶的介绍一下为 JPA 插上 ...

  8. XCode4.5.6,iOS6.1下测试 判断当前设备,及其联网状态等; 关于设备插上后XCode检测不出的情况的说明

    目录[-] 一.判断设备 二.判断网络连接状态 三.设备不显示的解决办法 一.判断设备 01 //设备名称 02 return [UIDevice currentDevice].name; 03   ...

  9. QT使用WOL实现远程一键开机(局域网,需要目标电脑的主板支持,并且插上网线,用udpSocket.writeDatagram一句话就可以)

    功能:让关机的电脑一键开机,需要目标电脑的主板支持,并且插上网线: 效果:相当于手动按了一下目标电脑的开关机按钮. 没啥技术含量,简单开说... 1.获取目标机MAC地址 QByteArray sMa ...

随机推荐

  1. Mac 装Sequel pro 连接 Mysql 8.0 失败、登录不了、loading问题

    最近都没更新博客,零零散散的笔记也都没整理,so 觉得还是不放上来了. 高兴的是入手了期待好久的水果机,开始了各种捣鼓,好想大撸一下代码啊.... 回到正轨,刚装了mysql8.0, 想装下mysql ...

  2. 手把手详解持续集成之GitLab CI/CD

    一.环境准备 首先需要有一台 GitLab 服务器,然后需要有个项目:这里示例项目以 Spring Boot 项目为例,然后最好有一台专门用来 Build 的机器,实际生产中如果 Build 任务不频 ...

  3. 【mysql】 快速搞定数据库迁移

    工具:navicat for mysql

  4. 末学者笔记——SAMBA服务、FTP服务讲解

    samba服务 一.概念: Smb主要作为网络通信协议; Smb是基于cs(client,sever)架构: 完成Linux与windows之间的共享:linux与linux之间共享用NFS   二. ...

  5. C# 模拟键盘操作SendKey(),SendKeys()

    模拟键盘输入就是使用以下2个语法实现的. SendKeys.Send(string keys);  //模拟汉字(文本)输入SendKeys.SendWait(string keys); //模拟按键 ...

  6. Java 多线程系列 CountDownLatch

    CountDownLatch 一个或多个线程等待其他线程完成操作后在在执行 CountDownLatch通过一个计数器来实现,await方法阻塞直到 countDown() 调用计数器归零之后释放所有 ...

  7. redis安装使用

    Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构服务器,因为值(valu ...

  8. Netty5客户端源码解析

    Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...

  9. nginx学习.第一部分

    1.nginx的版本发布历史 2015年支持thread pool提供stream四层反向代理支持reuseport特性,支持http v2协议.完全可以替代LVS 2016年支持动态模块 2.ngi ...

  10. java笔记:排错5:误删maven target:恢复不了,怎么再生成

    上篇讲过,误删maven项目的target,或clean以后,target文件夹会删掉. 想要重新加载模块生成最新的target目录,可以再跑一下tomcat. 但有时不灵,可能是因为Tomcat本身 ...