亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot整合Aop全過(guò)程

 更新時(shí)間:2024年10月17日 17:06:23   作者:小疙瘩的編程之路  
AOP(面向切面編程)技術(shù)可以高效地解決日志記錄、事務(wù)管理、權(quán)限控制等問(wèn)題,日志記錄通過(guò)自定義注解和切面類(lèi),自動(dòng)記錄方法調(diào)用詳情,減少重復(fù)代碼,事務(wù)管理方面,通過(guò)AOP可以在不改變業(yè)務(wù)代碼的情況下,實(shí)現(xiàn)事務(wù)的自動(dòng)開(kāi)啟、提交和回滾,保證數(shù)據(jù)一致性

AOP 可以做什么?

  • 1. 日志記錄
  • 自動(dòng)記錄方法的調(diào)用、參數(shù)、返回值和異常等信息,減少了在每個(gè)方法中添加日志代碼的需要。
  • 2. 管理事務(wù)
  • 在方法執(zhí)行前后自動(dòng)處理事務(wù)的開(kāi)啟、提交和回滾,確保數(shù)據(jù)的一致性和完整性。
  • 3. 權(quán)限控制
  • 實(shí)現(xiàn)方法的訪問(wèn)控制,檢查用戶(hù)權(quán)限,確保只有授權(quán)用戶(hù)才能執(zhí)行特定操作。
  • 4. 性能監(jiān)控
  • 自動(dòng)收集方法的執(zhí)行時(shí)間、調(diào)用次數(shù)等性能指標(biāo),幫助開(kāi)發(fā)者進(jìn)行性能分析和優(yōu)化。
  • 5. 緩存管理
  • 實(shí)現(xiàn)方法結(jié)果的緩存,減少重復(fù)計(jì)算,提高系統(tǒng)性能。
  • 6. 異常處理
  • 統(tǒng)一處理方法執(zhí)行中的異常,簡(jiǎn)化異常捕獲和處理邏輯。
  • 7. 輸入驗(yàn)證
  • 在方法執(zhí)行前對(duì)輸入?yún)?shù)進(jìn)行驗(yàn)證,保證數(shù)據(jù)的有效性和完整性。
  • 8. 動(dòng)態(tài)代理
  • 創(chuàng)建代理對(duì)象,在不修改原有類(lèi)的情況下添加額外的行為。

應(yīng)用場(chǎng)景

  • Web開(kāi)發(fā):用于請(qǐng)求處理、事務(wù)管理、安全控制等。
  • 企業(yè)應(yīng)用:在服務(wù)層實(shí)現(xiàn)統(tǒng)一的日志和異常處理。
  • 微服務(wù):在服務(wù)之間進(jìn)行統(tǒng)一的監(jiān)控和熔斷處理。

日志記錄

1.準(zhǔn)備工作

首先需要導(dǎo)入AOP依賴(lài)

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>

然后需要?jiǎng)?chuàng)建日志記錄數(shù)據(jù)庫(kù)和實(shí)體類(lèi)還有在Mapper層實(shí)現(xiàn)插入數(shù)據(jù)方法

  • 實(shí)體類(lèi)
//操作日志實(shí)體類(lèi)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
    private Integer id; //主鍵ID
    private Integer operateUser; //操作人ID
    private LocalDateTime operateTime; //操作時(shí)間
    private String className; //操作類(lèi)名
    private String methodName; //操作方法名
    private String methodParams; //操作方法參數(shù)
    private String returnValue; //操作方法返回值
    private Long costTime; //操作耗時(shí)
}
  • Mapper接口
@Mapper
public interface OperateLogMapper {

    //插入日志數(shù)據(jù)
    @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.創(chuàng)建自定義注解和切面類(lèi)

因?yàn)槲覀円涗浀牟僮魅罩臼菍?duì)于數(shù)據(jù)的增,刪,改所以采用@annotation來(lái)指定要為連接點(diǎn)的方法。

而且在涉及到消耗時(shí)間的字段,所以需要采用@Around通知類(lèi)型

  • 自定義注解類(lèi)
@Retention(RetentionPolicy.RUNTIME)//運(yùn)行時(shí)有效
@Target(ElementType.METHOD)//作用在方法上
public @interface Log {
}

3.實(shí)現(xiàn)日志記錄(Around)

首先需要需要記錄的操作接口方法前加上@Log注解

接下來(lái)在切面類(lèi)中實(shí)現(xiàn)操作日志記錄:

@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,通過(guò)獲取并解析jwt令牌
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJwt((jwt));
        Integer operateUser =(Integer) claims.get("id");
        operateLog.setOperateUser(operateUser);
        //獲取操作時(shí)間
        operateLog.setOperateTime(LocalDateTime.now());
        //獲取操作類(lèi)名
        operateLog.setClassName(joinPoint.getTarget().getClass().getName());
        //獲取操作方法名
        operateLog.setMethodName(joinPoint.getSignature().getName());
        //獲取操作方法參數(shù)
        operateLog.setMethodParams(Arrays.toString(joinPoint.getArgs()));
        //獲取開(kāi)始時(shí)間
        long begin = System.currentTimeMillis();
        //獲取操作方法返回值
        Object result = joinPoint.proceed();
        String returnValue = JSONObject.toJSONString(result);
        operateLog.setReturnValue(returnValue.toString());
        //獲取操作結(jié)束時(shí)間
        long end = System.currentTimeMillis();
        //獲取操作耗時(shí)
        operateLog.setCostTime((end-begin));
        operateLogMapper.insert(operateLog);
        return  result;

    }
}

管理事務(wù)

1. 添加依賴(lài)

在 pom.xml 中添加 MyBatis-Plus 和 AOP 的依賴(lài)

<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> <!-- 根據(jù)需要選擇版本 -->
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

2. 配置 MyBatis-Plus

在 application.yml 中配置 MyBatis-Plus 和數(shù)據(jù)源:

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. 創(chuàng)建事務(wù)切面

創(chuàng)建一個(gè)事務(wù)切面類(lèi):

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..*(..))") // 指定需要事務(wù)的業(yè)務(wù)邏輯包
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        try {
            result = joinPoint.proceed(); // 執(zhí)行目標(biāo)方法
            return result;
        } catch (Exception e) {
            throw e; // 拋出異常以觸發(fā)回滾
        }
    }
}

4. 示例業(yè)務(wù)邏輯類(lèi)

創(chuàng)建一個(gè)服務(wù)類(lèi),使用 MyBatis-Plus 進(jìn)行數(shù)據(jù)庫(kù)操作:

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); // 調(diào)用 MyBatis-Plus 的 save 方法
    }
}

5. 用戶(hù)實(shí)體和 Mapper

  • 定義用戶(hù)實(shí)體:
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

@TableName("users") // 數(shù)據(jù)庫(kù)表名
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. 創(chuàng)建控制器

在控制器中調(diào)用 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); // 調(diào)用 UserService 的 createUser 方法
        return "User created successfully"; // 返回成功消息
    }
}

7. 啟動(dòng)類(lèi)

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);
    }
}

心得

  • 通過(guò)以上步驟,你可以在 Spring Boot 項(xiàng)目中整合 AOP 和 MyBatis-Plus,實(shí)現(xiàn)簡(jiǎn)單而有效的事務(wù)管理。
  • 這樣,無(wú)論是在正常情況下提交事務(wù),還是在出現(xiàn)異常時(shí)回滾事務(wù),都能得到很好的支持。

為什么做事務(wù),做事務(wù)有啥用

  • 事務(wù)確保一組操作要么全部成功,要么全部失敗,從而保持?jǐn)?shù)據(jù)的一致性和完整性。
  • 它們?cè)谔幚磴y行轉(zhuǎn)賬、訂單處理等場(chǎng)景時(shí)尤其重要,可以防止數(shù)據(jù)不一致、部分更新或系統(tǒng)故障導(dǎo)致的數(shù)據(jù)丟失。
  • 通過(guò)事務(wù),確保即使在異常情況下,數(shù)據(jù)狀態(tài)依然可靠。

那為什么要結(jié)合aop去做事務(wù)

  • 結(jié)合 AOP(面向切面編程)可以將事務(wù)管理的邏輯與業(yè)務(wù)邏輯分離,提高代碼的可維護(hù)性和可讀性。
  • 通過(guò) AOP,可以在不修改業(yè)務(wù)代碼的情況下,集中管理事務(wù),簡(jiǎn)化代碼結(jié)構(gòu),并實(shí)現(xiàn)事務(wù)的自動(dòng)化管理,減少重復(fù)代碼,提高開(kāi)發(fā)效率。

權(quán)限控制

1. 添加依賴(lài)

在 pom.xml 中添加 AOP 相關(guān)依賴(lài):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 創(chuàng)建權(quán)限注解

定義一個(gè)自定義注解 @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. 創(chuàng)建切面類(lèi)

創(chuàng)建切面類(lèi),使用 @Aspect 注解來(lái)定義切面,處理權(quán)限控制邏輯:

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; // 獲取用戶(hù)服務(wù)

    @Around("@annotation(requiresPermission)") // 攔截使用 @RequiresPermission 注解的方法
    public Object checkPermission(ProceedingJoinPoint joinPoint, RequiresPermission requiresPermission) throws Throwable {
        String requiredPermission = requiresPermission.value(); // 獲取所需權(quán)限

        // 權(quán)限檢查邏輯
        if (!hasPermission(requiredPermission)) {
            throw new SecurityException("Permission denied: " + requiredPermission);
        }

        return joinPoint.proceed(); // 執(zhí)行目標(biāo)方法
    }

    private boolean hasPermission(String permission) {
        User currentUser = userService.getCurrentUser(); // 獲取當(dāng)前用戶(hù)

        if (currentUser == null) {
            return false; // 用戶(hù)未登錄
        }

        return currentUser.getPermissions().contains(permission); // 檢查權(quán)限
    }
}

在使用 AOP 時(shí),@RequiresPermission 注解是一個(gè)標(biāo)記,它本身并不直接傳遞參數(shù)。Spring AOP 在攔截帶有該注解的方法時(shí),會(huì)自動(dòng)創(chuàng)建該注解的實(shí)例,并將其作為參數(shù)傳遞給

checkPermission 方法。這是通過(guò) AOP 框架的代理機(jī)制實(shí)現(xiàn)的,而不是通過(guò)顯式調(diào)用。具體來(lái)說(shuō),當(dāng)被注解的方法被調(diào)用時(shí),AOP 會(huì)攔截這個(gè)調(diào)用并注入相應(yīng)的注解信息。

permission 參數(shù)來(lái)源于 @RequiresPermission 注解的 value() 方法。在 checkPermission 方法中,當(dāng)該方法攔截到一個(gè)使用 @RequiresPermission 注解的方法時(shí),Spring AOP 會(huì)將該注解的實(shí)例作為第二個(gè)參數(shù)傳遞給 checkPermission 方法。因此,你可以通過(guò)調(diào)用 requiresPermission.value() 來(lái)獲取注解中定義的權(quán)限字符串。

4. 使用權(quán)限注解

在需要進(jìn)行權(quán)限控制的方法上使用自定義注解

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 應(yīng)用程序能夠掃描到切面和自定義注解。通常情況下,只需在主類(lèi)中添加 @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 的代理機(jī)制來(lái)實(shí)現(xiàn)切面。具體來(lái)說(shuō),它有以下幾個(gè)功能:

1.啟用代理

它告訴 Spring 創(chuàng)建代理對(duì)象,這些代理對(duì)象可以攔截方法調(diào)用并執(zhí)行切面邏輯。

2.支持注解

當(dāng)你在代碼中使用注解(如 @Around、@Before 等)時(shí),@EnableAspectJAutoProxy 會(huì)使這些注解生效,從而實(shí)現(xiàn)方法攔截和切面邏輯的執(zhí)行。

3.簡(jiǎn)化配置

通過(guò)添加這個(gè)注解,開(kāi)發(fā)者不需要額外的 XML 配置,只需通過(guò)注解來(lái)定義切面和增強(qiáng),減少了配置的復(fù)雜性。

在主類(lèi)中添加這個(gè)注解后,Spring Boot 應(yīng)用會(huì)自動(dòng)掃描到切面類(lèi)并將其注冊(cè)到應(yīng)用上下文中,從而實(shí)現(xiàn)所需的 AOP 功能。

AOP的五種通知類(lèi)型包括‌

  • 前置通知(@Before)‌
  • 后置通知(@After)‌
  • 返回通知(@AfterReturning)‌
  • 異常通知(@AfterThrowing)‌
  • 環(huán)繞通知(@Around)‌

每種通知類(lèi)型都有其特定的用途和場(chǎng)景,可以根據(jù)實(shí)際需求選擇使用。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot?+rabbitmq+redis實(shí)現(xiàn)秒殺示例

    springboot?+rabbitmq+redis實(shí)現(xiàn)秒殺示例

    本文主要介紹了springboot?+rabbitmq+redis實(shí)現(xiàn)秒殺示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java實(shí)現(xiàn)異步延遲隊(duì)列的方法詳解

    Java實(shí)現(xiàn)異步延遲隊(duì)列的方法詳解

    目前系統(tǒng)中有很多需要用到延時(shí)處理的功能,本文就為大家介紹了Java實(shí)現(xiàn)異步延遲隊(duì)列的方法,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-03-03
  • java中反射和注解的簡(jiǎn)單使用方法

    java中反射和注解的簡(jiǎn)單使用方法

    相信大家對(duì)注解和反射應(yīng)該并不陌生,在現(xiàn)在信息飛速發(fā)展的年代,各種優(yōu)秀的框架或許都離不開(kāi)注解的使用,這篇文章主要給大家介紹了關(guān)于java中反射和注解的簡(jiǎn)單使用方法,需要的朋友可以參考下
    2021-08-08
  • 淺談java監(jiān)聽(tīng)器的作用

    淺談java監(jiān)聽(tīng)器的作用

    這篇文章主要介紹了淺談java監(jiān)聽(tīng)器的作用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • Intellij IDEA 添加jar包的三種方式(小結(jié))

    Intellij IDEA 添加jar包的三種方式(小結(jié))

    這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • 詳解spring batch的使用和定時(shí)器Quart的使用

    詳解spring batch的使用和定時(shí)器Quart的使用

    spring Batch是一個(gè)基于Spring的企業(yè)級(jí)批處理框架,它通過(guò)配合定時(shí)器Quartz來(lái)輕易實(shí)現(xiàn)大批量的數(shù)據(jù)讀取或插入,并且全程自動(dòng)化,無(wú)需人員管理
    2017-08-08
  • java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢(xún)功能

    java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢(xún)功能

    這篇文章主要介紹了java mybatis框架實(shí)現(xiàn)多表關(guān)系查詢(xún),基于Maven框架的整體設(shè)計(jì) —— 一多一的關(guān)系,文中通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • mybatis-plus查詢(xún)?cè)创a詳解

    mybatis-plus查詢(xún)?cè)创a詳解

    這篇文章主要介紹了mybatis-plus查詢(xún)?cè)创a解讀,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • java 獲取當(dāng)前函數(shù)名的實(shí)現(xiàn)代碼

    java 獲取當(dāng)前函數(shù)名的實(shí)現(xiàn)代碼

    以下是對(duì)使用java獲取當(dāng)前函數(shù)名的實(shí)現(xiàn)代碼進(jìn)行了介紹。需要的朋友可以過(guò)來(lái)參考下
    2013-08-08
  • SpringCloud如何使用Eureka實(shí)現(xiàn)服務(wù)之間的傳遞數(shù)據(jù)

    SpringCloud如何使用Eureka實(shí)現(xiàn)服務(wù)之間的傳遞數(shù)據(jù)

    這篇文章主要介紹了SpringCloud使用Eureka實(shí)現(xiàn)服務(wù)之間的傳遞數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06

最新評(píng)論