zoukankan      html  css  js  c++  java
  • 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、如果不想对接口内的所有方法都添加拦截该怎么办?

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

  • 相关阅读:
    Oracle 不走索引
    Oracle不等值链接
    查看统计信息是否过期
    JavaScript利用append添加元素报错
    Subversion Native Library Not Available & Incompatible JavaHL library loaded
    Oracle并行查询出错
    Oracle连接出错(一)
    Linux下Subclipse的JavaHL
    Java生成文件夹
    Java生成文件
  • 原文地址:https://www.cnblogs.com/chenxizhaolu/p/12362548.html
Copyright © 2011-2022 走看看