Spring—AOP实践,利用切面记录用户操作日志

来源:互联网 发布:简易动画制作软件 编辑:程序博客网 时间:2024/05/15 06:40

配置Spring切面之前,首先准备一下开发环境,Spring不必说了,需要注意的是可能还需要两个jar包,分别是:aopalliance.jar和aspectjweaver.jar.

1:基于注解的方式实现,
首先在Spring配置文件中,开启切面的注解

<!-- 打开AspectJ注解,生成自动代理 --><aop:aspectj-autoproxy expose-proxy="true"/>
然后定义切面类
/** * 写入日志 */@Aspect@Componentpublic class LogAspect {    private Logger logger = LoggerFactory.getLogger(LogAspect.class);    @Reference    private ISysOperateLogProvider sysOperateLogProvider;    // 指定切入点    @Pointcut("@annotation(com...annotation.Log)")    public void logPointCut() {    }    // 前置通知    @Before("logPointCut()")    public void beforeMethod() {    }    // 环绕通知    @Around("logPointCut()")    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {        return pjp.proceed();    }    // 后置通知    @AfterReturning("logPointCut()")    public void afterMethod(JoinPoint joinPoint) {        // 获取被调用的对象(真实对象)        Class<?> entity = joinPoint.getTarget().getClass();        // 获取调用的方法名        String methodName = joinPoint.getSignature().getName();        Method method = null;        Method[] methods = entity.getMethods();        for (Method m : methods) {            if (m.getName().equals(methodName)) {                // 通过反射得到被调用的方法对象                method = m;                break;            }        }// 日志实体对象,保存用户操作相关信息        SysOperateLog sysOperateLog = new SysOperateLog();        // 获取方法上的所有注解        Annotation[] annotations = method.getAnnotations();        for (Annotation annotation : annotations) {            if (annotation.annotationType().equals(Log.class)) {                Log logAnnotation = (Log) annotation;                sysOperateLog.setRemark(logAnnotation.remark());            }        }        try {            // 保存日志            this.sysOperateLogProvider.save(sysOperateLog);        } catch (DubboProviderException e) {            logger.error("操作日志写入失败", e);        }    }    // 异常通知    @AfterThrowing("logPointCut()")    public void exceptionMethod() {    }}

这里有几个点需要注意一下,第一是@Component注解,作用是把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>,第二个是@Reference,这个是dubbo相关知识,请自动忽略,当做是用来保存日志数据的对象即可.第三点是

// 指定切入点@Pointcut("@annotation(com...annotation.Log)")
这里使用自定义注解的形式去指定切入点了,也可以写成其他的表达式,可以参考事务的切面配置,我这里用自定义的注解,里面包含了一个remark的属性,用来记录操作模块信息,如下:
/** * 自定义注解写入日志 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Log {    /*     * 用户操作模块说明     */    public String remark();}

这样就大功告成了,标注了@Log的模块,就变成切面了,自定义注解记得要在Spring配置文件中扫描.

2:基于配置文件的实现,同上,也是将被@Log注解过的模块为切面,定义切面类

/** * 配置写入日志的切面 */public class LogAspect {    private Logger logger = LoggerFactory.getLogger(LogAspect.class);    @Reference    private ISysOperateLogProvider sysOperateLogProvider;    // 前置通知    public void beforeMethod() {    }    // 环绕通知    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {        return pjp.proceed();    }    // 后置通知    public void afterMethod(JoinPoint joinPoint) {        // 获取被调用的对象(真实对象)        Class<?> entity = joinPoint.getTarget().getClass();        // 获取调用的方法名        String methodName = joinPoint.getSignature().getName();        Method method = null;        Method[] methods = entity.getMethods();        for (Method m : methods) {            if (m.getName().equals(methodName)) {                // 通过反射得到被调用的方法对象                method = m;                break;            }        }        SysOperateLog sysOperateLog = new SysOperateLog();        sysOperateLog.setUserId("admin");        // 获取方法上的所有注解        Annotation[] annotations = method.getAnnotations();        for (Annotation annotation : annotations) {            if (annotation.annotationType().equals(Log.class)) {                Log logAnnotation = (Log) annotation;                sysOperateLog.setRemark(logAnnotation.remark());            }        }        try {            // 保存日志            this.sysOperateLogProvider.save(sysOperateLog);        } catch (DubboProviderException e) {            logger.error("操作日志写入失败", e);        }    }    // 异常通知    public void exceptionMethod() {    }}
Spring配置文件新增如下内容即可.
<bean id="logAspect" class="com...LogAspect"/><aop:config proxy-target-class="true"><aop:pointcut id="logPointCut" expression="@annotation(com...annotation.Log)"/><aop:aspect ref="logAspect"><aop:after-returning method="afterMethod" pointcut-ref="logPointCut"/></aop:aspect></aop:config>
关于切面类里面的各个通知的意思:
通知就是:在调用目标方法的什么时候调用切面组件的方法,可以是:
前置通知:@Before,方法调用之前被调用
后置通知:@AfterReturning,方法正常返回后被调用
异常通知:@AfterThrowing,方法调用过程中出现异常被调用
最终通知:@After,不管方法是正常返回还是出现异常,这个通知都会调用
环绕通知:@Around,在方法被调用前和返回后都会被调用(慎用)



原创粉丝点击