SpringAOP 常见应用场景

文章目录

  • SpringAOP
    • 1 概念
    • 2 常见应用场景
    • 3 AOP的几种通知类型分别有什么常见的应用场景
    • 4 AOP实现 性能监控
      • 4.1 首先,定义一个切面类,用于实现性能监控逻辑:
      • 4.2 定义自定义注解
      • 4.3 注解修饰监控的方法
    • 5 AOP实现 API调用统计
      • 5.1 定义切面类,用于实现API调用统计逻辑
    • 6 AOP实现 缓存
      • 6.1 定义缓存注解
      • 6.2 实现缓存切面
      • 6.3 应用缓存注解
    • 7 AOP实现自定义滑动窗口限流
      • 7.1 定义缓存注解
      • 7.2 滑动窗口限流器
      • 7.3 AOP切面实现
      • 7.4 应用限流注解

SpringAOP

1 概念

Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个模块,它提供了面向切面编程的支持。AOP允许开发者将横切关注点(如日志记录、权限检查、性能监控等)从业务逻辑中分离出来,通过这种方式,可以使代码更加模块化,易于维护和管理。

核心概念:

  1. 切面(Aspect):切面是跨越多个对象的行为或关注点的模块化。例如,事务管理就是企业级应用中的一个关注点,它需要跨越多个对象进行管理。
  2. 连接点(Joinpoint):在程序执行过程中某个特定的点,比如方法的调用或者异常的抛出。在Spring AOP中,连接点总是方法的执行。
  3. 切入点(Pointcut):定义了切面应该在哪些连接点上执行的规则。可以通过表达式来匹配哪些方法需要被切面所影响。
  4. 通知(Advice):在切面识别到某个连接点后要执行的动作。有多种类型的通知,包括前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。
  5. 织入(Weaving):将切面应用到目标对象上,从而创建代理对象的过程。这个过程可以在编译时、类加载时或运行时完成。Spring AOP采用的是运行时织入。

2 常见应用场景

Spring AOP(面向切面编程)的常见应用场景广泛,主要用于将那些遍布于应用各处的横切关注点(Cross-cutting Concerns)进行集中管理和代码复用。以下是一些典型的Spring AOP应用场景:

  1. 日志记录(Logging):在方法调用前后记录日志信息,用于跟踪方法执行情况、性能监控或调试。
  2. 权限检查(Security/Authorization):在方法执行前验证用户是否有权限执行该操作,比如角色检查或资源访问控制。
  3. 事务管理(Transaction Management):自动管理数据库事务的开启、提交或回滚,保证数据的一致性。
  4. 异常处理(Exception Handling):集中处理特定类型的异常,比如记录异常信息或执行特定的恢复操作。
  5. 性能监控(Performance Monitoring):监控方法执行时间,帮助识别和优化性能瓶颈。
  6. 缓存(Caching):自动缓存方法的返回结果,减少不必要的数据库查询或其他耗时操作。
  7. 参数校验和转换(Parameter Validation and Conversion):在方法调用前对参数进行校验或转换,确保符合业务逻辑要求。
  8. API调用统计(API Call Tracking):记录API的调用次数、频率等,用于分析和优化。
  9. SLF4J、Logback、Log4j等日志框架集成:通过AOP可以在不修改业务代码的情况下,灵活地切换或增强日志框架的功能。
  10. 自定义注解的处理:使用AOP拦截带有特定自定义注解的方法,实现特定逻辑,如标记某个方法需要审计、限流等。

这些场景体现了AOP的核心价值,即通过将横切关注点与核心业务逻辑分离,提高代码的可维护性和可读性,同时降低了模块间的耦合度。

aop的几种通知类型分别有什么常见的应用场景

3 AOP的几种通知类型分别有什么常见的应用场景

AOP(面向切面编程)的通知类型是实现切面功能的关键组成部分,每种类型对应着不同的应用场景。以下是Spring AOP五种通知类型及其常见应用场景:

  1. 前置通知(Before advice)
    • 应用场景:在目标方法执行前执行某些操作,如记录方法调用日志、验证权限、参数校验等。例如,在方法开始前记录操作日志,或检查用户是否已经登录。
  2. 后置通知(After returning advice)
    • 应用场景:在目标方法正常执行完毕后执行,通常用于清理资源、记录方法返回值或日志。例如,记录方法执行成功的信息或操作结果,以及进行一些资源清理工作。
  3. 异常通知(After throwing advice)
    • 应用场景:在目标方法抛出异常后执行,用于异常处理,如记录异常日志、发送错误报告、执行异常补偿措施等。例如,捕获并记录业务异常,或者向管理员发送异常报警邮件。
  4. 最终通知(After (finally) advice)
    • 应用场景:无论目标方法是否正常结束(包括正常返回或抛出异常),都会执行的代码块,常用于释放资源、关闭文件或数据库连接等。例如,确保数据库连接关闭,或执行必要的清理操作。
  5. 环绕通知(Around advice)
    • 应用场景:最灵活的通知类型,可以在方法调用前后执行自定义操作,甚至可以选择是否执行目标方法,适用于需要完全控制方法调用流程的场景,如性能监控、事务管理、日志记录与时间度量等。例如,环绕一个方法调用,测量其执行时间的同时控制事务的开启与提交或回滚。

通过这些通知类型,AOP能够有效地将横切关注点(如日志、安全、事务等)从核心业务逻辑中分离出来,提高代码的模块化程度和可维护性。

4 AOP实现 性能监控

在Spring AOP中,实现性能监控的一种常见方法是通过环绕通知(Around Advice)来测量方法的执行时间。环绕通知可以在方法调用前后执行自定义逻辑,非常适合用来监控性能。下面是一个简单的例子,展示如何使用Spring AOP来监控方法的执行时间:

4.1 首先,定义一个切面类,用于实现性能监控逻辑:

这里,我们定义了一个带有@Around注解的环绕通知方法,它会拦截所有标有自定义注解@PerformanceMonitor的方法。PerformanceMonitor是我们自定义的一个注解,用于标记需要监控的方法,并可配置额外的监控阈值。

package com.example.demo.aspect;import com.example.demo.annotation.PerformanceMonitor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;/*** PerformanceMonitorAspect : 性能监控切面** @author zyw* @create 2024-06-06  13:18*/@Aspect
@Component
@Slf4j
public class PerformanceMonitorAspect {/*** 切面方法 Around环绕通知方法** @param joinPoint* @param performanceMonitor* @return* @throws Throwable*/@Around("@annotation(performanceMonitor)")public Object monitorPerformance(ProceedingJoinPoint joinPoint, PerformanceMonitor performanceMonitor) throws Throwable {long start = System.currentTimeMillis();try {// 执行方法Object result = joinPoint.proceed();return result;} finally {long elapsedTime = System.currentTimeMillis() - start;// 记录方法执行时间log.info("方法: {} 执行了 {} ms", joinPoint.getSignature().getName(), elapsedTime);if (performanceMonitor.logIfGreaterThan() > 0 && elapsedTime > performanceMonitor.logIfGreaterThan()) {log.warn("性能警告:方法 {} 执行时间超过{}ms.", joinPoint.getSignature().getName(), performanceMonitor.logIfGreaterThan());}}}}

4.2 定义自定义注解

package com.example.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;/*** PerformanceMonitor : 性能监控注解** @author zyw* @create 2024-06-06  13:19*/@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PerformanceMonitor {// 默认不设置警告阈值long logIfGreaterThan() default 0;
}

4.3 注解修饰监控的方法

这样,每次调用performSomeTask方法时,都会自动记录其执行时间,并在超过设定阈值时输出警告信息,帮助识别和优化性能瓶颈。

import com.example.demo.annotation.PerformanceMonitor;    @Override@PerformanceMonitor(logIfGreaterThan = 100) // 如果执行时间超过100ms,则记录警告日志public void performSomeTask(Integer num) {if (num == 1){try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}

在这里插入图片描述

5 AOP实现 API调用统计

5.1 定义切面类,用于实现API调用统计逻辑

在这个切面中,我们使用了ConcurrentHashMapAtomicLong来安全地记录每个API方法的调用次数,确保在高并发环境下也能正确统计。

package com.example.demo.aspect;import com.example.demo.annotation.PerformanceMonitor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;/*** PerformanceMonitorAspect : 性能监控切面** @author zyw* @create 2024-06-06  13:18*/@Aspect
@Component
@Slf4j
public class PerformanceMonitorAspect {private ConcurrentHashMap<String, AtomicLong> callCountMap = new ConcurrentHashMap<>();/*** 切面方法 Around环绕通知方法** @param joinPoint* @param performanceMonitor* @return* @throws Throwable*/@Around("@annotation(performanceMonitor)")public Object monitorPerformance(ProceedingJoinPoint joinPoint, PerformanceMonitor performanceMonitor) throws Throwable {long start = System.currentTimeMillis();try {String methodName = joinPoint.getSignature().getName();long count = callCountMap.computeIfAbsent(methodName, k -> new AtomicLong()).incrementAndGet();// 执行方法Object result = joinPoint.proceed();// 可以在这里添加更复杂的统计逻辑,比如记录到数据库、发送到监控系统等// 这里简单打印调用次数log.info("方法: {} 调用次数: {}", methodName, count);return result;} finally {long elapsedTime = System.currentTimeMillis() - start;// 记录方法执行时间log.info("方法: {} 执行了 {} ms", joinPoint.getSignature().getName(), elapsedTime);if (performanceMonitor.logIfGreaterThan() > 0 && elapsedTime > performanceMonitor.logIfGreaterThan()) {log.warn("性能警告:方法 {} 执行时间超过{}ms.", joinPoint.getSignature().getName(), performanceMonitor.logIfGreaterThan());}}}}

现在,每当/api/data这个API被调用时,ApiCallStatsAspect就会自动增加调用计数,并打印调用次数。你可以根据需要进一步扩展此逻辑,比如定期将统计数据发送到监控系统、数据库等,以便进行更深入的分析和优化。

在这里插入图片描述

6 AOP实现 缓存

6.1 定义缓存注解

首先,你需要定义一个自定义注解,用于标记需要缓存的方法。

package com.example.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Cacheable : AOP缓存注解** @author zyw* @create 2024-06-06  16:16*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {// 缓存的键,可以根据方法参数生成String key();// 缓存过期时间,默认永不过期long ttl() default 0;
}

6.2 实现缓存切面

接下来,创建一个切面来拦截带有@Cacheable注解的方法,并实现缓存逻辑。

package com.example.demo.aspect;import com.example.demo.annotation.Cacheable;
import com.example.demo.uitls.RedisUtil;
import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;/*** CacheAspect :** @author zyw* @create 2024-06-06  16:17*/@Aspect
@Component
public class CacheAspect {@Resourceprivate RedisUtil redisUtil;@Around("@annotation(cacheable)")public Object cacheable(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {String cacheKey = generateCacheKey(joinPoint, cacheable.key());Object result = redisUtil.get(cacheKey);if (result == null) {// 缓存中没有,执行方法并缓存结果result = joinPoint.proceed();if (cacheable.ttl() > 0) {redisUtil.set(cacheKey, result, cacheable.ttl());} else {redisUtil.set(cacheKey, result);}}return result;}private String generateCacheKey(ProceedingJoinPoint joinPoint, String keyExpression) {// 根据方法名、参数等生成缓存键,这里简化处理,实际可能需要更复杂的逻辑StringBuilder keyBuilder = new StringBuilder(keyExpression);Object[] args = joinPoint.getArgs();for (Object arg : args) {keyBuilder.append(":").append(arg.toString());}return keyBuilder.toString();}}

6.3 应用缓存注解

最后,在你想要缓存其返回结果的方法上使用@Cacheable注解。

package com.example.demo.service.impl;import com.example.demo.annotation.Cacheable;
import com.example.demo.annotation.PerformanceMonitor;
import com.example.demo.entity.SysUser;
import com.example.demo.service.SysUserService;
import com.example.demo.service.TestService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.List;/*** TestServiceImpl :** @author zyw* @create 2023-12-18  15:15*/
@Service
public class TestServiceImpl implements TestService {@Resourceprivate SysUserService sysUserService;@Override@Cacheable(key = "UserListCacheKey", ttl = 60) // 缓存1分钟public List<SysUser> getUserList() {return sysUserService.list();}
}

可用于结果固定,频繁需要获取的数据集,首次查询时走数据库,后缓存有效期内再次获取都从redis中取

在这里插入图片描述
在这里插入图片描述

7 AOP实现自定义滑动窗口限流

要实现AOP结合滑动窗口算法来实现自定义规则的限流,我们可以在原有的基础上进一步扩展,以支持更灵活的配置和更复杂的规则。以下是一个基于Spring AOP和滑动窗口算法的简单示例,包括自定义注解来设置限流规则,以及如何在切面中应用这些规则。

7.1 定义缓存注解

首先,定义一个自定义注解来标记需要限流的方法,并允许传入限流的具体规则

package com.example.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** SlidingWindowRateLimiter : 滑动窗口限流注解** @author zyw* @create 2024-06-06  17:20*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WindowRateLimit {// 允许的最大请求数int limit();// 窗口时间长度,单位毫秒long timeWindowMilliseconds();
}

7.2 滑动窗口限流器

接下来,实现滑动窗口限流器,这里简化处理,直接使用内存实现,实际应用中可能需要基于Redis等持久化存储以适应分布式场景:

package com.example.demo.uitls;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.LinkedList;/*** SlidingWindowRateLimiter : 滑动窗口限流算法** @author zyw* @create 2024-06-07  15:16*/@Data
@AllArgsConstructor
@NoArgsConstructor
public class SlidingWindowRateLimiter implements Serializable {/*** 请求队列*/private LinkedList<Long> requests = new LinkedList<>();/*** 最大请求数*/private int maxRequests;/*** 窗口大小*/private long windowSizeInMilliseconds;public SlidingWindowRateLimiter(int maxRequests, long windowSizeInMilliseconds) {this.maxRequests = maxRequests;this.windowSizeInMilliseconds = windowSizeInMilliseconds;}/*** 判断是否允许请求* @return*/public synchronized boolean allowRequest() {// 获取当前时间long currentTime = System.currentTimeMillis();// 清除窗口之外的旧请求while (!requests.isEmpty() && currentTime - requests.peekFirst() > windowSizeInMilliseconds) {requests.removeFirst();}// 如果当前窗口请求未达到上限,则允许请求并记录if (requests.size() < maxRequests) {requests.addLast(currentTime);return true;} else {// 达到限流阈值,拒绝请求return false;}}
}

7.3 AOP切面实现

最后,创建AOP切面来应用限流逻辑:

package com.example.demo.aspect;import com.example.demo.annotation.WindowRateLimit;
import com.example.demo.config.redis.RedisKeyEnum;
import com.example.demo.uitls.RedisUtil;
import com.example.demo.uitls.SlidingWindowRateLimiter;
import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;/*** RateLimiterAspect :** @author zyw* @create 2024-06-06  17:21*/@Aspect
@Component
public class SlidingWindowRateLimiterAspect {@Resourceprivate RedisUtil redisUtil;@Around("@annotation(rateLimit)")public Object applyRateLimit(ProceedingJoinPoint joinPoint, WindowRateLimit rateLimit) throws Throwable {// 获取调用的方法名String methodName = joinPoint.getSignature().getName();// 获取方法对应的缓存滑动窗口限流器KEYString key = RedisKeyEnum.WINDOW_CURRENT_LIMITING.getKey() + methodName;// 从缓存中获取滑动窗口限流器SlidingWindowRateLimiter rateLimiter = redisUtil.getCacheObject(key);// 如果滑动窗口限流器不存在,则创建一个新限流器if (rateLimiter == null) {rateLimiter = new SlidingWindowRateLimiter(rateLimit.limit(), rateLimit.timeWindowMilliseconds());}// 如果滑动窗口限流器存在,则判断是否允许请求if (!rateLimiter.allowRequest()) {throw new RuntimeException("Too many requests, please try again later.");}// 如果允许请求,则更新滑动窗口限流器redisUtil.setCacheObject(key, rateLimiter);// 允许执行方法return joinPoint.proceed(); }}

7.4 应用限流注解

在需要做限流的方法上加上注解,在注解参数中设定 允许的最大请求数窗口时间长度(单位毫秒)

package com.example.demo.service.impl;import com.example.demo.annotation.WindowRateLimit;
import com.example.demo.service.TestService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;/*** TestServiceImpl :** @author zyw* @create 2023-12-18  15:15*/
@Service
public class TestServiceImpl implements TestService {@Override@WindowRateLimit(limit = 5, timeWindowMilliseconds = 60L*1000) // 每最多允许5次请求public String getContent() {return "Hello Word";}
}

首次请求时,初始化滑动窗口限流器,记录第一次请求的时间戳

在这里插入图片描述

窗口期内,记录了五次请求的时间戳后,已达到我们在注解中设置的窗口期最大请求量

在这里插入图片描述

此时接口限流

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/850307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度图的方法实现加雾,Synscapes数据集以及D455相机拍摄为例

前言 在次之前&#xff0c;我们已经做了图像加雾的一些研究&#xff0c;这里我们将从深度图的方法实现加雾展开细讲 图像加雾算法的研究与应用_图像加雾 算法-CSDN博客 接下来将要介绍如何使用深度图像生成雾效图像的方法。利用Synscapes数据集&#xff0c;通过读取EXR格式的…

【实盘】第二十期:2024-06月~第一周

一、每周净值 01 CTA投资组合 CTA多品种全覆盖全天候策略2024年2月至2024年5月底实盘总收益12.753%&#xff0c;当前浮动净值为1.1407&#xff0c;当前平仓净值为1.12753。 月度最大本金回撤0.3%(资金曲线为平仓盈亏,总体回撤应加入浮动持仓的盈亏总体计算,实际当前净值见棕色…

各种空气能热泵安装图

空气能热泵安装图 循环式空气能热泵安装图 直热循环式空气能热泵安装图 泳池空气能热泵安装图 循环式水源热泵热安装系统原理图 直热循环式水源热泵安装系统图 空气水源热泵安装图

flutter as连接网易模拟器

网易模拟器下载 Mac 使用MuMu模拟器调试 Flutter开发 Android Studio 安装第三方模拟器—网易MuMu Mac 安卓Studio使用外部模拟器 Mac电脑&#xff1a;Android Studio 连接 MUMU 网易模拟器 Mac 上 Android Studio 链接网易 MuMu 模拟器调试 在 .zshrc 中设置 adb 二进制文…

重构某测试站点

一、计算校验值 校验值结果&#xff1a; 文件名称&#xff1a;培训用centos.rar&#xff0c;文件大小&#xff1a;1,335,759,953&#xff0c;MD5&#xff1a;534EC38CDA7DA2196C84AC8F6092514B&#xff0c;SHA1&#xff1a;FD35D86A27A007AE10872980C48653A110DF6067&#xf…

EverWeb 强大的零基础Mac网页设计制作软件

搜索Mac软件之家下载EverWeb 强大的零基础Mac网页设计制作软件 EverWeb 4.2是非专业网页设计师的绝佳网页制作工具&#xff0c;无需编码即可创建美观、响应迅速的网站。只需拖放自己的图像、文本和其他任何html元素到网页布局的任何位置。 EverWeb的功能特性&#xff1a; 下…

C++模板编程—学习C++类库的编程基础

课程总目录 文章目录 一、详解函数模板二、类模板三、类模板实践&#xff1a;实现向量容器vector四、理解容器空间配置器allocator的重要性 一、详解函数模板 模板的意义&#xff1a;对类型也可以进行参数化了 // 也可以用template<class T>&#xff0c;但class容易和类…

适用于 Windows 的 8 大数据恢复软件

数据恢复软件可帮助您恢复因意外删除或由于某些技术故障&#xff08;如硬盘损坏等&#xff09;而丢失的数据。这些工具可帮助您从硬盘驱动器 (HDD) 中高效地恢复丢失的数据&#xff0c;因为这些工具不支持从 SSD 恢复数据。重要的是要了解&#xff0c;您删除的数据不会被系统永…

NodeJs实现脚本:将xlxs文件输出到json文件中

文章目录 前期工作和依赖笔记功能代码输出 最近有一个功能&#xff0c;将json文件里的内容抽取到一个xlxs中&#xff0c;然后维护xlxs文件。当要更新json文件时&#xff0c;就更新xlxs的内容并把它传回json中。这个脚本主要使用NodeJS写。 以下是完成此功能时做的一些笔记。 …

【面试八股总结】内存页面置换算法

参考资料&#xff1a;小林coding、阿秀 缺页中断 在 CPU 里访问一条 Load M 指令&#xff0c;然后 CPU 会去找 M 所对应的页表项。如果该页表项的状态位是「有效的」&#xff0c;那 CPU 就可以直接去访问物理内存了&#xff0c;如果状态位是「无效的」&#xff0c;则 CPU 则会…

stanfordcorenlp+python做中文nlp任务,得到的结果中全是空字符串,而不是中文字符串

问题描述 代码&#xff1a; from stanfordcorenlp import StanfordCoreNLP import logging#中文中的应用&#xff0c;一定记得下载中文jar包&#xff0c;并标志lang‘zh’ nlp_zh StanfordCoreNLP(rD:\stanford-corenlp-full-2016-10-31, port8094, langzh,quietFalse,logg…

GiantPandaCV | 提升分类模型acc(一):BatchSizeLARS

本文来源公众号“GiantPandaCV”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;提升分类模型acc(一)&#xff1a;BatchSize&LARS 在使用大的bs训练情况下&#xff0c;会对精度有一定程度的损失&#xff0c;本文探讨了训练的b…

Java Web学习笔记24——Vue项目开发流程

import是引入文件。 export是将对象导出为模块。 new Vue({ router, router: h > h(App) }).$mount(#app) App.vue: vue的组成文件以.vue结尾&#xff0c;每个组件由三个部分组成&#xff1a;<template>、<script>、<style>。 <template><d…

i.MX8MP平台开发分享(RDC软件配置篇)

Uboot中已经将RDC的配置写入到了OCRAM中&#xff0c;NXP在ATF中预设了SIP服务&#xff0c;SIP服务下有厂商自定义的smc命令ID。例如下面的DDR、GPC、SRC和HAB的smc回调函数。 在SRC中断处理函数中&#xff0c;对于SRC_M4_START指令&#xff0c;先读取OCRAM中的配置&#xff0c;…

第一个小爬虫_爬取 股票数据

前言 爬取 雪球网的股票数据 [环境使用]&#xff1a;python 3.12 解释器pycharm 编辑器 【模块使用】&#xff1a;import requests -->数据请求模块 要安装 命令 pip install requestsimport csv -->将数据保存到CSV表格中import pandas -->也可以将数据保…

vue3+vite插件开发

插件开发目的:由于我司使用的前端技术栈为vue3tsvite2.Xaxios,在前端代码框架设计初期,做了把axios挂载到proxy对象上的操作,具体可见我的另一篇文章vue3TS自动化封装全局api_ts 封装腾讯位置api-CSDN博客 现在可以实现vue2的类似this.$api.xxx去调用接口,但是vue2源码使用的是…

flutter日历范围选择器

1.传入日期跨度&#xff0c;选择上架日期时&#xff0c;自动显示下架日期 2.手动选择上架日期和下架日期(图中下架日期自动填了只需CalendarDateRangePicker在initState方法中使用_startDate widget.initialStartDate; _endDate widget.initialEndDate;&#xff0c;而不直接…

【python】OpenCV—Blob Detection(11)

学习来自OpenCV基础&#xff08;10&#xff09;使用OpenCV进行Blob检测 文章目录 1、cv2.SimpleBlobDetector_create 中文文档2、默认 parameters3、配置 parameters附录——cv2.drawKeypoints 1、cv2.SimpleBlobDetector_create 中文文档 cv2.SimpleBlobDetector_create 是 O…

端午搞个零花钱,轻松赚取创业的第一桶金!2024最受欢迎的创业项目,2024新的创业机会

好好的端午节&#xff0c; 净给我添堵&#xff01; 本来我打算在端午节愉快的玩耍&#xff0c; 结果一大早起床却看到舍友在给一堆设备充电&#xff0c; 然后装的整整齐齐&#xff0c; 满满一书包。 我好奇他小子这是要干嘛&#xff1f; 不会是打算今天回去给亲朋好友准备…

【动态规划-BM79 打家劫舍(二)】

题目 BM79 打家劫舍(二) 描述 你是一个经验丰富的小偷&#xff0c;准备偷沿湖的一排房间&#xff0c;每个房间都存有一定的现金&#xff0c;为了防止被发现&#xff0c;你不能偷相邻的两家&#xff0c;即&#xff0c;如果偷了第一家&#xff0c;就不能再偷第二家&#xff0c;如…