`
Rocky_rup
  • 浏览: 145345 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

基于AOP的日志调试

阅读更多

断点 vs 日志


断点是我们日常开发最为常见和高效的调试手段, 相比较输入日志它给予更多的状态信息和灵活的观察角度, 但断点调试是有前提和局限的.

  # 需要一个界面友好, 功能强大的IDE,
  # 比较适合于在单机的开发环境中进行.

企业应用开发中, 我们常常会遇到无法断点调试的窘境, 例如:

  # 这个异常仅在生产环境出现, 开发环境里无法重现;
  # 存在外部系统依赖, 开发环境无法模拟等.

这迫使我们不得不回到*日志调试*的老路子上来.

Print vs Logging


简单点的话, 我们用

 

System.out.println("debug infomation");
 

 

就是因为过于简单, 当需要更多信息(如线程, 时间等), 或是定义输出模式和形式就需要编写更多代码, 于是我们有了[http://logging.apache.org/log4j Log4j].

为什么要基于AOP


Log4j挺好用的, 只是与`System.out.print`一样, 在代码中随处可见, 但却没有业务价值.

更令人头痛的是, 并非每次我们都有足够的经验告诉自己应该在哪里添加这些语句, 以致于调试中不断的因为调正它们的在代码中的位置, 而反复编译 - 打包 - 发布系统. 这种体力活, 太没艺术感了, 囧!

换而言之, 我们会希望:

  # 将Logging剥离于业务之外, 让代码更易于维护,
  # 无需重新编译,甚至能够运行时, 可调整输出日志的位置.

[http://en.wikipedia.org/wiki/Aspect-oriented_programming AOP]完全可以帮助我们做到上述两点.

这完全不是什么新鲜观点, 这在任何介绍[http://en.wikipedia.org/wiki/Aspect-oriented_programming AOP]文章中, 都会提到Logging是其最典型的应用场景.

所以这儿将基于[http://code.google.com/p/google-guice/ Guice], 讨论如何实现一个非侵入式的, 且能无需重新编译即可调正Logging位置的简单示例.

 

一个基于Guice的示例


我曾经用过一个叫[http://log4e.jayefem.de/ Log4E]的Eclipse插件, 它可根据我们预先的配置, 自动的为我们在编写的代码中插入logging的语句, 如方法调用的进口和出口:

public int sum(int a, int b){
    if (logger.isDebugEnabled()){
        logger.debug("sum - start : a is " + a + ", b is " + b);
    }

    int result = a + b;

    if (logger.isDebugEnabled()){
        logger.debug("sum - end : return is " + result);
    }
}


从上例不难发现, 我们在调试过程中, 往往会通过一个方法的进入或退出的状态(参数, 返回值或异常)来分析问题出在什么地方. 那么, 借助 *MethodInterceptor* 我们可以这样做:

Logging拦截器

 

public class LoggingInterceptor implements MethodInterceptor {


    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try {
            Object result = invocation.proceed();

            // logging 方法, 参数与返回值
            log(invocation.getMethod(), invocation.getArguments(), result);

            return result;
        } catch (Throwable throwable) {

            // logging 方法, 参数与异常
            error(invocation.getMethod(), invocation.getArguments(), throwable);

            throw throwable;
        }
    }
}

 

接下来, 我们需要配置这个拦截器, 并向[http://code.google.com/p/google-guice/ Guice]声明它.

public class LoggingModule extends AbstractModule {

    @Override
    public void configure() {
        bindInterceptor(Matchers.any(), Matchers.any(), new LoggingInterceptor());
    }

}

public class Main {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new BusinessModule(), new LoggingModule());

    }
}

 
很简单, 不是吗? 这样我们的业务模块的代码完全不用编写输出日志的代码, 只需要在创建Injector的时候加入LoggingModule就可以了.

等等, 好像忘了去实现如何配置日志输出的位置. 好吧, 这个其实很简单:

配置Logging位置

 

bindInterceptor(Matchers.any(), Matchers.any(), new LoggingInterceptor());

 
bindInterceptor方法的第一个参数定义了拦截器将匹配所有类, 第二个参数定义了拦截器将匹配一个类所有方法. 那么, 我们要做的仅仅是通过外部参数调整这两个参数就可以啦. 这儿就演示一个用正则表达式匹配要Logging的方法的例子:

public class MethodRegexMatcher extends AbstractMatcher<Method> {

    private final Pattern pattern = Pattern.compile(System.getProperty("logging.method.regex", "*"));

    @Override
    public boolean matches(Method method) {
        return pattern.matcher(method.getName()).matches();
    }

}

 
可惜这种方法不能在运行时调整, 但这也是可以实现的.

运行时配置Logging位置


还是以用正则表达式匹配要Logging的方法为例:

public class LoggingInterceptor implements MethodInterceptor {

    private String regex = "*";

    public void setMethodRegex(String regex){
        this.regex = regex;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String methodName = invocation.getMethod().getName();

        try {
            Object result = invocation.proceed();

            if (methodName.matches(regex))
                // logging 方法, 参数与返回值
                log(invocation.getMethod(), invocation.getArguments(), result);

            return result;
        } catch (Throwable throwable) {

            if (methodName.matches(regex))
                // logging 方法, 参数与异常
                error(invocation.getMethod(), invocation.getArguments(), throwable);

            throw throwable;
        }
    }
}

 
而后可借助JMX动态调整regex的值, 来实现运行时的配置. 当然, 肯定还会有其它更好的方法, 如果你知道了不妨分享一下.

 

小结


本文仅以Guice为例讨论如何改进我们日常开发中调试的问题, 其实这在Spring应用也同样能够实现的, 甚至其它应用AOP的场景都是可行的.

拓展开来, 不仅是Logging, 说不定验证(测试)也是可行的呢!

有句话不是这样说的吗, "思想有多远, 我们就能走多远!"

 

 

2
0
分享到:
评论
1 楼 snail_gtt 2010-04-20  
good

相关推荐

    JAVA 中Spring aop 实现日志记载

    在实际开发中,Spring AOP的日志记载不仅限于打印方法名和返回值,还可以记录参数、执行时间、异常信息等,帮助开发者更好地监控和调试系统。 综上所述,Spring AOP提供了一种优雅的方式,让我们能够轻松地在不...

    Flex整合Spring实现aop日志管理

    在IT行业中,日志管理是系统开发中的重要一环,它可以帮助我们追踪错误、调试代码以及监控系统的运行状态。本文将深入探讨如何使用Flex与Spring框架整合,实现AOP(面向切面编程)来达到日志管理的目标。AOP允许我们...

    基于AOP的系统容错研究论文

    【基于AOP的系统容错应用研究】 在信息技术领域,系统容错是保障软件系统稳定性和可靠性的重要手段。本文主要探讨了面向切面编程(Aspect-Oriented Programming, AOP)在系统容错中的应用,旨在提高软件系统的可用...

    spring AOP日志框架

    总结来说,Spring AOP日志框架允许我们通过注解方式轻松地实现业务日志管理,提高代码的可读性和可维护性,同时减少了代码冗余。通过自定义切面和通知,我们可以灵活地控制日志记录的时机和内容,满足不同场景的需求...

    Spring源码工程,可以断点调试,外加一个AOP的小例子(不带JAR包)

    AOP允许开发者将关注点分离,比如日志记录、事务管理、性能监控等,这些通用功能可以编写为切面并在程序的多个点自动应用,而无需在每个具体方法中重复代码。Spring AOP支持两种实现方式:基于代理的AOP和基于注解的...

    利用 spring annotation AOP 反射 记录日志

    在这种场景下,我们常常利用注解来实现AOP,以便于记录日志。注解AOP使得代码更加简洁、可读性更强,而反射则是实现这一目标的关键技术之一。下面我们将详细探讨如何利用Spring的注解AOP和反射来实现日志记录。 ...

    AOP拦截日志JAVA

    日志是任何应用程序的重要组成部分,它有助于调试、性能分析和故障排查。 首先,我们需要了解Spring AOP的五个核心概念: 1. **连接点(Join Point)**:程序执行中的特定点,例如方法的调用或异常的抛出。 2. **...

    spring.net结合三层AOP异常日志记录功能

    Spring.NET是中国开源社区基于.NET Framework实现的一个轻量级企业级应用框架,它借鉴了Java平台上的Spring框架,为.NET开发者提供了强大的依赖注入(Dependency Injection,DI)和面向方面编程(Aspect-Oriented ...

    基于.NET平台C#开发实现的AOP日历管理系统

    《基于.NET平台C#开发实现的AOP日历管理系统》 在软件开发中,日历管理系统是一种常见的应用,它能够帮助用户有效地管理时间,安排任务和活动。本系统采用C#编程语言,利用.NET框架的强大功能,实现了这样一个实用...

    Spring Mvc AOP通过注解方式拦截controller等实现日志管理

    Spring MVC AOP日志管理通常与日志框架(如Log4j、Logback或Java内置的java.util.logging)集成。以下以Log4j为例: 1. 引入依赖:在项目pom.xml中添加Log4j的依赖。 2. 配置Log4j:创建log4j.properties或log4j....

    基于AOP技术的邮件日志系统研究

    总的来说,基于AOP技术的邮件日志系统研究展示了如何利用面向方面编程来优化日志记录,提高系统的可维护性和可扩展性。这种方法不仅适用于邮件服务,也可以推广到其他需要日志功能的软件系统中,体现了AOP在解决横切...

    基于SSM的日志系统

    这个日志系统是基于SSM框架实现的,它旨在记录和管理应用程序运行过程中的各种信息,帮助开发者追踪错误、监控性能、分析用户行为等。 1. **Spring框架**:Spring是核心的依赖注入(DI)和面向切面编程(AOP)框架...

    spring-boot aop

    默认情况下,Spring使用基于Java的代理,但对于需要在静态方法或非Spring管理对象上应用AOP的情况,可能需要使用CGLIB或AspectJ字节码代理。 5. **理解代理行为**:理解Spring AOP代理的工作方式很重要,因为这可能...

    spring-boot-aop-logging:Spring Boot中方法的Aop日志记录

    通过以上步骤,我们就能在Spring Boot应用中实现基于AOP的日志记录。这种方式的好处在于,我们可以在不侵入业务代码的情况下,统一地管理和控制日志记录,提高代码的可维护性和灵活性。 在提供的“spring-boot-aop-...

    springboot spring aop 拦截器注解方式实现脱敏

    虽然在这个特定的例子中,`application.properties`可能没有直接与拦截器相关,但我们可以在这里配置一些全局属性,比如日志级别,这对于调试和监控拦截器的行为非常有用。例如: ```properties logging.level.org....

    aopalliance-1.0.jar &amp; aopalliance-1.0-src.jar

    例如,Spring AOP模块就是基于AOP Alliance的API构建的,它提供了声明式事务管理、缓存管理和其他企业级服务。通过集成aopalliance-1.0.jar,开发者能够充分利用Spring的AOP功能,实现更高效、更灵活的代码组织。 ...

    Java实现aop案例

    10. **测试和调试**:指导如何编写测试用例来验证AOP逻辑的正确性,以及如何调试AOP相关的代码问题。 通过阅读博客文章《Java实现aop案例》,读者应该能够了解并掌握如何在实际项目中应用Spring AOP,从而实现代码...

    aop@work.rar

    面向切面编程(Aspect-Oriented Programming,简称AOP)是软件开发中的一个重要概念,它旨在解决程序中的横切关注点,即那些跨越多个模块、类或方法的共同功能,如日志、事务管理、性能监控等。AOP的核心思想是将...

    Spring AOP的简单实现

    这种方法的好处在于,我们可以在不改动业务代码的情况下,轻松地为系统增加日志记录功能,使得维护和调试变得更加方便。 总结,Spring AOP通过切面、切入点和通知等概念,提供了在不入侵原有代码的基础上,进行日志...

    spring-aop源码

    导入Spring AOP源码到Eclipse工程后,可以通过调试和阅读源码,了解通知的创建、切点的匹配、代理的生成等核心流程,进一步理解Spring AOP的工作原理。 总结,Spring AOP源码的探索有助于开发者深入理解面向切面...

Global site tag (gtag.js) - Google Analytics