Unity容器实现AOP面向切面编程

为什么要有AOP

  需求总是变化的,比如经常会对一些方法后期增加日志、异常处理、权限、缓存、事务的处理,遇到这种情况我们往往只能修改类。

  为了应对变化,我们常常使用设计模式解决,但是也有其局限性:设计模式这能替换整个对象,但是没办法把一个类动态改变。所以我们需要引入AOP的编程思想,因为它允许开发者动态的修改静态的OO模型,构造出一个不断增长,不断变化的需求。

  AOP是一种编程思想,是对OOP面向对象编程思想的补充。

  使用AOP编程可以方便我们聚焦一些核心业务逻辑,比如权限、异常、日志、缓存、事务这种通用功能可以封装起来,通过AOP添加到指定的方法,简化程序设计。

 

如何使用AOP

1、添加引用

 

2、配置文件

在configuration节点下添加(注意看注释)

 <configSections>
   <!--这里添加一个unity扩展-->
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration" /> </configSections> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration" /> <containers> <!--这里最好起一个名字 方便代码查找--> <container name="oneBehaviorTestContainer"> <extension type="Interception" /> <!--设置接口的实现类--> <register type="IServers.IUser,IServers" mapTo="Providers.UserProvider,Providers"> <!--InterfaceInterceptor:继承接口的方法都会被拦截。 TransparentProxyInterceptor:继承类使用的方法都会被拦截。 VirtualMethodInterceptor:继承的方法必须是虚方法且必须是公开的方法才会被拦截。--> <interceptor type="InterfaceInterceptor"/> <!--配置文件的注册顺序是调用顺序,然后才是业务方法,但是扩展逻辑也可以在业务方法之后--> <!--应该把捕捉异常的拦截器放到第一位,这样还可以捕捉其他拦截器内的异常--> <interceptionBehavior type="AOPExe.Interceptions.ExceptionBehavior, AOPExe"/> <!--应该把性能计算的拦截器放到第二位,这样还可以捕捉其他拦截器内的异常--> <interceptionBehavior type="AOPExe.Interceptions.MonitorBehavior, AOPExe"/> <!--参数检查--> <interceptionBehavior type="AOPExe.Interceptions.ParameterCheckBehavior, AOPExe"/> <!--缓存--> <interceptionBehavior type="AOPExe.Interceptions.CachingBehavior, AOPExe"/> </register> </container> </containers> </unity>

 

3、程序调用

3.1程序调用

                //声明一个Unity容器
                var container = new UnityContainer();
                //获取到Unity部分
                UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
                //将扩展部分注册到容器
                unitySection.Configure(container, "oneBehaviorTestContainer");
                //获取接口实例
                var userService = container.Resolve<IUser>();
                //调用接口方法(该方法被添加了拦截器)
                var user = userService.GetUser(100);
                if (user!=null)
                {
                    Console.WriteLine(user.Name);
                }

3.2 拦截器

拦截器的类要实现:IInterceptionBehavior接口

    /// <summary>
    /// 缓存(用于方法前)
    /// </summary>
    public class CachingBehavior : IInterceptionBehavior
    {
        public bool WillExecute => true;

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            return input.CreateMethodReturn(new UserModel() { Id = 1, Name = "缓存姓名" });
        }
    }
  
/// <summary> 
/// 异常处理
/// </summary>

public
class ExceptionBehavior : IInterceptionBehavior { public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); if (methodReturn.Exception != null) { //处理异常 Console.WriteLine("ExceptionBehavior捕捉到异常:" + methodReturn.Exception.Message); //隐藏异常 methodReturn.Exception = null; } else { Console.WriteLine("ExceptionBehavior没有捕捉到异常。"); } return methodReturn; } }
/// <summary>
    /// 性能检测
    /// </summary>
    public class MonitorBehavior : IInterceptionBehavior
    {
        public bool WillExecute => true;

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            var returnMethod = getNext()(input, getNext);
            sw.Stop();
            Console.WriteLine("MonitorBehavior 本次方法共耗时:" + sw.ElapsedMilliseconds);
            return returnMethod;
        }
    }
/// <summary>
    /// 参数检查
    /// </summary>
    public class ParameterCheckBehavior : IInterceptionBehavior
    {
        public bool WillExecute => true;

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ParameterCheckBehavior,打印所有传入参数:");
            foreach (var ipt in input.Inputs)
            {
                Console.WriteLine(ipt);
            }
            int id = (int)input.Inputs[0];
            if (id > 100)
            {
                //这种写法不对
                //new Exception("Id不能超过100");
                return input.CreateExceptionMethodReturn(new Exception("Id不能超过100"));
            }
            else
            {
                Console.WriteLine("参数检查通过");
            }
            return getNext()(input, getNext);
        }
    }

3.3业务方法

 public interface IUser
    {
        UserModel GetUser(int Id);
    }
 public UserModel GetUser(int Id)
        {
            Console.WriteLine("数据库中读取UserModel,可能时间会比较长一点点(对比缓存)");
            //throw new Exception("业务方法中抛出异常");//这里抛出的异常,也可以捕获到
            Thread.Sleep(10000);
            return new UserModel()
            {
                Id = Id
                ,
                Name = "张三"
            };
        }

4、如果不想对接口内的所有方法都添加拦截该怎么办?

我能想到的办法是为接口方法添加特性,然后再拦截器内判断该方法是否含有该特性。小伙伴们有啥想法欢迎留言。

 

posted @ 2020-02-25 16:53  chenxizhaolu  阅读(892)  评论(0编辑  收藏  举报