基于schema的AOP,实现日志记录Demo

来源:互联网 发布:阿里云 余额不足通知 编辑:程序博客网 时间:2024/05/27 21:48

笔者今天使用<aop:aspect>配置文件的形式,外加注解,一个接口,一个日志记录类,实现访问某些指定Controller层方法时候记录日志的功能,并在注解中传入参数functionCode和menuCode,供日志记录类使用,

如下为Demo代码:

1.准备工作,一个注解的接口类

import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;/* * 业务日志接口 */@Retention(RetentionPolicy.RUNTIME)public @interface SaveLog {        //接口成员:基本以及衍生的数据类型  无入参 无异常    String menuCode();    String functionCode();}
说明:SaveLog接口必须使用@标注,可解释为标签;接口的参数成员menuCode,functionCode必须是无参的,且是八种基本数据类型及其衍生类;如List menu(),就是错误的。

2.Controller里的调用方法

/**     *      *       * 〈日志记录Demo入口〉     *     * @return     * @see [相关类/方法](可选)     * @since [产品/模块版本](可选)     */    @ResponseBody    @RequestMapping("/aopTest.action")    @SaveLog(menuCode="10",functionCode="20")    public Map<String, Object> aopTest(String a){        Map<String, Object> map = new HashMap<String, Object>();        map.put("aopTest", "true");        return map;    }

说明:这里请重点关注@SaveLog,并且传入参数menuCode="10"和functionCode="20",aopTest(String a)方法传入参数String a,返回一个Map对象,这些参数打算在日志记录里捕获。

3.Spring里的配置文件




<!--  logSave切面配置 --><aop:config proxy-target-class="true"><aop:aspect ref="SaveLog"><aop:pointcut expression="execution(* com.suning.sample.web.*.*(..))" id="SaveLogPoint"/><aop:after-returning method="saveBusinessLog" pointcut-ref="SaveLogPoint"  returning="res"/></aop:aspect></aop:config><bean id="SaveLog" class="com.suning.schema.aop.SaveLogImpl"></bean>

说明:proxy-target-class="true"是指使用CGLIB的动态代理,定义一个切面SaveLog指的是SaveLogImpl这个类,切点是com.suning.sample.web包下所有类的所有方法,第一个*是指返回值任意,第二个*指com.suning.sample.web包下任意类,第三个*指任意方法,(..)指方法参数任意;在切入点上的方法执行结束后(after-return),调用切面SaveLog的saveBusinessLog()方法,并传入参数res:


4.重点:此处为实现记录业务日志的关键类SaveLogImpl.java

package com.suning.schema.aop;import java.lang.reflect.Method;import java.util.Map;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.reflect.MethodSignature;/* * 切面增强实现类 */public class SaveLogImpl{        public void saveBusinessLog(JoinPoint joinPoint, Map<String,Object> res){        // 得到类路径        String classType = joinPoint.getTarget().getClass().getName();        // 得到方法名        String methodName = joinPoint.getSignature().getName();        MethodSignature jp = (MethodSignature) joinPoint.getSignature();        Method method = jp.getMethod();        Class<?>[] parameterTypes = method.getParameterTypes();        Class<?> className = null;        try {            className = Class.forName(classType);            method = className.getMethod(methodName, parameterTypes);        }catch(Exception e){            System.out.println("抛异常");        }         SaveLog desc = method.getAnnotation(SaveLog.class);        System.out.println("SaveLog注解参数functionCode:" + desc.functionCode());        System.out.println("SaveLog注解参数menuCode:" + desc.menuCode());    }}

说明:我的demo里重点是展现获取连接点相关的参数,包括如下三个参数



还记得配置文件中这个么?


其实他是aopTest作为参数传给了saveBusinessLog这个记录日志的业务方法,如下:





5:测试,地址栏中输入如下地址,地址中传入参数a=1




查看saveBusinessLog()方法是否获取了连接点的相关值:




心得:同一pointCut下的增强方法均会执行,小技巧就是在配置文件中最好细化切入点。不赘述。







0 0
原创粉丝点击