zoukankan      html  css  js  c++  java
  • 20181122_C#中AOP_使用Unity实现AOP

    一.   使用Unity的AOP实现

    a)         整体项目截图:

    b) 添加Unity的Nuget包, 直接使用最新版就行, 需要添加两个 Unity 和 Unity.Interception (这个是为AOP做的一个扩展) 

     

    c)    AOP配置文件, 详细注释(CfgFilesUnity.Config)

     1 <!--这是一个标准Unity配置文件的格式-->
     2 
     3 <configuration> <!--根节点名称-->
     4   <configSections>
     5     <!--name容器的名称    type 表示如何查找节点, 这是固定写法-->
     6     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
     7   </configSections>
     8   <unity>
     9     <!--下面一行是固定写法, 用这个写法来支持AOP-->
    10     <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
    11     <containers><!--定义一组容器-->
    12       <container name="aopContainer">
    13       <!--定义一个容器; 表示在IUserProcessor这个接口下所有的方法都给他增加, 这个容器(aopContainer)内所包含的方法-->
    14         <extension type="Interception"/>
    15         <!--这里使用Interception类型的扩展; 其实在Unity中有三种类型来处理这件事; 这种是属于实现接口的方法, 还有一种是继承父类; 第三种是使用Virtual虚方法的形式, 使用虚方法有点类似于CastleProxyAOP这个代理-->
    16         <!--把接口映射到具体的实现类; 也就是说告诉容器如果遇到了MyAOP.UnityWay.IUserProcessor这个抽象, 就使用MyAOP.UnityWay.UserProcessor来帮我们实例化-->
    17         <!--MyAOP.UnityWay.IUserProcessor完整的接口名称, MyAOP是程序所在的dll名称, 程序集的名称(当然在这里是当前exe文件的名称-->
    18         <!--MyAOP.UnityWay.UserProcessor具体的实现类, MyAOP和上面的解释一样-->
    19         <!--MyAOP是程序集的名称-->
    20         <!-- register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP"  这一句整体的意思就是告诉容器, 如果遇到IUserProcessor这个抽象, 就使用UserProcessor类来帮我进行初始化一个具体的实例出来-->
    21         <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
    22           <!--Unity中的AOP有三种模式, 第一种必须继承MarshalByRefObject这个父类的AOP
    23           第二种必须是虚方法的AOP
    24           第三种就是下面写的接口形式的 InterfaceInterceptor 一般都用这种接口形式的:
    25             表示只要是接口下的所有方法, 都会被增加上下面的方法
    26           -->
    27           <interceptor type="InterfaceInterceptor"/> <!--AOP支持的模式; 推荐使用这种接口模式的-->
    28           <!--下面这五个表示  在IUserProcessor接口中的所有方法, 都拥有下面方法的扩展-->
    29           
    30           <!--异常处理的; 注意如果你想全局处理异常, 则应该把异常处理的Behavior放到最顶层, 否则在Unity中自己抛出的异常则会抓不到-->
    31           <interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
    32           <!--缓存的behavior; 注意缓存的Behavior也应该放在记录日志之前; 需要注意的是, 如果被缓存命中了, 那么后面的AOP也不会执行的-->
    33           <interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
    34           <!--方法执行前写日志-->
    35           <interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
    36           <!--参数检查-->
    37           <interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
    38           <!--方法执行后做的事情-->
    39           <interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/>
    40         </register>
    41       </container>
    42     </containers>
    43   </unity>
    44 </configuration>
    View Code

    d)  Model代码:

    1 public class User
    2     {
    3         public int Id { get; set; }
    4         public string Name { get; set; }
    5         public string Password { get; set; }
    6 }
    View Code

    e)  IuserProcessor代码:

    1 public interface IUserProcessor
    2     {
    3         void RegUser(User user);
    4         User GetUser(User user);
    5 }
    View Code

    f)  UserProcessor代码:

     1  public class UserProcessor : IUserProcessor
     2     {
     3         public void RegUser(User user)
     4         {
     5             Console.WriteLine("用户已注册。");
     6             //throw new Exception("11");
     7         }
     8         [Obsolete]
     9         public User GetUser(User user)
    10         {
    11             return user;
    12         }
    13 }
    View Code

    g) LogBeforeBehavior代码(在方法执行之前写日志):

     1 /// <summary>
     2     /// 1. 标准的通过AOP写日志的功能, 必须实现IInterceptionBehavior; 这个接口来自于Unity容器
     3     /// </summary>
     4     public class LogBeforeBehavior : IInterceptionBehavior
     5     {
     6         /// <summary>
     7         /// 3. 此方法为固定写法
     8         /// </summary>
     9         /// <returns></returns>
    10         public IEnumerable<Type> GetRequiredInterfaces()
    11         {
    12             return Type.EmptyTypes;
    13         }
    14 
    15         /// <summary>
    16         /// 4. 关键方法
    17         /// </summary>
    18         /// <param name="input"></param>
    19         /// <param name="getNext"></param>
    20         /// <returns></returns>
    21         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    22         {
    23             Console.WriteLine("LogBeforeBehavior");
    24             //5. 如果有的方法想用, 有的方法不想被AOP, 则可以在这里做切断
    25 
    26             //这里可以将某个方法打上特性,然后获取MemberInfo中的特性信息, 以此来判断哪个
    27             //方法需要AOP切入,哪些方法不需要AOP切入
    28             Console.WriteLine(input.MethodBase.Name);
    29            // Console.WriteLine( input.MethodBase.GetCustomAttributes(true)[0].ToString()  ); 
    30             foreach (var item in input.Inputs) //input中包含了所有的参数信息
    31             {
    32                 Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
    33                 //反射&序列化获取更多信息
    34             }
    35             // Unity.Interception.InterceptionBehaviors.InvokeInterceptionBehaviorDelegate gn = getNext();
    36             // return getNext()(input, getNext);//注意这种写法也是可以的; 这种写法的意思就是getNext()方法返回了一个委托, 然后委托又被调用了
    37             return getNext().Invoke(input, getNext);//4.  固定写法
    38 
    39           //  return null;
    40             //return gn.Invoke(input, getNext);
    41             //getNext()表示执行完当前的方法之后, 去执行原始方法;   但是注意的是, getNext()中可能有多个方法
    42         }
    43 
    44 
    45         /// <summary>
    46         /// 2. 固定写法
    47         /// </summary>
    48         public bool WillExecute
    49         {
    50             get { return true; }
    51         }
    52     }
    View Code

    h)  LogAfterBehavior代码(方法执行之后写日志):

     1 //IInterceptionBehavior来自于AOP容器中      Unity.Interception.InterceptionBehaviors;
     2     public class LogAfterBehavior : IInterceptionBehavior
     3     {
     4         /// <summary>
     5         /// 固定写法
     6         /// </summary>
     7         /// <returns></returns>
     8         public IEnumerable<Type> GetRequiredInterfaces()
     9         {
    10             return Type.EmptyTypes;
    11         }
    12 
    13         /// <summary>
    14         /// 可以记录调用时间, 参数, 函数名称
    15         /// </summary>
    16         /// <param name="input"></param>
    17         /// <param name="getNext"></param>
    18         /// <returns></returns>
    19         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    20         {
    21             //getNext()(input, getNext);  关键点; 如果业务代码写在这句话之前, 那么就会先执行业务代码, 再执行配置文件中配置的实例代码; 反之同理
    22 
    23             IMethodReturn methodReturn = getNext().Invoke(input, getNext);//执行后面的全部动作
    24             //原始方法执行后
    25 
    26             Console.WriteLine("LogAfterBehavior");
    27             Console.WriteLine(input.MethodBase.Name);
    28             foreach (var item in input.Inputs)
    29             {
    30                 Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
    31                 //反射&序列化获取更多信息
    32             }
    33             Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
    34             return methodReturn;
    35         }
    36 
    37         /// <summary>
    38         /// 固定写法
    39         /// </summary>
    40         public bool WillExecute
    41         {
    42             get { return true; }
    43         }
    44     }
    View Code

    i)  ParameterCheckBehavior代码(在方法执行之前进行参数校验):

     1 /// <summary>
     2     /// 参数检查
     3     /// </summary>
     4     public class ParameterCheckBehavior : IInterceptionBehavior
     5     {
     6         public IEnumerable<Type> GetRequiredInterfaces()
     7         {
     8             return Type.EmptyTypes;
     9         }
    10 
    11         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    12         {
    13             Console.WriteLine("ParameterCheckBehavior");
    14             User user = input.Inputs[0] as User;//可以不写死类型,反射+特性完成数据有效性监测
    15             if (user.Password.Length < 10)//可以过滤一下敏感词
    16             {
    17                 //返回一个异常
    18                 return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
    19                 //注意只要抛出异常, 那么后面的都不会再执行了, 在这里也就是说后的 logafterbehavior是不会再执行了
    20                 //throw new Exception("密码长度不能小于10位");
    21             }
    22             else
    23             {
    24                 Console.WriteLine("参数检测无误");
    25                 return getNext().Invoke(input, getNext);
    26             }
    27         }
    28 
    29         public bool WillExecute
    30         {
    31             get { return true; }
    32         }
    33     }
    View Code

    j) ExceptionLoggingBehavior代码(异常处理):

     1 /// <summary>
     2     /// 异常处理
     3     /// </summary>
     4     public class ExceptionLoggingBehavior : IInterceptionBehavior
     5     {
     6         public IEnumerable<Type> GetRequiredInterfaces()
     7         {
     8             return Type.EmptyTypes;
     9         }
    10 
    11         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    12         {
    13             IMethodReturn methodReturn = getNext()(input, getNext);
    14 
    15             Console.WriteLine("ExceptionLoggingBehavior");
    16             if (methodReturn.Exception == null) //检查methodReturn中是否有异常
    17             {
    18                 Console.WriteLine("无异常");
    19             }
    20             else
    21             {
    22                 Console.WriteLine($"异常:{methodReturn.Exception.Message}");
    23             }
    24             return methodReturn;
    25         }
    26 
    27         public bool WillExecute
    28         {
    29             get { return true; }
    30         }
    31     }
    View Code

    k)  CachingBehavior代码(缓存处理):

     1 /// <summary>
     2     /// 缓存AOP
     3     /// </summary>
     4     public class CachingBehavior : IInterceptionBehavior
     5     {
     6         public IEnumerable<Type> GetRequiredInterfaces()
     7         {
     8             return Type.EmptyTypes;
     9         }
    10         /// <summary>
    11         /// 定义缓存字典
    12         /// </summary>
    13         private static Dictionary<string, object> CachingBehaviorDictionary = new Dictionary<string, object>();
    14 
    15         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    16         {
    17             Console.WriteLine("CachingBehavior");
    18             //把方法的名称和所有的参数列表全部标识为key , 然后放到字典里面;
    19             string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}";
    20             //当方法名和参数都不变, 则表示有缓存
    21 
    22            
    23             if (CachingBehaviorDictionary.ContainsKey(key))
    24             {
    25                 return input.CreateMethodReturn(CachingBehaviorDictionary[key]);//直接返回  [短路器]  不再往下; 包括后面的Behavior也不会再执行了; 因为全部被直接短路了
    26             }
    27             else
    28             {
    29                 //如果字典中没有, 则继续执行这里
    30                 IMethodReturn result = getNext().Invoke(input, getNext);
    31                 if (result.ReturnValue != null) //并将其加入到缓存列表中去; 当然缓存中放一个null没有任何意义, 所以这里判断一下
    32                 {
    33                     //不存在则, 加入缓存中
    34                     CachingBehaviorDictionary.Add(key, result.ReturnValue);
    35                 }
    36 
    37                 return result;
    38             }
    39 
    40 
    41         }
    42 
    43         public bool WillExecute
    44         {
    45             get { return true; }
    46         }
    47     }
    View Code

    l) UnityConfigAOP代码(调用):

     1 /// <summary>
     2     /// 使用EntLibPIAB Unity 实现动态代理
     3     /// 
     4     /// 1. 添加引用→右键→添加 NuGet包, 添加Unity的包引用
     5     /// 2. 这里添加的 Unity是5.8.13的版本, 而Unity.Interception是5.5.0; 因为最新的(5.5.5)不支持 .net 4.0
     6     /// 3. Unity是一个 Unity的容器; 而Unity.Interception当Unity做AOP时的一个扩展
     7     /// </summary>
     8     public class UnityConfigAOP
     9     {
    10         public static void Show()
    11         {
    12             User user = new User()
    13             {
    14                 Name = "孙悟空",
    15                 Password = "12345678934534643"
    16             };
    17  
    18 
    19             {
    20                 //1. 初始化UnityContainer容器
    21                 IUnityContainer container = new UnityContainer();
    22                 ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
    23 
    24                 //2. 开始读取配置文件
    25                 fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\Unity.Config");
    26                 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
    27                 UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
    28 
    29 
    30                 //3. 使用配置文件中aopContainer节点下的所有配置信息来初始化container这个AOP容器
    31                 configSection.Configure(container, "aopContainer"); //10. 这个aopContainer就是配置文件中的 <container name="aopContainer"> 这里这个容器的名称 ; 注意如果配置文件中的名字和这里的名字不一样就会报出以下错误:
    32                                                                     // The container named "aopContainer" is not defined in this configuration section.
    33 
    34                 // 在这里创建对象, 创建的规则就来自于配置文件的  <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP"> 这一行; 如果是 IUserProcessor 类型, 就是使用UserProcessor  来创建实例
    35                 IUserProcessor processor = container.Resolve<IUserProcessor>();
    36                 processor.RegUser(user); //4. 注意, 当程序运行到这里的时候, 正常情况应该是去调用userProcessor的Reguser方法, 但是由于在配置文件中进行了配置, 所以它会去执行 LogBeforeBehavior 的 Invoke的方法(当aopContainer这容器中只有一个LogBeforeBehavior的时候, 如果多个, 则那个方法在前面则优先执行, 其它的上依次的调)
    37                 User userNew1 = processor.GetUser(user); //调用GetUser的时候, 也会执行配置文件中对应配置了的方法
    38 
    39 
    40                 //演示缓存Behavior
    41                 User userNew2 = processor.GetUser(user);
    42             }
    43         }
    44     }
    View Code
  • 相关阅读:
    黑马前端2020就业Web全套课-2020.4月最新版
    什么是Redis雪崩、穿透和击穿? 全面掌握Redis
    ElasticStack高级搜索入门到项目实战,Elasticsearch全文检索
    阿里云盘邀请码+软件下载
    Intellij IDEA超实用设置汇总,高效便捷敲代码
    双11的亿级高并发架构,是怎么设计的?
    TensorFlow 卷积神经网络实用指南 | iBooker·ApacheCN
    TensorFlow 入门 | iBooker·ApacheCN
    TensorFlow 2.0 快速入门指南 | iBooker·ApacheCN
    深度学习快速参考 | iBooker·ApacheCN
  • 原文地址:https://www.cnblogs.com/wxylog/p/10000266.html
Copyright © 2011-2022 走看看