前言

Autofac的DynamicProxy来自老牌的Castle项目。DynamicProxy(以下称为动态代理)起作用主要是为我们的类生成一个代理类,这个代理类可以在我们调用原本类的方法之前,调用拦截器以实现AOP。那么动态代理是怎么实现的呢,这里简单一下提一下,这里主要是用了emit技术动态生成IL,相当于在内存中用IL给我们编写了一个Class。

通过静态代理实现AOP

我们新建一个类Cat,并实现ICat接口

ICat:

public interface ICat
{
void Eat();
}

Cat:

public class Cat:ICat
{
public void Eat()
{
Console.WriteLine("猫在吃东西");
}
}

然然后我们为其创建一个代理类,CatProxy

public class CatProxy:ICat
{
private readonly ICat _cat;
public CatProxy(ICat cat)
{
_cat = cat;
}
public void Eat()
{
Console.WriteLine("猫吃东西之前");
_cat.Eat();
Console.WriteLine("猫吃东西之后");
}
}

现在我们调用一下试试效果:

public class Progarm
{
static void Main(string[] args)
{
ICat icat=new Cat(); var catProxy=new CatProxy(icat); catProxy.Eat(); Console.Read();
}
}

可以看见,我们已经成功的通过代理实现在猫吃东西之前和之后执行我们定义的代码,这就是一个简单的AOP,这个称之为静态代理,需要我们手动编写代理类,这个是十分耗费时间的,那么有什么方法帮我们自动生成代理呢,当然有了,接下来介绍我们的动态代理。

动态代理(DynamicProxy)实现AOP

我在前言中已经简单提了下动态代理的实现原理,我们这里就只说说怎么用,而不去讨论怎么实现了(烧脑阔)。我们这里使用Autofac的DynamicProxy。

我们依然使用前一章节所用的控制台项目,通过nuget安装两个Package:AutofacAutofac.Extras.DynamicProxy

首先我们需要定义一个拦截器:

public class CatInterceptor:IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("猫吃东西之前");
invocation.Proceed();
Console.WriteLine("猫吃东西之后");
}
}

然后在Autofac容器中注册我们的拦截器和类型:

static void Main(string[] args)
{ var builder = new ContainerBuilder(); builder.RegisterType<CatInterceptor>();//注册拦截器
builder.RegisterType<Cat>().As<ICat>().InterceptedBy(typeof(CatInterceptor)).EnableInterfaceInterceptors();//注册Cat并为其添加拦截器 var container = builder.Build(); var cat = container.Resolve<ICat>(); cat.Eat(); Console.Read();
}

我们运行一下看看效果:

通过运行我们可以看出,和上一章节的效果一样,但是我们并不需要取手动定义我们的代理类,而是通过组件动态生成了。

关于这个拦截器,我们还可以通过Attribute的方式绑定到我们的具体类型,而不需要在注册到容器的时候动态指定。

[Intercept(typeof(CatInterceptor))]
public class Cat:ICat
{
public void Eat()
{
Console.WriteLine("猫在吃东西");
}
}

注册的代码可改为:

builder.RegisterType<Cat>().As<ICat>().EnableInterfaceInterceptors();

动态代理的高级用法

我们前面说了,动态代理是动态生成一个代理类,那么我们可以动态的为这个代理类添加一个接口吗,答案当然是可以。

现在我们定义一个铲屎官类:

public class CatOwner
{ }

可以看出我们的铲屎官类什么都没有,如果我们的铲屎官想喂猫吃东西怎么办,按照我们传统的思维当然是实例化一个cat传入我们的 CatOwner,但是我们可以用我们的DynamicProxy动态生成。

var builder = new ContainerBuilder();

builder.RegisterType<CatInterceptor>();//注册拦截器
builder.RegisterType<Cat>().As<ICat>();//注册Cat
builder.RegisterType<CatOwner>().InterceptedBy(typeof(CatInterceptor))
.EnableClassInterceptors(ProxyGenerationOptions.Default, additionalInterfaces: typeof(ICat));//注册CatOwner并为其添加拦截器和接口
var container = builder.Build(); var cat = container.Resolve<CatOwner>();//获取CatOwner的代理类 cat.GetType().GetMethod("Eat").Invoke(cat, null);//因为我们的代理类添加了ICat接口,所以我们可以通过反射获取代理类的Eat方法来执行 Console.Read();

我们上面的代码是肯定不能运行的,因为我们的代理类虽然添加了ICat接口,但是却没有具体实现它,所以抛出为卫视现异常:

我们可以使用AOP在我们执行代理类的Eat方法之前去调用我们的具体实现Cat的Eat方法,我们修改一下拦截器。

public class CatInterceptor:IInterceptor
{
private readonly ICat _cat; /// <summary>
/// 通过依赖注入 注入ICat的具体实现
/// </summary>
/// <param name="cat"></param>
public CatInterceptor(ICat cat)
{
_cat = cat;
}
public void Intercept(IInvocation invocation)
{
Console.WriteLine("喂猫吃东西"); invocation.Method.Invoke(_cat, invocation.Arguments);//调用Cat的指定方法
}
}

我们看一下运行效果:

可以看见我们从一个什么都没有的CatOwner类,来为其调用了一个具体的猫吃东西的行为,是不是感觉很神奇!

有人可能会说,一个铲屎官为什么要去实现一个ICat接口。我想说纯属胡编乱造,只是想阐明这个用法,这个意思。

应用场景

用过ABP框架的人都应该知道其有个技术名为DynamicWebapi,非常方便可以动态帮我们的应用逻辑层生成webapi,而不需要我们手动去编写webapi来发布。这里据用到了上面所说的技术,动态生成Wabpi Controller,然后为其添加应用逻辑接口,在调用具体的应用逻辑方法时(Action)通过AOP拦截调用具体应用逻辑实现来完成。

Demo:https://github.com/stulzq/BlogDemos/tree/master/AutofacDynamicProxyTest

Autofac高级用法之动态代理的更多相关文章

  1. 【转】Autofac高级用法之动态代理

    原文:http://www.cnblogs.com/stulzq/p/8547839.html 前言 Autofac的DynamicProxy来自老牌的Castle项目.DynamicProxy(以下 ...

  2. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  3. Java EE开发平台随手记5——Mybatis动态代理接口方式的原生用法

    为了说明后续的Mybatis扩展,插播一篇广告,先来简要说明一下Mybatis的一种原生用法,不过先声明:下面说的只是Mybatis的其中一种用法,如需要更深入了解Mybatis,请参考官方文档,或者 ...

  4. Android Data Binding高级用法-Observable、动态生成Binding Class(三)

    设置View的id 虽然说Data Binding这种分层模式使得我们对数据的传递简单明了,一般情况下我们可以不设置View的id,不使用findViewById即可对View进行数据上一系列的操作, ...

  5. Python面试常用的高级用法,怎么动态创建类?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第16篇文章,今天我们来聊聊Python当中的元类. 元类是Python当中的高级用法,如果你之前从来没见过这个术语 ...

  6. java高级---->Java动态代理的原理

    Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程 ...

  7. Spring AOP高级——源码实现(1)动态代理技术

    在正式进入Spring AOP的源码实现前,我们需要准备一定的基础也就是面向切面编程的核心——动态代理. 动态代理实际上也是一种结构型的设计模式,JDK中已经为我们准备好了这种设计模式,不过这种JDK ...

  8. 【java高级编程】JDK和CGLIB动态代理区别

    转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...

  9. [tcpreplay] tcpreplay高级用法--使用tcpreplay-edit进行循环动态发包

    tcpreplay-edit提供了可对包进行修改的高级用法: --unique-ip Modify IP addresses each loop iteration to generate uniqu ...

随机推荐

  1. 重写equals()和hashCode()

    什么时候需要重写equals()? 只有当一个实例等于它本身的时候,equals()才会返回true值.通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相 等.而我们在使用 ...

  2. 插入排序Insertion Sort

    插入排序:将一个数据插入到一个已经排好序的有序数据序列中,从而得到一个新的.个数+1的有序数列:插入排序适用于少量数据排序,时间复杂度为O(n^2). 实现思路:1.对于一个无序数组,选取第一个元素, ...

  3. 对html语义化的理解

    所有人都知道html即超文本标记语言或超文本链接标示语言,是目前网络上应用最为广泛的语言,也是构成网页文档的主要语言. html标签中的大部分都是由"语义化"标签所担任 那么,它有 ...

  4. abp中文件下载,将内存数据导出到Excel并下载

    1.数据导出为Excel的Stream using System; using System.Collections.Generic; using System.IO; using Abp.Colle ...

  5. OSI网络模型

    OSI中的层 功能 TCP/IP协议族 应用层         文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层         数 ...

  6. 安装git,gitlab和TortoiseGit

    全部都是默认配置安装 需注册用户:用户名尽量好认 测试用户: 注册成功: 生成密钥: 1.首先使用TortoiseGit自带的Puttygen创建本地的公/私钥对 2.点击Generate按钮,在窗口 ...

  7. 由select引发的思考

    一.前言 网络编程里一个经典的问题,selec,poll和epoll的区别?这个问题刚学习编程时就接触了,当时看了材料很不明白,许多概念和思想没有体会,现在在这个阶段,再重新回头看这个问题,有一种豁然 ...

  8. 计蒜客 无脑博士 bfs

    题目链接无脑博士的试管们 思路:直接模拟倒水过程即可,但是需要记忆判断当前的情况是否已经处理过.dfs和bfs都ok AC代码 #include <cstdio> #include < ...

  9. hdu1242 Rescue bfs+优先队列

    直接把Angle的位置作为起点,广度优先搜索即可,这题不是步数最少,而是time最少,就把以time作为衡量标准,加入优先队列,队首就是当前time最少的.遇到Angle的朋友就退出.只需15ms A ...

  10. BZOJ3224/洛谷P3391 - 普通平衡树(Splay)

    BZOJ链接 洛谷链接 题意简述 模板题啦~ 代码 //普通平衡树(Splay) #include <cstdio> int const N=1e5+10; int rt,ndCnt; i ...