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允许开发者将横切关注点(如日志记录、权限检查、性能监控等)从业务逻辑中分离出来,通过这种方式,可以使代码更加模块化,易于维护和管理。
核心概念:
- 切面(Aspect):切面是跨越多个对象的行为或关注点的模块化。例如,事务管理就是企业级应用中的一个关注点,它需要跨越多个对象进行管理。
- 连接点(Joinpoint):在程序执行过程中某个特定的点,比如方法的调用或者异常的抛出。在Spring AOP中,连接点总是方法的执行。
- 切入点(Pointcut):定义了切面应该在哪些连接点上执行的规则。可以通过表达式来匹配哪些方法需要被切面所影响。
- 通知(Advice):在切面识别到某个连接点后要执行的动作。有多种类型的通知,包括前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。
- 织入(Weaving):将切面应用到目标对象上,从而创建代理对象的过程。这个过程可以在编译时、类加载时或运行时完成。Spring AOP采用的是运行时织入。
2 常见应用场景
Spring AOP(面向切面编程)的常见应用场景广泛,主要用于将那些遍布于应用各处的横切关注点(Cross-cutting Concerns)进行集中管理和代码复用。以下是一些典型的Spring AOP应用场景:
- 日志记录(Logging):在方法调用前后记录日志信息,用于跟踪方法执行情况、性能监控或调试。
- 权限检查(Security/Authorization):在方法执行前验证用户是否有权限执行该操作,比如角色检查或资源访问控制。
- 事务管理(Transaction Management):自动管理数据库事务的开启、提交或回滚,保证数据的一致性。
- 异常处理(Exception Handling):集中处理特定类型的异常,比如记录异常信息或执行特定的恢复操作。
- 性能监控(Performance Monitoring):监控方法执行时间,帮助识别和优化性能瓶颈。
- 缓存(Caching):自动缓存方法的返回结果,减少不必要的数据库查询或其他耗时操作。
- 参数校验和转换(Parameter Validation and Conversion):在方法调用前对参数进行校验或转换,确保符合业务逻辑要求。
- API调用统计(API Call Tracking):记录API的调用次数、频率等,用于分析和优化。
- SLF4J、Logback、Log4j等日志框架集成:通过AOP可以在不修改业务代码的情况下,灵活地切换或增强日志框架的功能。
- 自定义注解的处理:使用AOP拦截带有特定自定义注解的方法,实现特定逻辑,如标记某个方法需要审计、限流等。
这些场景体现了AOP的核心价值,即通过将横切关注点与核心业务逻辑分离,提高代码的可维护性和可读性,同时降低了模块间的耦合度。
aop的几种通知类型分别有什么常见的应用场景
3 AOP的几种通知类型分别有什么常见的应用场景
AOP(面向切面编程)的通知类型是实现切面功能的关键组成部分,每种类型对应着不同的应用场景。以下是Spring AOP五种通知类型及其常见应用场景:
- 前置通知(Before advice)
- 应用场景:在目标方法执行前执行某些操作,如记录方法调用日志、验证权限、参数校验等。例如,在方法开始前记录操作日志,或检查用户是否已经登录。
- 后置通知(After returning advice)
- 应用场景:在目标方法正常执行完毕后执行,通常用于清理资源、记录方法返回值或日志。例如,记录方法执行成功的信息或操作结果,以及进行一些资源清理工作。
- 异常通知(After throwing advice)
- 应用场景:在目标方法抛出异常后执行,用于异常处理,如记录异常日志、发送错误报告、执行异常补偿措施等。例如,捕获并记录业务异常,或者向管理员发送异常报警邮件。
- 最终通知(After (finally) advice)
- 应用场景:无论目标方法是否正常结束(包括正常返回或抛出异常),都会执行的代码块,常用于释放资源、关闭文件或数据库连接等。例如,确保数据库连接关闭,或执行必要的清理操作。
- 环绕通知(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调用统计逻辑
在这个切面中,我们使用了ConcurrentHashMap和AtomicLong来安全地记录每个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";}
}
首次请求时,初始化滑动窗口限流器,记录第一次请求的时间戳

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

此时接口限流

相关文章:
SpringAOP 常见应用场景
文章目录 SpringAOP1 概念2 常见应用场景3 AOP的几种通知类型分别有什么常见的应用场景4 AOP实现 性能监控4.1 首先,定义一个切面类,用于实现性能监控逻辑:4.2 定义自定义注解4.3 注解修饰监控的方法 5 AOP实现 API调用统计5.1 定义切面类&am…...
html+css示例
HTML HTML(超文本标记语言)和CSS(层叠样式表)是构建和设计网页的两种主要技术。HTML用于创建网页的结构和内容,而CSS用于控制其外观和布局。 HTML基础 HTML使用标签来标记网页中的不同部分。每个标签通常有一个开始…...
Day51 动态规划part10+Day52 动态规划part11
LC121买卖股票的最佳时机(未掌握) 暴力:双层循环寻找最优间距,每一次都确定一个起点,遍历剩余节点当作终点 贪心:取最左最小值,不断遍历那么得到的差值最最大值就是最大利润。 动态规划 dp数组…...
Wireshark自定义Lua插件
背景: 常见的抓包工具有tcpdump和wireshark,二者可基于网卡进行抓包:tcpdump用于Linux环境抓包,而wireshark用于windows环境。抓包后需借助包分析工具对数据进行解析,将不可读的二进制数转换为可读的数据结构。 wires…...
商城项目【尚品汇】07分布式锁-2 Redisson篇
文章目录 1 Redisson功能介绍2 Redisson在Springboot中快速入门(代码)2.1 导入依赖2.2 Redisson配置2.3 将自定义锁setnx换成Redisson实现(可重入锁) 3 可重入锁原理3.1 自定义分布式锁setnx为什么不可以重入3.2 redisson为什么可…...
Adobe Illustrator 矢量图设计软件下载安装,Illustrator 轻松创建各种矢量图形
Adobe Illustrator,它不仅仅是一个简单的图形编辑工具,更是一个拥有丰富功能和强大性能的设计利器。 在这款软件中,用户可以通过各种精心设计的工具,轻松创建和编辑基于矢量路径的图形文件。这些矢量图形不仅具有高度的可编辑性&a…...
Nvidia/算能 +FPGA+AI大算力边缘计算盒子:中国舰船研究院
中国舰船研究院又称中国船舶重工集团公司第七研究院,隶属于中国船舶重工集团公司,是专门从事舰船研究、设计、开发的科学技术研究机构,是中国船舶重工集团公司的军品技术研究中心、科技开发中心;主要从事舰船武器装备发展战略研究…...
双网卡配置IP和路由总结
1.在网络适配器属性IPv4中设置默认网关(记网关地址为A),将会在本地路由表中新增一条记录: 网络号子网掩码网关地址0.0.0.00.0.0.0A 2.如果有两个网卡(假设一个连接内网,一个连接互联网)&#…...
【纯血鸿蒙】——自适应布局如何实现?
界面级一多能力有 2 类: 自适应布局: 略微调整界面结构 响应式布局:比较大的界面调整 本文章先主要讲解自适应布局,响应式布局再后面文章再细讲。话不多说,开始了。 自适应布局 针对常见的开发场景,方舟开发框架提…...
Qt5学习笔记(一):Qt Widgets Application项目初探
笔者长期使用MFC开发Windows GUI软件。随着软件向Linux平台迁移的趋势越发明朗,GUI程序的跨平台需求也越来越多。因此笔者计划重新抓一下Qt来实现跨平台GUI程序的实现。 0x01. 看看Qt Widgets Application项目结构 打开Qt5,点击“ New”按钮新建项目。…...
Linux网络编程:数据链路层协议
目录 前言: 1.以太网 1.1.以太网帧格式 1.2.MTU(最大传输单元) 1.2.1.IP协议和MTU 1.2.2.UDP协议和MTU 1.2.3.TCP协议和MTU 2.ARP协议(地址解析协议) 2.1.ARP在局域网通信的角色 2.2.ARP报文格式 2.3.ARP报文…...
企业估值的三种方法
估值模型三剑客—DCF、P/E、EV /EBITDA 三种主要估值模型的优缺点: DCF 优点:通过对自由现金流的折现计算,反映了公司内在价值的本质,是最重要与最合理的估值方法。 缺点:未来自由现金流的估计不准确,受折现率影响…...
比亚迪正式签约国际皮划艇联合会和中国皮划艇协会,助推龙舟入奥新阶段
6月5日,比亚迪与国际皮划艇联合会、中国皮划艇协会在深圳共同签署合作协议,国际皮划艇联合会主席托马斯科涅茨科,国际皮划艇联合会秘书长理查德派蒂特,中国皮划艇协会秘书长张茵,比亚迪品牌及公关处总经理李云飞&#…...
宏集Panorama SCADA:个性化定制,满足多元角色需求
前言 在考虑不同人员在企业中的职能和职责时,他们对于SCADA系统的需求可能因其角色和工作职责的不同而有所差异。在SCADA系统的设计和实施过程中,必须充分考虑和解决这种差异性。 为了满足不同人员的需求, 宏集Panorama SCADA平台具备灵活的功能和定制…...
聪明人社交的基本顺序:千万别搞反了,越早明白越好
聪明人社交的基本顺序:千万别搞反了,越早明白越好 国学文化 德鲁克博雅管理 2024-03-27 17:00 作者:方小格 来源:国学文化(gxwh001) 导语 比一个好的圈子更重要的,是自己优质的能力。 唐诗宋…...
图片和PDF展示预览、并支持下载
需求 展示图片和PDF类型,并且点击图片或者PDF可以预览 第一步:遍历所有的图片和PDF列表 <div v-for"(data,index) in parerFont(item.fileInfo)" :key"index" class"data-list-item"><downloadCard :file-inf…...
图论第5天
127.单词接龙 需要cout看一下过程。 #include <iostream> #include <queue> #include <stack> #include <unordered_map> #include <unordered_set> #include <vector> using namespace ::std;class Solution { public:int ladderLength(…...
Java开发-面试题-0004-HashMap 和 Hashtable的区别
Java开发-面试题-0004-HashMap 和 Hashtable的区别 更多内容欢迎关注我(持续更新中,欢迎Star✨) Github:CodeZeng1998/Java-Developer-Work-Note 技术公众号:CodeZeng1998(纯纯技术文) 生活…...
Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)
概览 在任何语言中对序列(或集合)元素的排序无疑是一种司空见惯的常规操作,在 Swift 语言里自然也不例外。序列排序看似简单,实则“暗藏玄机”。 要想真正掌握 Swift 语言中对排序的“各种姿势”,我们还得从长计议。不如就先从最简单的排序基本功开始聊起吧。 在本篇博…...
redis 04 redis结构
1.客户端...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
门静脉高压——表现
一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构:由肠系膜上静脉和脾静脉汇合构成,是肝脏血液供应的主要来源。淤血后果:门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血,引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...
