Spring AOP实现简单的日志功能

时间:2022-06-23
本文章向大家介绍Spring AOP实现简单的日志功能,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

AOP对代码的侵入性非常的小,是一种可插拔的思想,大大降低了耦合度,AOP在许多地方都有应用,这篇文章就看看使用AOP实现日志的功能,也算是AOP思想的一种体现了。

主要是在用户访问一个URL前,记录用户的ip,访问方式,访问的URL,访问的哪个方法以及该方法的参数,访问URL后,记录访问返回的结果。

整个项目基于Spring Boot构建。

首先建立一个实体类Man,对应数据库中的一个表
@Entity
public class Man {
    // 主键、自增
    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    private Integer age;
    // 省略get/set方法
}
使用jpa实现基本的CRUD(没搞service,直接在controller里干了,凑合着看~)
@RestController
@RequestMapping("/man")
public class ManController {
    @Autowired
    private ManDao manDao;
    
    @Autowired
    private ManService manService;
    
    private Logger logger = LoggerFactory.getLogger(ManController.class);
    
    /**
     * 添加一条记录
     * @param man 结果集合
     * @Validated 注解
     * @return
     */
    @GetMapping("/insertMan")
    public Man insertOne(@Validated Man man, BindingResult br) {
        man.setName(man.getName());
        man.setAge(man.getAge());
        return manDao.save(man);
    }
    
    /**
     * 获取所有记录
     * @return
     */
    @GetMapping("/manList")
    public List<Man> getList() {
        logger.info("getList");
        return manDao.findAll();
    }
    
    /**
     * 根据id查询一条记录
     * @param id
     * @return
     */
    @GetMapping("/man/{id}")
    public Man getOne(@PathVariable("id") Integer id) {
        return manDao.findOne(id);
    }
    
    /**
     * 更新指定的一条记录
     * @param id
     * @param name
     * @param age
     * @return
     */
    @GetMapping("/updateMan/{id}")
    public Man updateOne(@PathVariable("id") Integer id, @RequestParam("name") String name, 
            @RequestParam("age") Integer age) {
        Man man = new Man();
        man.setId(id);
        man.setName(name);
        man.setAge(age);
        return manDao.save(man);
    }
    
    @RequestMapping("/deleteMan/{id}")
    public void deleteOne(@PathVariable("id") Integer id) {
        manDao.delete(id);
    }
    
    @RequestMapping("/insertTwo")
    public void insertTwo() {
        manService.insertTwo();
    }
}
使用AOP实现日志功能
/**
 * @Component 该注解表示把类加入spring容器
 * @Aspect 该注解表示切面
 * @author liu
 */
@Component
@Aspect
public class Log {
    
    private Logger logger = LoggerFactory.getLogger(Log.class);
    
    /**
     * 定义一个公共切点,代码复用
     * 拦截com.codeliu.controller.ManController类下面的所有public方法
     */
    @Pointcut(value = "execution(public * com.codeliu.controller.ManController.*(..))")
    private void log() {}
    
    /**
     * 方法执行前切入
     */
    @Before(value = "log()")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes sa = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sa.getRequest();
        // 获取用户访问的url
        logger.info("url={}", request.getRequestURL());
        // 获取用户访问的方式,get/post
        logger.info("method={}", request.getMethod());
        // 获取的ip
        logger.info("ip={}", request.getRemoteAddr());
        // 获取用户访问的是哪个方法
        logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        // 获取方法的参数
        logger.info("args={}", joinPoint.getArgs());
    }
    
    @After(value = "log()")
    public void after() {
        logger.info("记录操作后");
    }
    
    /**
     * 打印返回的内容
     * @param object
     */
    @AfterReturning(value = "log()", returning = "object")
    public void afterReturn(Object object) {
        logger.info("object={}", object);
    }
}

切点是ManController 下面的所有public方法,在执行方法前,记录访问的URL等信息,方法返回后,记录返回的结果(@AfterReturning注解的returning 属性)。

试着访问一下getList方法获取数据库所有记录

可以看看控制台的输出

这样使用aop就实现了一个简单的日志功能。