Spring中Aop实现日志功能

前言

上篇分享了jdk动态代理以及cglib代理,是对某个接口或者类进行增强扩展实现。AOP (Aspect Orient Programming),面向切面编程,AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,实现开闭原则。下边我们以实现aop实现日志的记录为例。

1.环境搭建

jdk1.8+IDEA+MyBatisPlus+mysql实现。
具体的安装不在这里赘述。

2.设计日志记录表

CREATE TABLE `busi_log` (
  `ID` bigint(20) NOT NULL COMMENT '主键id',
  `USER_ID` bigint(20) DEFAULT NULL COMMENT '用户id',
  `CLASS_NAME` varchar(255) DEFAULT NULL COMMENT '类名称',
  `METHOD` varchar(100) DEFAULT NULL COMMENT '方法名称',
  `DESCRIPTION` text COMMENT '方法描述',
  `CREATE_DATE` datetime DEFAULT NULL COMMENT '创建日期',
  PRIMARY KEY (`ID`) USING BTREE,
  KEY `ID` (`ID`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作日志表';

3.aop需要引入aspectj依赖

      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.9.7</version>
      </dependency>

4.日志实体类设计

/**
 * 操作日志表
 */
@TableName("busi_log")
public class BusiLog {
    //主键id
    @TableId(value = "ID", type = IdType.ASSIGN_ID)
    protected Long id;

    //用户id
    @TableField(value = "USER_ID")
    protected Long userId;

    //类名称
    @TableField(value = "CLASS_NAME")
    protected String className;

    //方法名称
    @TableField(value = "METHOD")
    protected String method;

    //方法描述
    @TableField(value = "DESCRIPTION")
    protected String description;

    // 创建日期
    @TableField(value = "CREATE_DATE", fill = FieldFill.INSERT)
    protected Date createDate;
    //此处省略 set get方法
}

5.自定义日志BusiLog注解

/**
 * 自定义日志注解
 */
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BusiLog {

    /**
     * 操作具体某个功能的描述
     * @return
     */
    String desc() default "";
}

6.定义日志切面

6.1 此处只使用了环绕通知

实际业务中我们还可能记录异常日志,操作日志,等等。

/**
 * 日志切面类
 */
@Component
@Aspect
@Slf4j
public class BusiLogAop {

    /**
     * 引入日志持久化的mapper类
     */
    @Autowired
    private BusiLogMapper busiLogMapper;

    /**
     * 定义BusLogAop的切入点为标记@BusLog注解的方法
     */
    @Pointcut(value = "@annotation(com.elite.mybatisplus.annotation.BusiLog)")
    public void pointcut() {
    }

    /**
     * 业务操作环绕通知
     *
     * @param proceedingJoinPoint
     * @retur
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        log.info("==========BusiLogAop环绕通知===============");
        //执行目标方法
        Object result = null;
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //目标方法执行完成后,获取目标类、目标方法上的业务日志注解上的功能名称和功能描述
        Object target = proceedingJoinPoint.getTarget();
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        BusiLog anno = signature.getMethod().getAnnotation(BusiLog.class);
        //没设计好名字,注解和实体类名字一致了
        com.elite.mybatisplus.entity.BusiLog busiLogEntity = new com.elite.mybatisplus.entity.BusiLog();
        busiLogEntity.setUserId(1L); //此处写死
        busiLogEntity.setClassName(target.getClass().getName());
        busiLogEntity.setMethod(signature.getMethod().getName());
        busiLogEntity.setDescription(anno.desc());
        busiLogEntity.setCreateDate(new Date());
        //保存业务操作日志信息
        this.busiLogMapper.insert(busiLogEntity);
        log.info("----BusAop 环绕通知 end");
        return result;
    }
}

6.2 @Aspect中有5种通知

  • @Before:前置通知, 在方法执行之前执行
  • @Aroud:环绕通知, 围绕着方法执行
  • @After:后置通知, 在方法执行之后执行
  • @AfterReturning:返回通知, 在方法返回结果之后执行
  • @AfterThrowing:异常通知, 在方法抛出异常之后

7.业务中使用注解

直接在方法上边使用注解即可。

/**
 * 人员信息管理
 */
@RestController
public class PersonController {

    @Autowired
    IPersonService personService;

    /**
     * 查询人员信息列表
     * @return
     */
    @BusiLog(desc = "查询人员信息列表")
    @GetMapping("/getPersonList")
    public List<Person> getPersonList(){
        return  personService.list();
    }

    /**
     * 新增人员信息
     */
    @BusiLog(desc = "新增人员信息")
    @PostMapping("/addPerson")
    public String addPerson(@RequestBody Person person){
        personService.save(person);
        return "新增人员信息成功!";
    }

    /**
     * 更新人员信息
     */
    @BusiLog(desc = "更新人员信息")
    @PostMapping("/updatePerson")
    public String updatePerson(@RequestBody Person person){
        personService.updateById(person);
        return "更新人员信息成功!";
    }
    /**
     * 删除人员信息
     */
    @BusiLog(desc = "删除人员信息")
    @GetMapping("/deletePersonById/{id}")
    public String deletePersonById(@PathVariable("id")Long id){
       personService.removeById(id);
       return "删除成功!";
    }
}

8.测试

此处我们只测试查询,看看效果。

8.1 测试查询

查询

8.2 测试删除

delete
新增和修改就不测试,同样的方法。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 使用SpringAOP可以实现缓存功能。具体实现方式是,在需要缓存的方法上添加@Cacheable注解,指定缓存的key和缓存的名称。当方法被调用时,Spring会先检查缓存是否存在该key对应的缓存数据,如果存在则直接返回缓存数据,否则执行方法并将返回结果缓存起来。同时,还可以使用@CachePut注解更新缓存数据,或者使用@CacheEvict注解清除缓存数据。这样可以有效地提高系统性能和响应速度。 ### 回答2: 使用SpringAOP实现缓存功能的步骤如下: 1. 首先,需要在Spring配置文件启用AOP功能,可以通过添加`<aop:aspectj-autoproxy/>`来实现。 2. 然后,创建一个用于缓存方法调用结果的类,该类需要实现`org.springframework.cache.Cache`接口,并提供对缓存的读取、写入、删除等操作方法。 3. 还需要创建一个切面类,该类需要使用`@Aspect`注解进行标记,并在需要缓存的方法上添加`@Cacheable`注解。在切面类,使用`@Before`和`@After`等注解来定义缓存操作的切点和通知。 4. 在Spring配置文件,将切面类声明为一个bean,并在`<aop:config>`指定要应用缓存的方法和切面。 5. 最后,配置`ehcache.xml`(或其他缓存配置文件),并将其指定为Spring配置文件缓存管理器的实现类,例如`<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"/>`。 这样,当被缓存的方法被调用时,AOP将切入切面类的通知方法,首先查询缓存是否存在该方法的结果,如果存在,则直接返回缓存的结果;如果不存在,则调用原始方法,并将结果存入缓存。在后续的调用,如果参数相同,则直接从缓存获取结果,从而减少了对原始方法的调用,提高了系统的性能和响应速度。 使用SpringAOP实现缓存功能可以大大简化代码,提高项目的可维护性和可扩展性,同时还能通过缓存数据减少对数据库等资源的访问,提升系统整体的性能。 ### 回答3: 使用SpringAOP可以很方便地实现缓存功能AOP(面向切面编程)是一种编程范式,通过在程序运行时动态地将横切逻辑(如日志记录、事务管理、异常处理等)插入到应用程序的特定位置,以提供更好的代码结构和模块化。 在使用SpringAOP实现缓存功能时,我们可以通过以下步骤来实现: 1. 定义一个缓存注解:可以使用Spring提供的@Cacheable注解来定义缓存的方法。这个注解可以应用在方法上,用于标记被缓存的方法。 2. 配置缓存切面:通过AOP切面配置,将缓存注解和具体的缓存实现关联起来。可以使用Spring的@Aspect注解来定义一个切面类,该类可以包含多个增强方法用于处理缓存操作。 3. 配置缓存策略:在切面类,可以通过使用Spring的缓存管理器(如Ehcache、Redis等)来定义缓存的具体策略。可以配置缓存的过期时间、缓存的存储位置等。 4. 在目标方法使用缓存注解:在需要被缓存的方法上添加之前定义的缓存注解。当方法被调用时,AOP切面会先检查缓存是否存在对应的缓存数据,如果存在则直接返回缓存数据,否则执行方法逻辑并将结果存入缓存。 5. 测试缓存功能:执行目标方法,观察是否从缓存获取数据以及方法执行的时间。 通过这种方式,我们可以很方便地在应用加入缓存功能,提高系统性能和响应速度。同时,由于使用了AOP的方式,可以很好地解耦和复用缓存相关的代码逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘同学要加油呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值