Castle 学习 之 动态代理

前几天看见在项目中用Castle来实现动态代理,觉得很有意思,就找个时间自己研究一下。介绍就免了,那开始吧。

    public class AccountController : Controller
    {
        private AccountService accountService = new AccountService();
        // GET: Account
        public ActionResult Index(string name)
        {
            ViewBag.Msg = accountService.GetUser(name);
            return View();
        }
    }

以前Service的实现基本上是IOC或者单例,今天我们就用动态代理来实现。

        public ActionResult Index(string name)
        {
            var proxy = new ProxyGenerator(); //提供类和接口的代理对象
            var interceptor =new AccountInterceptor();  //拦截器
            //var logInterceptor = new LogInterceptor();
            var accountService = proxy.CreateClassProxy(interceptor);
            ViewBag.Msg = accountService.GetUser(name);
            return View();
        }

ProxyGenerator类会创建一个代理类来继承目标类,并重写目标类中虚方法。

    public class AccountInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            var arguments = invocation.GetArgumentValue(0) as string;

            if (string.IsNullOrWhiteSpace(arguments))
            {
                invocation.ReturnValue = "nono";
                invocation.SetArgumentValue(0, "Stranger");
                invocation.Proceed();
                invocation.ReturnValue = "Stranger";
                return;
            }
            else if (arguments.Equals("陈绮贞"))
            {
                invocation.SetArgumentValue(0,arguments+"SAMA!");
                invocation.Proceed();
                return;
            }
            invocation.Proceed();
            return;
        }
    }

拦截器需要需要实现IInterceptor接口,实现Intercept方法。Intercept接受一个实现了IInvocation接口类的参数,invocation个参数封装了一个代理的方法,其中Proceed用于调用目标方法。看一下方法注释。

        // 摘要:(度娘翻译)
        //     Proceeds the call to the next interceptor in line, and ultimately to the target
        //     method.将调用到下一个拦截线,并最终向目标方法。
        //
        // 备注:
        //     Since interface proxies without a target don't have the target implementation
        //     to proceed to, it is important, that the last interceptor does not call this
        //     method, otherwise a System.NotImplementedException will be thrown.
        没有目标的接口代理没有目标实现要继续进行,这是很重要的,即最后一个拦截不调用这个方法,否则会抛出 system.notimplementedexception。
        void Proceed();

解释一下:ProxyGenerator的CreateClassProxy方法接受的是一个实现了IInterceptor接口的拦截器可变数组,并按顺序执行,类似一个调用链。Proceed被调用时,若果当前拦截器之后还有拦截器等待执行,则将调用传递到下一个拦截器,而不会去调用需要执行的方法,等到最后一个拦截器时才调用目标方法。如果我们调用的方法不是虚方法,也不会抛出异常的。(这里有个疑问:记得我在公司时,当我们调用的方法不是虚函数时也能被拦截到,Proceed方法不调用目标方法,然后拦截器结束后才会调用目标方法,今天debug时却发现拦截器一直没进去,不知道是不是由于使用的CreateClassProxy重载方法不同,明天去公司看一下。更新:虽然调用的方法不是虚函数,但是其内部调用了一个虚函数,这个虚函数被拦截到了,而不是调用的方法被拦截到。)

IInvocation接口里有一些方法可以使我们获取和设置目标方法的参数可返回值,在这里我们就可以做一些参数上的验证和日志的记录。

Castle的动态代理很简单明了,也是AOP实现方式的一种,有兴趣的可以了解一下。

PS:有错误欢迎指摘。

你可能感兴趣的:(Castle 学习 之 动态代理)