AOP切面记录日志-实操

前言

        记录日志的就是把很多重要的数据给记录下来,写到数据库中;可以写一个方法,组装好之日信息的参数穿进去,但这样做不是很优雅,因为对于日志来说,不是业务逻辑代码的一部分,不应该影响到业务代码的,所以,使用切面正好解决了这个问题。

使用案例

1、自定义注解

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    //参数类
    Class< ? extends ConvertParam> convert();

    //操作类型
    BusinessType businessType() default BusinessType.OTHER;

}

这个Log注解就是使用在需要记录日志的地方,注解里面的参数,是需要在注解使用时传进去的,有些给了默认值的的就可以不传,如果传了就会覆盖掉

2、参数统一

上面的注解里面有一个参数类:

Class< ? extends ConvertParam> convert();

 这个是自定义的一个接口,作用是将我们任何的参数转换成切面注解能够使用的参数,实现标准化。例如:SysLog类,有两个属性,这个就是接口的标准返回值

public class SysLog {
    private Integer id;
    private String serviceName;
}

标准接口:

public interface ConvertParam {
    SysLog convert(Param param);
}

不管你传递的Param是什么类型,你在实现这个convert方法的时候,都必须想办法将Param转换为SysLog,因为SysLog这个对象是你后面写入逻辑的标准对象,就不需要你去做if-else的判断了,这个其实用到了策略模式,来处理多种实现方式。

3、定义切面、切点

@Aspect
@Component
public class LogAspect {

    @Resource
    HttpServletRequest httpServletRequest;

    /**
     * 定义切面
     */
    @Pointcut("@annotation(com.cart.cartservice.Log.annotation.Log)")
    public void section() {
    }

    /**
     * 环绕切点
     *
     * @param
     * @return result
     */
    @Around("section()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        //注解修饰的方法的返回结果
        Object result = joinPoint.proceed();
        //切面逻辑,收集日志什么的
        handleLog(joinPoint, result);
        //这个别忘记了
        return result;
    }

    @SneakyThrows
    private void handleLog(ProceedingJoinPoint joinPoint, Object result) {
        //标准三部曲,拿取注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log logAnnotation = method.getAnnotation(Log.class);
        
        //获取方法参数
        Object[] args = joinPoint.getArgs();

        //获取注解里面的通用接口,这一步就是接口的参数转换为标准类型,方便后续使用
        Class convert = logAnnotation.convert();
        ConvertParam convertParam = convert.newInstance();
        SysLog sysLog = convertParam.convert(args[0]);

        //拿到sysLog 标准对象之后,就可以定义标准的写入逻辑,不需要做任何的类型判断了
    }

}

切面配置你自定义的注解,只要是出现你注解的地方就是切面,然后就是切点和处理逻辑。

 4、使用注解

    @Log(convert = IntegerConvertParamImpl.class,businessType = BusinessType.QUERY)
    @GetMapping("{id}")
    public ResponseEntity queryById(@PathVariable("id") Integer id) {
        return ResponseEntity.ok(this.cartService.queryById(id));
    }

IntegerConvertParamImpl就是将接口的参数转换为标准SysLog的实现类

import com.cart.cartservice.Log.convert.ConvertParam;
import com.cart.cartservice.Log.entity.SysLog;
import org.springframework.stereotype.Service;

@Service
public class IntegerConvertParamImpl implements ConvertParam {

    @Override
    public SysLog convert(Integer integer) {
        SysLog sysLog = new SysLog();
        sysLog.setId(integer);
        return sysLog;
    }
}

你可能感兴趣的:(spring,java,spring)