前言

刚加入新公司,一来项目组长就让我带3个实习生,也是鸭梨山大啊。今天在旁边看他们写代码,感觉基础的能力还是可以的,不过技术上面还是有不少欠缺的啊。
比如:项目组长让他们把Service层,每个方法都要加上日志打印,执行该方法之前的,执行之后的,还要打印方法参数值。看他们一直就那样手动的log.debug(),我也是很无奈。。当时就说了用AOP去实现很简单的,尤其是本来项目就是基于SpringBoot的,连配置都省了。结果都不会,因为我电脑还没审批下来,当时就没给他们演示了。回来写了Demo,等电脑下来,就让他们学学看,苦逼的花大半天加log,在我这里只需要分分钟的事,嘿嘿。

环境

  • jdk1.8
  • springboot 1.5.1.RELEASE

配置

需要注意的是,Mavenpom.xml文件再原有的springboot配置之上还要加一个aop的,如下:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

添加以上配置会自动导入spring-aop, aspectjrt, aspectjweaver这几个jar包的

AOP

这里只为了简单的演示一下如何完成打印日志需求:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class LoggerAopConfig {

    private static final Logger log = LoggerFactory.getLogger(LoggerAopConfig.class);

    // 只关注方法名为find前缀的
    @Pointcut("execution(* find* (..))")
    public void executeService() {}


    @Before("execution(* find*(..))")
    public void invokeBefore(JoinPoint point) {
        String realClassName = getRealClassName(point);
        log.debug("调用-----"+ realClassName + " 执行 " + getMethodName(point) + " 方法之前");
    }

    @After("execution(* find*(..))")
    public void invokeAfter(JoinPoint point) {
        String realClassName = getRealClassName(point);
        log.debug("调用-----"+ realClassName + " 执行 " + getMethodName(point) + " 方法之后");
    }


    /**
     * 获取被代理对象的真实类全名
     * @param point 连接点对象
     * @return 类全名
     */
    private String getRealClassName(JoinPoint point) {
        return point.getTarget().getClass().getName();
    }

    /**
     * 获取代理执行的方法名
     * @param point 连接点对象
     * @return 调用方法名
     */
    private String getMethodName(JoinPoint point) {
        return point.getSignature().getName();
    }
}

其中关于JoinPoint有以下几个常用方法:

  • Object[] getArgs:返回目标方法的参数
  • Signature getSignature:返回目标方法的签名
  • Object getTarget:返回被织入增强处理的目标对象
  • Object getThis:返回AOP框架为目标对象生成的代理对象
    注意:当使用@Around处理时,我们需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。

总结

技术是需要灵活变通的,当一个类似的代码重复3-5遍的时候就应该要想想,有什么办法可以减少重复代码了。当基础技术学的差不多的时候,编程思想就能看出技术水平的高低啦,要想着摆脱低级搬砖码农的处境,思想很关键。还要学的有很多,坚持。