当前位置: 代码网 > it编程>编程语言>Java > SpringBoot整合Aop全过程

SpringBoot整合Aop全过程

2024年11月03日 Java 我要评论
aop 可以做什么?1. 日志记录自动记录方法的调用、参数、返回值和异常等信息,减少了在每个方法中添加日志代码的需要。2. 管理事务在方法执行前后自动处理事务的开启、提交和回滚,确保数据的一致性和完整

aop 可以做什么?

  • 1. 日志记录
  • 自动记录方法的调用、参数、返回值和异常等信息,减少了在每个方法中添加日志代码的需要。
  • 2. 管理事务
  • 在方法执行前后自动处理事务的开启、提交和回滚,确保数据的一致性和完整性。
  • 3. 权限控制
  • 实现方法的访问控制,检查用户权限,确保只有授权用户才能执行特定操作。
  • 4. 性能监控
  • 自动收集方法的执行时间、调用次数等性能指标,帮助开发者进行性能分析和优化。
  • 5. 缓存管理
  • 实现方法结果的缓存,减少重复计算,提高系统性能。
  • 6. 异常处理
  • 统一处理方法执行中的异常,简化异常捕获和处理逻辑。
  • 7. 输入验证
  • 在方法执行前对输入参数进行验证,保证数据的有效性和完整性。
  • 8. 动态代理
  • 创建代理对象,在不修改原有类的情况下添加额外的行为。

应用场景

  • web开发:用于请求处理、事务管理、安全控制等。
  • 企业应用:在服务层实现统一的日志和异常处理。
  • 微服务:在服务之间进行统一的监控和熔断处理。

日志记录

1.准备工作

首先需要导入aop依赖

pom.xml

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-aop</artifactid>
</dependency>
<dependency>
    <groupid>com.alibaba.fastjson2</groupid>
    <artifactid>fastjson2</artifactid>
    <version>2.0.50</version>
</dependency>
<dependency>
    <groupid>io.jsonwebtoken</groupid>
    <artifactid>jjwt</artifactid>
    <version>0.9.1</version>
</dependency>

然后需要创建日志记录数据库和实体类还有在mapper层实现插入数据方法

  • 实体类
//操作日志实体类
@data
@noargsconstructor
@allargsconstructor
public class operatelog {
    private integer id; //主键id
    private integer operateuser; //操作人id
    private localdatetime operatetime; //操作时间
    private string classname; //操作类名
    private string methodname; //操作方法名
    private string methodparams; //操作方法参数
    private string returnvalue; //操作方法返回值
    private long costtime; //操作耗时
}
  • mapper接口
@mapper
public interface operatelogmapper {

    //插入日志数据
    @insert("insert into operate_log (operate_user, operate_time, class_name, method_name, method_params, return_value, cost_time) " +
            "values (#{operateuser}, #{operatetime}, #{classname}, #{methodname}, #{methodparams}, #{returnvalue}, #{costtime});")
    public void insert(operatelog log);

}

2.创建自定义注解和切面类

因为我们要记录的操作日志是对于数据的增,删,改所以采用@annotation来指定要为连接点的方法。

而且在涉及到消耗时间的字段,所以需要采用@around通知类型

  • 自定义注解类
@retention(retentionpolicy.runtime)//运行时有效
@target(elementtype.method)//作用在方法上
public @interface log {
}

3.实现日志记录(around)

首先需要需要记录的操作接口方法前加上@log注解

接下来在切面类中实现操作日志记录:

@aspect
@component
public class logasper {
    @autowired
    private operatelogmapper operatelogmapper;
    @autowired
    private httpservletrequest request;

    @around("@annotation(com.ly.springbootdemotlias.anno.log)")//匹配加了log注解的方法
    public object recordlog(proceedingjoinpoint joinpoint) throws throwable {
        operatelog operatelog = new operatelog();
        //获取操作人id,通过获取并解析jwt令牌
        string jwt = request.getheader("token");
        claims claims = jwtutils.parsejwt((jwt));
        integer operateuser =(integer) claims.get("id");
        operatelog.setoperateuser(operateuser);
        //获取操作时间
        operatelog.setoperatetime(localdatetime.now());
        //获取操作类名
        operatelog.setclassname(joinpoint.gettarget().getclass().getname());
        //获取操作方法名
        operatelog.setmethodname(joinpoint.getsignature().getname());
        //获取操作方法参数
        operatelog.setmethodparams(arrays.tostring(joinpoint.getargs()));
        //获取开始时间
        long begin = system.currenttimemillis();
        //获取操作方法返回值
        object result = joinpoint.proceed();
        string returnvalue = jsonobject.tojsonstring(result);
        operatelog.setreturnvalue(returnvalue.tostring());
        //获取操作结束时间
        long end = system.currenttimemillis();
        //获取操作耗时
        operatelog.setcosttime((end-begin));
        operatelogmapper.insert(operatelog);
        return  result;

    }
}

管理事务

1. 添加依赖

在 pom.xml 中添加 mybatis-plus 和 aop 的依赖

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-aop</artifactid>
</dependency>
<dependency>
    <groupid>com.baomidou</groupid>
    <artifactid>mybatis-plus-boot-starter</artifactid>
    <version>3.5.0</version> <!-- 根据需要选择版本 -->
</dependency>
<dependency>
    <groupid>mysql</groupid>
    <artifactid>mysql-connector-java</artifactid>
    <scope>runtime</scope>
</dependency>

2. 配置 mybatis-plus

在 application.yml 中配置 mybatis-plus 和数据源:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.driver
  mybatis-plus:
    mapper-locations: classpath*:/mappers/**/*.xml

3. 创建事务切面

创建一个事务切面类:

import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.springframework.stereotype.component;
import org.springframework.transaction.annotation.transactional;

@aspect
@component
public class transactionaspect {

    @transactional
    @around("execution(* com.yourpackage.service..*(..))") // 指定需要事务的业务逻辑包
    public object managetransaction(proceedingjoinpoint joinpoint) throws throwable {
        object result;
        try {
            result = joinpoint.proceed(); // 执行目标方法
            return result;
        } catch (exception e) {
            throw e; // 抛出异常以触发回滚
        }
    }
}

4. 示例业务逻辑类

创建一个服务类,使用 mybatis-plus 进行数据库操作:

import com.baomidou.mybatisplus.extension.service.impl.serviceimpl;
import org.springframework.stereotype.service;

@service
public class userservice extends serviceimpl<usermapper, user> {

    public void createuser(user user) {
        this.save(user); // 调用 mybatis-plus 的 save 方法
    }
}

5. 用户实体和 mapper

  • 定义用户实体:
import com.baomidou.mybatisplus.annotation.tableid;
import com.baomidou.mybatisplus.annotation.tablename;

@tablename("users") // 数据库表名
public class user {
    @tableid
    private long id;
    private string name;

    // getters and setters
}
  • mapper 接口:
import com.baomidou.mybatisplus.core.mapper.basemapper;

public interface usermapper extends basemapper<user> {
    // 可以自定义额外的方法
}

6. 创建控制器

在控制器中调用 userservice 的 createuser 方法:

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.*;

@restcontroller
@requestmapping("/users")
public class usercontroller {

    @autowired
    private userservice userservice;

    @postmapping
    public string createuser(@requestbody user user) {
        userservice.createuser(user); // 调用 userservice 的 createuser 方法
        return "user created successfully"; // 返回成功消息
    }
}

7. 启动类

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;

@springbootapplication
public class application {
    public static void main(string[] args) {
        springapplication.run(application.class, args);
    }
}

心得

  • 通过以上步骤,你可以在 spring boot 项目中整合 aop 和 mybatis-plus,实现简单而有效的事务管理。
  • 这样,无论是在正常情况下提交事务,还是在出现异常时回滚事务,都能得到很好的支持。

为什么做事务,做事务有啥用

  • 事务确保一组操作要么全部成功,要么全部失败,从而保持数据的一致性和完整性。
  • 它们在处理银行转账、订单处理等场景时尤其重要,可以防止数据不一致、部分更新或系统故障导致的数据丢失。
  • 通过事务,确保即使在异常情况下,数据状态依然可靠。

那为什么要结合aop去做事务

  • 结合 aop(面向切面编程)可以将事务管理的逻辑与业务逻辑分离,提高代码的可维护性和可读性。
  • 通过 aop,可以在不修改业务代码的情况下,集中管理事务,简化代码结构,并实现事务的自动化管理,减少重复代码,提高开发效率。

权限控制

1. 添加依赖

在 pom.xml 中添加 aop 相关依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-aop</artifactid>
</dependency>

2. 创建权限注解

定义一个自定义注解 @requirespermission:

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@target(elementtype.method)
@retention(retentionpolicy.runtime)
public @interface requirespermission {
    string value();
}

3. 创建切面类

创建切面类,使用 @aspect 注解来定义切面,处理权限控制逻辑:

import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;

@component
@aspect
public class permissionaspect {

    @autowired
    private userservice userservice; // 获取用户服务

    @around("@annotation(requirespermission)") // 拦截使用 @requirespermission 注解的方法
    public object checkpermission(proceedingjoinpoint joinpoint, requirespermission requirespermission) throws throwable {
        string requiredpermission = requirespermission.value(); // 获取所需权限

        // 权限检查逻辑
        if (!haspermission(requiredpermission)) {
            throw new securityexception("permission denied: " + requiredpermission);
        }

        return joinpoint.proceed(); // 执行目标方法
    }

    private boolean haspermission(string permission) {
        user currentuser = userservice.getcurrentuser(); // 获取当前用户

        if (currentuser == null) {
            return false; // 用户未登录
        }

        return currentuser.getpermissions().contains(permission); // 检查权限
    }
}

在使用 aop 时,@requirespermission 注解是一个标记,它本身并不直接传递参数。spring aop 在拦截带有该注解的方法时,会自动创建该注解的实例,并将其作为参数传递给

checkpermission 方法。这是通过 aop 框架的代理机制实现的,而不是通过显式调用。具体来说,当被注解的方法被调用时,aop 会拦截这个调用并注入相应的注解信息。

permission 参数来源于 @requirespermission 注解的 value() 方法。在 checkpermission 方法中,当该方法拦截到一个使用 @requirespermission 注解的方法时,spring aop 会将该注解的实例作为第二个参数传递给 checkpermission 方法。因此,你可以通过调用 requirespermission.value() 来获取注解中定义的权限字符串。

4. 使用权限注解

在需要进行权限控制的方法上使用自定义注解

import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;

@restcontroller
public class mycontroller {

    @getmapping("/admin")
    @requirespermission("admin_access")
    public string adminaccess() {
        return "welcome, admin!";
    }
}

5. 配置 spring boot

确保 spring boot 应用程序能够扫描到切面和自定义注解。通常情况下,只需在主类中添加 @enableaspectjautoproxy 注解:

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.context.annotation.enableaspectjautoproxy;

@springbootapplication
@enableaspectjautoproxy
public class myapplication {
    public static void main(string[] args) {
        springapplication.run(myapplication.class, args);
    }
}

@enableaspectjautoproxy 注解的作用是启用 spring 的 aop(面向切面编程)支持,允许使用 aspectj 的代理机制来实现切面。具体来说,它有以下几个功能:

1.启用代理

它告诉 spring 创建代理对象,这些代理对象可以拦截方法调用并执行切面逻辑。

2.支持注解

当你在代码中使用注解(如 @around、@before 等)时,@enableaspectjautoproxy 会使这些注解生效,从而实现方法拦截和切面逻辑的执行。

3.简化配置

通过添加这个注解,开发者不需要额外的 xml 配置,只需通过注解来定义切面和增强,减少了配置的复杂性。

在主类中添加这个注解后,spring boot 应用会自动扫描到切面类并将其注册到应用上下文中,从而实现所需的 aop 功能。

aop的五种通知类型包括‌

  • 前置通知(@before)‌
  • 后置通知(@after)‌
  • 返回通知(@afterreturning)‌
  • 异常通知(@afterthrowing)‌
  • 环绕通知(@around)‌

每种通知类型都有其特定的用途和场景,可以根据实际需求选择使用。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com