关于面向切面编程的部分内容-错误处理机制

本文介绍了一种在MVC架构中实现错误处理的方法,通过创建自定义异常处理类MyExceptionAttribute来捕获并存储异常信息,并使用线程池定期将异常信息写入日志文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

错误处理机制。

面对多个web服务器,多线程处理,我们想把错误信息记录到一个txt文档中。

但是把错误信息写到内存是很快。写到硬盘上就有一堆的问题。比如说读写慢、并发问题。

今天我们就利用这个实现错误处理 此文以MVC为例

1、首先要在  golable  文件的  protected void Application_Start()


注册一个错误处理机制。

MVC中自带一个  过滤器

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

image

这里面 我们看到这个过滤器

 

2、其实就是在 app_Start文件夹下面 的 FilterConfig.cs 文件

image

3、 打开FilterConfig.cs文件

就写了一个注册事件。我们看得到 这个是对错误处理机制

image

(当然 ,你们看到的是  HandleErrorAttribute 这个类)

4、所以你们可能觉得奇怪,我们来查看MyExceptionAttribut的定义看一下

image

继承了HandleErrorAttribute

这里我把这个类的代码贴一下


public class MyExceptionAttribute : HandleErrorAttribute
    {
        //  private static object obj = new object();
        public static ConcurrentQueue<Exception> ExceptionQueue = new ConcurrentQueue<Exception>();//定义队列

        /// <summary>
        /// 在该方法中捕获异常。
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnException(ExceptionContext filterContext)
        {

            base.OnException(filterContext);
            Exception ex = filterContext.Exception;//捕获异常信息。
            //将异常信息写到队列中。
            ExceptionQueue.Enqueue(ex);
            //跳转到错误页面.
            filterContext.HttpContext.Response.Redirect("/Error.html");

          

        }
    }

 

主要是定义一个静态 队列  ConcurrentQueue

(当然你也可以用 Queue。但是微软说 这个ConcurrentQueue 比 Queue  安全。好像是线程安全的,一堆堆的理论,说白了就是用ConcurrentQueue 更安全)

这样所有的错误就都在这个队列里面了。(就是内存)

这样总不行吧。内存 断电就没有了的啊。

所以我们要想把资料存到 硬盘中。

5、现在又要在

  golable  文件的  protected void Application_Start()


中注册一个消费线程(这句话后面会解释,看不懂就继续)就是在 protected void Application_Start()中加入这些代码,最好放最前面。

内容就是线程池开启一个线程 从刚刚定义的 MyExceptionAttribute的 ExceptionQueue队列里面取出项来。

将错误信息最加到文件后面。如果队列为空,就线程停留3秒。


string filePath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem((a) =>
            {

                while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
                {

    // 这里可以加一条   if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
//{  发送邮件到管理员}
                    if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
                    {
                        // Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
                        Exception ex = null;
                        bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
                        if (ex != null && isResult)
                        {
                            string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                            File.AppendAllText(fullPath, ex.ToString());
                         //   ILog logger = LogManager.GetLogger("errorMsg");
                          //  logger.Error(ex.ToString());
                        }
                        else
                        {
                            Thread.Sleep(3000);
                        }
                    }
                    else
                    {
                        Thread.Sleep(3000);//避免造成CPU的空转。
                    }
                }

 

            }, filePath);

6、总结。

这个就是一个生产者消费者的模式。

生产者就是 产生错误的源头。 消费者就是注册保存日志的方法。

中间有一个仓库就是    那个静态错误队列。

可以看到 系统产生的错误临时存放于内存中。然后一个新的线程 去读写静态错误队列。

正常情况 需要在错误队列里面加一个错误队列数字大于1000条的时候  发警告到邮箱的功能。那样感觉有点问题复杂化了,毕竟这里只是讲错误处理。

7、log4net 我前面讲过的一个开源框架 记录错误很好。

这里提供一个连接    log4net配置方法你可以把那个一起并到这里。那么就会有

把protected void Application_Start()中添加 的代码

改成。注意是改成:

log4net.Config.XmlConfigurator.Configure();
            //开始一个线程,查看异常队列
            string filePath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem((a) =>
            {

                while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
                {
                    if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
                    {
                        // Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
                        Exception ex = null;
                        bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
                        if (ex != null && isResult)
                        {
                            string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                            //File.AppendAllText(fullPath, ex.ToString());
                            ILog logger = LogManager.GetLogger("errorMsg");
                            logger.Error(ex.ToString());
                        }
                        else
                        {
                            Thread.Sleep(3000);
                        }
                    }
                    else
                    {
                        Thread.Sleep(3000);//避免造成CPU的空转。
                    }
                }

 

            }, filePath);

这样就会按照你的要求把错误日志记录到

app_data文件夹下面。(前提是你有未处理的错误 。呵呵)

看到下图就成功了

image

题外话(

没有就自己创一个   var s=3/0;

这样就可以了。

转载于:https://www.cnblogs.com/jixinyu12345/p/4862859.html

<think>好的,我现在需要帮助用户了解AOP(面向切面编程)的概念及入门知识。首先,我要回忆自己之前学过的AOP相关知识,并结合用户提供的引用内容来组织回答。 用户的问题包括入门、介绍、原理,所以需要从基础开始解释。AOP是面向切面编程,用于处理横切关注点,比如日志、事务等,这些在传统OOP中可能分散在各处。我需要先定义AOP,说明它的作用和优势,比如解耦、代码复用等。 然后,用户提供的引用中有提到核心概念,比如切面、连接点、通知、切点、织入等。这些需要逐一解释,确保用户能理解每个术语的含义。例如,引用3提到织入(weave)是将通知应用到目标对象生成代理的过程,而Spring采用运行时织入。这部分需要详细说明,可能还要对比编译期织入和运行时织入的区别。 接下来是AOP的原理,用户可能想知道底层如何实现。根据引用3,Spring AOP使用了动态代理技术,具体是JDK动态代理和CGLIB。需要解释这两种代理的适用场景,比如基于接口还是类。此外,环绕通知的处理,如引用5中的例子,说明如何正确使用环绕通知处理返回值,避免类型不匹配的问题。 用户提供的引用中还提到了Spring AOP的配置方式,比如基于注解和XML。需要简要介绍这两种方式,并给出一个简单的例子,如引用4中的通知类,展示前置和后置通知的配置。同时,结合示例代码,让用户更直观地理解如何实现一个切面。 可能还需要比较AOP与其他编程思想的区别,比如OOP,说明AOP如何补充OOP的不足,处理横切关注点。引用3提到AOP解决OOP中非核心代码冗余和维护问题,这点需要强调。 最后,生成相关问题时,要考虑用户可能进一步想了解的内容,比如AOP的应用场景、实现方式对比、Spring AOP与其他框架(如AspectJ)的区别、通知类型的使用细节,以及如何解决常见错误(如引用5中的返回值问题)。 需要确保回答结构清晰,分点解释,使用用户可见的中文,避免技术术语过于晦涩,同时引用提供的参考资料来支持内容,比如引用3关于织入和动态代理的部分,引用4关于通知配置的例子,引用5关于环绕通知的注意事项。 可能还需要检查是否有遗漏的核心概念,确保覆盖切面、连接点、通知类型、切点表达式、织入方式、动态代理实现等关键点。同时,示例代码要符合用户提供的格式,使用正确的语法,比如Python的示例可能换成Java,但用户给的引用中有Spring的Java代码,所以保持Java示例更合适。 总结来说,回答的结构应该是:概念定义、核心概念解释、原理(动态代理)、实现方式(注解示例)、优缺点和应用场景,最后生成相关问题。需要确保每个部分都有引用支持,并且语言通俗易懂,帮助用户逐步理解AOP的入门知识。</think>### AOP(面向切面编程)概念及入门知识 #### 1. AOP 核心概念 **AOP(面向切面编程)** 是一种编程范式,用于将**横切关注点**(如日志、事务、权限校验等)从业务逻辑中分离,实现代码的模块化和复用。其核心思想是通过“切面”将分散在多个类中的公共行为集中管理,避免代码冗余和耦合[^3]。 **核心概念**: - **切面(Aspect)**:封装横切关注点的模块,包含通知(Advice)和切点(Pointcut)。例如,日志记录模块可以视为一个切面- **通知(Advice)**:切面在特定连接点执行的动作,分为: - **前置通知(Before)**:在方法执行前触发。 - **后置通知(AfterReturning)**:在方法正常返回后触发。 - **环绕通知(Around)**:包裹目标方法,控制其执行流程[^4][^5]。 - **连接点(Join Point)**:程序执行过程中可插入切面的点,如方法调用或异常抛出。 - **切点(Pointcut)**:通过表达式定义哪些连接点需要被切面处理。例如:`@Pointcut("execution(* com.service.*.*(..))")`。 - **织入(Weave)**:将切面应用到目标对象生成代理对象的过程。Spring AOP 默认使用**运行时动态代理**实现[^3]。 #### 2. AOP 实现原理 Spring AOP 基于**动态代理**技术,具体分为两种方式: 1. **JDK 动态代理**:适用于目标类实现了接口。 2. **CGLIB 代理**:适用于未实现接口的类,通过生成子类代理。 **示例**:环绕通知需正确处理返回值(避免类型不匹配)[^5]: ```java @Around("pt2()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice ..."); Object ret = pjp.proceed(); // 调用原始方法 System.out.println("around after advice ..."); return ret; // 返回原始方法的返回值 } ``` #### 3. Spring AOP 快速入门 **基于注解的实现**: 1. 定义切面类,标记 `@Aspect`。 2. 使用 `@Before`、`@Around` 等注解声明通知类型。 3. 通过切点表达式指定生效范围。 **示例**: ```java @Aspect @Component public class LogAspect { @Before("execution(* com.service.*.*(..))") public void beforeAdvice() { System.out.println("方法执行前记录日志"); } } ``` #### 4. AOP 的优缺点 - **优点**: - 解耦核心业务与非核心逻辑(如日志)。 - 提升代码复用性和可维护性。 - **缺点**: - 过度使用可能导致调试困难。 - 动态代理对性能有轻微影响。 #### 5. 应用场景 - 日志记录 - 事务管理 - 权限校验 - 性能监控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值