Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 428|回复: 0

运用Unity实现AOP拦截器[结合异常记录实例]

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-9 06:29:12 | 显示全部楼层 |阅读模式
     

     

    本篇文章将通过Unity实现Aop异常记录功能;有关Unity依赖注入可以看前两篇文章:

    1:运用Unity实现依赖注入[结合简单三层实例] 

    2:运用Unity实现依赖注入[有参构造注入] 

    另早期写过一个利用Spring.net实现相同的功能:spring.net结合普通三层(实现IOC 及AOP中的异常记录功能)

     

    一:理论知识

    AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。   OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。   AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是通过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。但是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,比如日志记录,验证等

    Unity默认提供了三种拦截器:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。

    TransparentProxyInterceptor:代理实现基于.NET Remoting技术,它可拦截对象的所有函数。缺点是被拦截类型必须派生于MarshalByRefObject。

    InterfaceInterceptor:只能对一个接口做拦截,好处时只要目标类型实现了指定接口就可以拦截。

    VirtualMethodInterceptor:对virtual函数进行拦截。缺点是如果被拦截类型没有virtual函数则无法拦截,这个时候如果类型实现了某个特定接口可以改用

    InterfaceInterceptor。

     

    二:实例介绍

    本实例是通过Unity实现异常的统一记录,解决以前在解决方法不同地方出现重复异常记录情况;

    图中同样是基于我们前两篇文章讲解依赖注入时的分层结构;增加对log4net.dll引用来记录异常的内容;

    若要了解分层情况看前一篇运用Unity实现依赖注入[结合简单三层实例],本文侧重讲解AOP的实现;

     

    三:实例编码

    1:首先了解公共助手层Command;其中Log4netFile加载log4net配置信息,特别要注意assembly

    using log4net;
    using log4net.Core;
    using System.Reflection;
    
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    namespace Command
    {
        public  class Log4NetFile
        {
            private ILog logger;
            public Log4NetFile()
            {
                logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
                log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo("Log4Net.config"));
            }
    
            public void Log(string message)
            {
                logger.Warn(message);
            }
           
            public void Log(Exception ex)
            {
                logger.Warn("异常的内容:", ex);
            }
        }
    }

    而ExceptionLogBehavior类是我们异常拦截器,也是本篇的重点,其中我们继承IInterceptionBehavior接口,不仅可以查看传入的参数,还可以对它进行统一的异常处理;getNext()(input, getNext)就是重调运行;

    using Microsoft.Practices.Unity.InterceptionExtension;
    namespace Command
    {
        public class ExceptionLogBehavior:IInterceptionBehavior
        {
            /// <summary>
            /// 获取当前行为需要拦截的对象类型接口。
            /// </summary>
            /// <returns>所有需要拦截的对象类型接口。</returns>
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
            /// <summary>
            /// 通过实现此方法来拦截调用并执行所需的拦截行为。
            /// </summary>
            /// <param name="input">调用拦截目标时的输入信息。</param>
            /// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
            /// <returns>从拦截目标获得的返回信息。</returns>
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("执行前");
                IMethodReturn retvalue = getNext()(input, getNext);
               
                #region 参数部分
                Console.WriteLine("-------------参数内容---------------");
                for (int i = 0; i < input.Arguments.Count; i++)
                {
                    var parameter = input.Arguments;
                    Console.WriteLine(string.Format("第{0}个参数值为:{1}", i+1, parameter.ToString()));
                }
                Console.WriteLine("------------------------------------");
                #endregion
    
                #region 异常处理部分
                if (retvalue.Exception == null)
                {
                    Console.WriteLine("执行成功,无异常");
                }
                else
                {
                    //记录异常的内容 比如Log4Net等
                    new Log4NetFile().Log("异常的内容为:" + retvalue.Exception.Message);
                    //retvalue.Exception设为null表示异常已经被处理过了
                    retvalue.Exception = null;
                }
                #endregion
                Console.WriteLine("完成");
                return retvalue; 
            }
    
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
            /// 某些操作。
            /// </summary>
            public bool WillExecute
            {
                get { return true; }
            }
        }

    2:逻辑层我们故意让它抛出异常内容

    using IAopDAL;
    using IAopBLL;
    using Command;
    namespace AopBLL
    {
        public class ReadDataBLL:IReadDataBLL
        {
            IReadData bllServer = new UnityContainerHelp().GetServer<IReadData>();
            public string ReadDataStr(string Name)
            {
                throw new Exception("BLL出现异常");
            }
        }
    }

    3:主程序层(Aopunity)主要关注配置信息

    a:首先是Log4Net.config,每天生成一个.txt文件记录异常内容

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
      </configSections>
      <log4net>
        <appender name="RollingLogRootFileAppender" type="log4net.Appender.RollingFileAppender">
          <!--日志的路径-->
          <file value=".\Log\WanLog" />
          <!--是否覆盖,默认是追加true-->
          <appendToFile value="true"/>
          <!--文件滚动周期(每日创建新日志文件)-->
          <datePattern value="yyyyMMdd&quot;.txt&quot;"/>
          <!--设置无限备份=-1 ,最大备份数为1000-->
          <maxSizeRollBackups value="1000"/>
          <!--名称是否可以更改为false为可以更改-->
          <staticLogFileName value="false" />
          <!--文件滚动选项Composite表示根据日期和大小来滚动-->
          <rollingStyle value="Composite" />
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%t][%-5p][%c]%m%n%exception%n" />
          </layout>
        </appender>
        <root>
          <level value="All" />
          <appender-ref ref="RollingLogRootFileAppender" />
        </root>
      </log4net>
    </configuration>

    b:App.config则是一些依赖注入跟Aop的配置,增加sectionExtension节点引用;interceptor则表示拦截器的类型,interceptionBehavior对应处理程序,lifetime生命周期

    <?xml version="1.0"?>
    <configuration>
      <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
      </configSections>
      <unity xmlns="http://schemas.microsoft.com/practces/2010/unity">
        <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 
    
    Microsoft.Practices.Unity.Interception.Configuration"/>
        <typeAliases>
          <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
        </typeAliases>
        <alias alias="ExceptionLogBehaviorName" type="Command.ExceptionLogBehavior,Command"></alias>
        <container name="FirstClass">
          <extension type="Interception"/>
          <register type="IAopBLL.IReadDataBLL,IAopBLL" mapTo="AopBLL.ReadDataBLL,AopBLL">
            <interceptor type="InterfaceInterceptor"/>
            <interceptionBehavior type="ExceptionLogBehaviorName"/>
            <lifetime type="transient"></lifetime>
          </register>
          <register type="IAopBLL.IPropertyBLL,IAopBLL" mapTo="AopBLL.PropertyBLL,AopBLL"></register>
          <register type="IAopDAL.IReadData,IAopDAL" mapTo="AopOracelDAL.ReadDataDAL,AopOracelDAL"/>
        </container>
      </unity> 
    <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
    </configuration>

    c:主程序运行代码如下:

    using IAopBLL;
    using Command;
    namespace AopUnity
    {
        class Program
        {
            static void Main(string[] args)
            {
                IReadDataBLL bllServer = new UnityContainerHelp().GetServer<IReadDataBLL>();
                Console.WriteLine(bllServer.ReadDataStr("踏浪帅"));
            }
        }
    }

     

    四:运行效果

     

    五:注意事项

    1:主程序没有对Microsoft.Practices.Unity.Interception.Configuration.dll进行引用报错

    创建 unity 的配置节处理程序时出错: 给定程序集名称或基本代码无效。 (异常来自 HRESULT:0x80131047)

    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 
    Microsoft.Practices.Unity.Interception.Configuration"/>

    解决方法:主要是我们配置文件中有,则要对它进行引用

    2:因为我们把log4net配置文件单独出来,所以要设置其为始终复制

     

     

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮,若有不足欢迎指正。  因为,我的写作热情也离不开您的肯定支持。
     
    感谢您的阅读(源代码下载

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-2 09:59 , Processed in 0.058275 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表