Spring AOP运用---记录方法调用与结果日志

来源:互联网 发布:阿里云服务器 密钥 编辑:程序博客网 时间:2024/06/05 15:45

Spring AOP运用—记录方法调用与结果日志

AOP(Aspect Oriented Programming),即面向切面编程,更多的理论知识可以参考http://jinnianshilongnian.iteye.com/blog/1418596,本文主要针对掌握了一定的理论知识基础上,如何在实际项目中运用AOP。

在进行互联网项目开发过程中,尤其是微服务开发模式下,各模块(或web服务)之间会有频繁的调用过程,为了后续的问题排查与定位,往往需要在方法调用入口与出口处记录日志,如下:

logger.info("接收xxxxxx参数{}",JSON.toJSONString(request));doSomething();logger.info("接收XXXXXX返回{}",JSON.toJSONString(result));

这样实现需要对每个方法添加类似代码,如果采用AOP实现,则方法体内仅实现具体的业务逻辑即可,不用再额外添加与业务无关的通用代码。

AOP编程基本流程

1、定义业务切面(所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。)
2、定义切入点,一个切入点可能横切多个业务组件(即在哪些地方,对哪些方法进行拦截)
3、定义处理动作,就是在AOP框架为业务切面织入的处理动作

AOP编程实战

下面将针对本文开头提到的采用AOP进行日志记录的完整实现。

定义日志处理切面

import com.alibaba.fastjson.JSON;import org.aspectj.lang.JoinPoint;public class LogHandler {    /**     * 打印方法入参     * @param jp     */    public void methodParam(JoinPoint jp){        System.out.println("---method " + jp.getSignature().toShortString() +"invoked,param is :"                + JSON.toJSONString(jp.getArgs()));    }    /**     * 打印方法返回结果     * @param jp     * @param retVal     */    public void methodResult(JoinPoint jp,Object retVal){        System.out.println("---method " + jp.getSignature().toShortString() +"invoked,result is :"                +retVal);    }    /**     * 打印异常     * @param jp     * @param exception     */    public void methodException(JoinPoint jp, Exception exception){        System.out.println("---method " + jp.getSignature().toShortString() +"invoked,exception " +                "is :"                + exception.getMessage());    }}

LogHandler 类中定义了3个切面处理,methodParam用于打印方法的入参,methodResult打印方法的返回结果,methodException打印异常日志。

定义切入点

在XML配置文件中进行配置

<aop:pointcut id="pointcut" expression="execution(* service.*.*(..))"/>

表示对service包下的所有方法有效。

定义处理动作

<aop:aspect ref="logHandler">            <aop:before pointcut-ref="pointcut" method="methodParam"/>            <aop:after-returning pointcut-ref="pointcut" method="methodResult" returning = "retVal"/>            <aop:after-throwing pointcut-ref="pointcut" method="methodException"  throwing = "exception"/>        </aop:aspect>

完整的XML配置如下:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:aop="http://www.springframework.org/schema/aop"       xmlns:task="http://www.springframework.org/schema/task"       xsi:schemaLocation="http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/context         http://www.springframework.org/schema/context/spring-context.xsd   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">    <aop:aspectj-autoproxy />    <context:annotation-config />    <context:component-scan base-package="service">        <context:exclude-filter type="annotation"                                expression="org.springframework.stereotype.Controller"/>    </context:component-scan>    <!-- 支持异步方法执行 -->    <task:annotation-driven />    <bean id="helloWorldService"          class="service.impl.HelloWorldServiceImpl"/>       <bean id="logHandler" class="aop.LogHandler"/>    <aop:config>        <aop:pointcut id="pointcut"                      expression="execution(* service.*.*(..))"/>           <aop:aspect ref="logHandler">            <aop:before pointcut-ref="pointcut" method="methodParam"/>            <aop:after-returning pointcut-ref="pointcut" method="methodResult" returning = "retVal"/>            <aop:after-throwing pointcut-ref="pointcut" method="methodException"  throwing = "exception"/>        </aop:aspect>    </aop:config></beans>

测试

在service包下创建HelloWorldService接口以及service.impl包下创建实现该接口的HelloWorldServiceImpl类
HelloWorldService.java

public interface HelloWorldService {    public String methodLog(String obj);}

HelloWorldServiceImpl.java

public class HelloWorldServiceImpl implements HelloWorldService {    public String methodLog(String obj) {        Random random = new Random(System.currentTimeMillis());        return String.valueOf(random.nextInt());    }}

创建Junit进行测试

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {"classpath*:config/applicationContext.xml"})public class AopTest {    @Resource    private HelloWorldService helloWorldService;    @Test    public void methodLogTest_nomal(){        helloWorldService.methodLog("nomal");    }}

测试结果:

---method HelloWorldService.methodLog(..)invoked,param is :["nomal"]---method HelloWorldService.methodLog(..)invoked,result is :-1928245693

AOP在项目中运用比较多的有方法权限验证、参数验证方法耗时统计处理等。具体使用方法类似。更多可参看Spring的官方文档。

原创粉丝点击