使用AOP加自定义注解输出日志

什么是AOP、切面编程?想必各位Java Coder早已不陌生,徐叔就不过多解释。直接上代码需要的小伙伴们可以参考。

一、自定义注解

/**
 * 打印日志注解<br>
 * 作者:徐承恩<br>
 * 日期:2016/12/7-17:11<br>
 */
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
@Inherited
public @interface PrintLog {
}

二、添加AspectJ依赖并整合Spring

<!-- AOP注解编程组件 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

整合spring使用注解的方式进行AOP编程

<!-- 注意:子容器可以访问父容器的Bean但父容器不可以访问子容器的Bean。-->

<!-- 开启父容器注解 -->
<context:annotation-config/>

<!-- 开启任务注解 -->
<task:annotation-driven/>

<!-- 开启AOP注解 -->
<aop:aspectj-autoproxy/>

<!-- 父容器只扫描@Service、@Repository、@Component的注解 -->
<context:component-scan base-package="com.bbc.rec">
    <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

三、编写切面类

/**
 * 打印日志切面类<br>
 * 作者:徐承恩<br>
 * 日期:2016/12/7-17:14<br>
 */
@Aspect
public class PrintLogAop {

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

    /**
     * 返回通知
     */
    @AfterReturning(value = "execution(@com.bbc.rec.common.annotation.PrintLog * *(..))", returning = "result")
    public void afterreturning(JoinPoint joinPoint, Object result) {
        try {
            Class targetClass = joinPoint.getTarget().getClass();
            //将代理类方法转为原始类方法以便拿到注解信息
            Method proxyMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();
            //原始方法名
            Method targetMethod = targetClass.getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
            //得到参数列表
            Object[] params = joinPoint.getArgs();
            //得到目标类名
            String className = targetClass.getSimpleName();
            //得到目标方法名
            String methodName = targetMethod.getName();
            //得到参数类型
            Class[] parmsClass = targetMethod.getParameterTypes();

            Map<String, Object> paramsMap = new HashedMap();
            for (int i = 0; i < parmsClass.length; i++) {
                String _className = parmsClass[i].getSimpleName();
                Object _param = params[i];
                paramsMap.put(_className, _param);
            }

            Map<String, Object> map = new LinkedHashMap<String, Object>();
            map.put("目标类名", className);
            map.put("目标方法名", methodName);
            map.put("请求参数", paramsMap);

            if (null != result) {
                Class resultClazz = result.getClass();
                //得到返回值类名
                String resultClassName = resultClazz.getSimpleName();
                map.put("返回值类名", resultClassName);
                map.put("返回值", result);
            }
            log.info("【切面打印日志】{}", JSONObject.toJSONString(map, SerializerFeature.WriteMapNullValue));
        } catch (NoSuchMethodException e) {
            log.error("【切面打印日志异常】【异常栈】", e);
        }
    }