SpringBoot IOC与AOP(一)
IOC AOP
一、 分层解耦
内聚: 软件中各个功能模块内部的功能联系
耦合: 衡量软件中各个层/模块之间的依赖、关联的程度
软件设计原则:高内聚、低耦合
控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想成为控制反转
依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称为依赖注入。
Bean对象: IOC容器中创建、管理的对象,称为bean
1.1 IOC - 控制反转 详细
把某个对象交给IOC容器管理,需要添加如下注解之一:
声名bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认是类名首字母小写
使用以上四个注解都可以生命bean,但是在Springboot集成web开发中,声名控制器bean只能用@Controller
bean的四大注解想要生效,需要被组件扫描注解@ComponentScan扫描
@ComponentScan注解虽然没有显示配置,但是实际上已经包含在了启动类生命注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包
如下包名是从“java”包后开始的,但是下面这种不推荐,我们希望的是按照Spring的规范,将包设置在启动类所在包及其子包
@ComponentScan({"dao","com.zhangjingqi"})
1.2 DI - 依赖注入 详解
@Autowired 注解,默认是按照类型进行的,如果存在多个相同的bean,会报错。
EmpServiceA 实现 EmpService类,EmpServiceB 实现 EmpService类,我们在某个地方注入EmpService对象时便会出现注入错误。
解决方案
@Primary 设置bean的优先级
如果我们想要哪个bean填入容器,可以在类名之上添加@Primary
@Qualifier 指定bean的名字
@Qualifier("empServiceA")@Autowiredprivate EmpService empService;
@Resource 按照名称注入
@Autowired 注解默认按照类型注入,@Resource默认按照类名进行注入
@Resource(name = "empServiceB")private EmpService empService;
二、AOP
2.1 了解
Spring的第二大核心,第一大核心是IOC
AOP:面向切面编程、面向方面编程,其实就是面向特定方法编程
实现:
**动态代理是面向切面编程最主流的实现。**而SpringAOP是Spring框架的高级技术,目的是在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程
为什么要面向方法编程?
场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时,找到耗时较长的业务进行优化
按照之前的方式,就是在方法开始前和开时候分别获取一个时间,两个时间相减就是执行耗时,但是这种方式是非常繁琐的
————————————————
版权声明:本文为CSDN博主「我爱布朗熊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_51351637/article/details/130779252二、AOP
2.1 了解
Spring的第二大核心,第一大核心是IOC
AOP:面向切面编程、面向方面编程,其实就是面向特定方法编程
实现:
**动态代理是面向切面编程最主流的实现。**而SpringAOP是Spring框架的高级技术,目的是在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程
为什么要面向方法编程?
场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时,找到耗时较长的业务进行优化
按照之前的方式,就是在方法开始前和开时候分别获取一个时间,两个时间相减就是执行耗时,但是这种方式是非常繁琐的
如果我们基于AOP,面向方法编程,我们可以做到在不改动原始方法的基础上,来针对原始的方法进行编程,可以是对原始方法功能的增强,也可以改变原始方法的功能
比如我们现在要统计方法的耗时,我们只需要定义一个模板方法,将公共的代码定义在模板方法中
原始业务方法在这里指的是需要统计执行耗时的业务方法。而这样面向一个或者多个方法进行编程,就称为面向切面编程
比如我们调用list()方法,此时并不会直接执行原始的list方法,而是自动的去执行模板方法。
模板中所定义的代码逻辑其实是创建出来的代理对象方法中的逻辑
2.2 快速入门 - AOP 开发步骤
需求:统计各个业务层方法执行耗时
2.2.1 Maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.2.2 代码实现
针对于特定方法根据业务需要进行编程
@Slf4j
@Component //交给容器IOC进行管理
@Aspect //加上这个注解表示不是一个普通的类,而是一个AOP类,在此类中定义模板方法
public class TimeAspect {// 参数是一个表达式,表示针对哪些特定方法进行编程
// com.zhangjingqi.service 包名
// 第一个*代表任意返回值 第二个*代表类名或者接口名 第三个*代表方法名@Around("execution(* com.zhangjingqi.service.*.*(..))") //切入点表达式public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {long begin = System.currentTimeMillis();// result 原始方法执行返回值Object result = proceedingJoinPoint.proceed();//调用原始方式运行long end = System.currentTimeMillis();// proceedingJoinPoint.getSignature() 获取方法的签名,我们就知道是哪个方法了
// 如: List com.zhangjingqi.service.impl.DeptServiceImpl.list()执行耗时:239mslog.info(proceedingJoinPoint.getSignature() + "执行耗时:{}ms", end - begin);// 原始方法的返回值我们需要返回回去return result;}
}
2.2.3 AOP 应用场景及优势
应用场景
记录操作日志
权限控制
事务管理
优势
代码无侵入
减少重复代码
提高开发效率
维护方便
2.3 核心概念
2.3.1 连接点 - JoinPoint
连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
通知:Advice,指那些重读的逻辑,也就是共性功能(最终体现为一个方法)
切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用(就是实际被AOP控制的方法)
我们通常会使用下面的切入点表达式来描述切入点
@Around("execution(* com.zhangjingqi.service.*.*(..))")
切面:Aspect,描述通知与切入点的对应关系(通知+切入点),被@Aspect注解修饰的类我们一般称为切面类
目标对象:Target,通知所应用的对象。
2.3.2 AOP执行流程
通知如何与目标对象结合在一起对目标对象中的方法进行功能增强的?
①SpringAOP是基于动态代理技术来实现的。程序运行的时候会自动的基于动态代理技术为目标对象生成一个对应的代理对象。
② 在代理对象中就会对目标对象中的原始方法进行功能的增强。
如何来增强的?增强的逻辑是什么样子的?
其实就是我们的通知
③最终在Spring容器中注入的是代理对象,调用的方法也是代理对象中的对应方法
2.4 通知
2.4.1 通知类型
@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行,出现异常后后置代码不会执行。(因为原始方法出现异常了)
@Before:前置通知,此注解标注的通知方法在目标方法前被执行
@After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
@AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing:异常后通知,此注解标注的通知方法在发生异常后执行
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect
public class MyAspect1 {//前置通知@Before("execution(* com.zhangjingqi.service.*.*(..))")public void before(JoinPoint joinPoint) {log.info("before ...");}//环绕通知@Around("execution(* com.zhangjingqi.service.*.*(..))")public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {log.info("around before ...");//调用目标对象的原始方法执行Object result = proceedingJoinPoint.proceed();//原始方法如果执行时有异常,环绕通知中的后置代码不会在执行了log.info("around after ...");return result;}//后置通知@After("execution(* com.zhangjingqi.service.*.*(..))")public void after(JoinPoint joinPoint) {log.info("after ...");}//返回后通知(程序在正常执行的情况下,会执行的后置通知)@AfterReturning("execution(* com.zhangjingqi.service.*.*(..))")public void afterReturning(JoinPoint joinPoint) {log.info("afterReturning ...");}//异常通知(程序在出现异常的情况下,执行的后置通知)@AfterThrowing("execution(* com.zhangjingqi.service.*.*(..))")public void afterThrowing(JoinPoint joinPoint) {log.info("afterThrowing ...");}
}
注意事项
@Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来执行原始方法,其他通知不需要考虑原始方法的执行
@Around环绕通知的方法的返回值,必须指定为Object,来接收原始方法的返回值
如果不return,在调用这个方法的地方时拿不到返回值的
对切入点表达式进行抽取
// 生命切入点表达式的注解,切点@Pointcut("execution(* com.zhangjingqi.service.*.*(..))")private void pt(){}//前置通知@Before("pt()")public void before(JoinPoint joinPoint) {log.info("before ...");}
其他类中也可以进行抽取,只需要定位到切入点表达式的位置即可。
@Slf4j
@Component
@Aspect
public class MyAspect2 {
//引用MyAspect1切面类中的切入点表达式
@Before("com.zhangjingqi.aspect.MyAspect1.pt()")
public void before(){
log.info("MyAspect2 -> before ...");}
}
2.4.2 通知顺序
当有多个切面的切入点都匹配到了目标方法,目标方法运行,多个通知方法都会被执行。
下面研究多个切面类的通知顺序。同个切面类的通知顺序不再研究
不同切面类中,默认按照切面类的类名字母排序
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
使用@Order(数字)加在切面类上来控制顺序
2.5 切入点表达式
切入点表达式:描述切入点方法的一种表达式
作用:主要用来决定项目中哪些方法需要加入通知
常见形式
execution(…):根据方法的签名来匹配
@annotation(…):根据注解匹配
2.5.1 execution
主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配
下面来描述的时候,可以基于接口。也可以基于实现类
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中?表示可省略的部分
访问修饰符:可省略,比如public、protected
包名.类名:可省略,但是不建议
throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
2.5.1.1 execution通配符
*:单个独立的任意符号,可以匹配任意返回值、包名、类名、方法名、方法参数等信息来匹配
此案例表示返回值人任意,二级包任意,类或接口任意,方法参数任意但是有且只有一个
execution(* com.*.service.*.update(*)
匹配类名以Service结尾,方法以delete开头的方法
execution(void
com.itheima.service.impl.*Service.delete*(java.lang.Integer)
)
…:多个连续的任意符号,可以通配任意层级的包,或者任意类型、任意个数的参数
层级包任意,方法的参数任意
execution(* com.zhangjingqi..DeptService.*(..)
返回值任意,方法名任意,方法参数任意
execution(* *(..)
2.5.1.2 execution表达式案例
@Pointcut("execution(* com.zhangjingqi.service.*.*(..))")
省略异常
execution(public void
com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer)
)
省略方法访问修饰符
参数是全类名
execution(void
com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer)
)
使用"…"省略包名
execution(public void com..DeptServiceImpl.delete(java.lang.Integer))
省略包名类名
指定方法名。
不建议将包名和方法名省略。一旦省略,将表达式的范围扩大,一是影响匹配的效率,而是可能匹配到其他不需要的方法
execution(public void delete(java.lang.Integer))
匹配所有的方法
此时表示匹配DeptServiceImpl类中的所有方法
execution(public void com..DeptServiceImpl.*(java.lang.Integer))
使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式
execution(* com.zhangjingqi.service.DeptService.list(..)) ||
execution(* com.zhangjingqi.service.DeptService.delete(..))
2.5.1.3 切入点表达式建议
所有业务方法名在命名时尽量规范,方便切入点快速匹配。
如查询方法find开头,更新类方法update开头
描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性
在满足业务需要的前提下,尽量缩小切入点的匹配范围
包名匹配进行不使用“…”,使用“*”匹配单个包
2.5.2 @annotation
用于匹配标识有特定注解的方法
@Before("@annotation(com.zhangjingqi.anno.MyLog)")
简化下列表达式
execution(* com.zhangjingqi.service.DeptService.list(..)) ||
execution(* com.zhangjingqi.service.DeptService.delete(..))
实现步骤
编写自定义注解
在业务类要做为连接点的方法上添加自定义注解
创建自定义注解类
@Retention(RetentionPolicy.RUNTIME)//描述注解什么时候生效的:运行时有效
@Target(ElementType.METHOD)//当前注解可以作用在哪些地方
public @interface MyLog {
}
添加自定义注解
@Override
@MyLog //自定义注解(表示:当前方法属于目标方法)
public List<Dept> list() { ... }@Override
@MyLog //自定义注解(表示:当前方法属于目标方法)
public void delete(Integer id) { ... }
切面类
@Slf4j
@Component
@Aspect
public class MyAspect6 {
//针对list方法、delete方法进行前置通知和后置通知
//前置通知
@Before("@annotation(com.zhangjingqi.anno.MyLog)")public void before(){log.info("MyAspect6 -> before ...");//后置通知
@After("@annotation(com.zhangjingqi.anno.MyLog)")public void after(){log.info("MyAspect6 -> after ...");}
}
2.5.3 切入点表达式总结
execution切入点表达式
根据我们所指定的方法的描述信息来匹配切入点方法,这种方式也是最为常用的一种方式
如果我们要匹配的切入点方法的方法名不规则,或者有一些比较特殊的需求,通过
execution切入点表达式描述比较繁琐
annotation 切入点表达式
基于注解的方式来匹配切入点方法。这种方式虽然多一步操作,我们需要自定义一个注解,但
是相对来比较灵活。我们需要匹配哪个方法,就在方法上加上对应的注解就可以了
2.6 连接点
被AOP控制的方法,目标对象中所有的方法都可以被AOP控制,在Spring AOP中又特制方法的执行
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法类名、方法参数等
对于@Around通知,获取连接点信息只能用ProceedingJoinPoint
对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint父类型
对于@Around通知,为什么获取连接点信息只能用ProceedingJoinPoint?
在Spring AOP中,@Around通知是最为强大和灵活的通知类型,它可以决定是否执行连接点,以及如何处理连接点返回的结果。因此,@Around通知需要通过ProceedingJoinPoint参数来获取连接点信息。
ProceedingJoinPoint是JoinPoint的子类,同时也是JoinPoint的扩展版本。JoinPoint表示连接点,也就是被Advice修饰的方法。而ProceedingJoinPoint除了表示连接点外,还具有一个proceed()方法,该方法是执行目标方法的关键。在@Before和@After通知中,JoinPoint足以满足需要,因为它们只需要获取连接点信息即可,不需要执行目标方法。但在@Around中,除了获取连接点信息,还需要控制目标方法的执行,因此需要用到ProceedingJoinPoint。
在@Around通知中,可以通过ProceedingJoinPoint的proceed()方法,手动控制目标方法的执行。例如,可以在proceed()方法前后进行一些预处理或后处理。同时,ProceedingJoinPoint还提供了一些其他的工具方法,例如getArgs()获取目标方法参数,getSignature()获取目标方法签名等,这些方法在编写@Around通知时也非常有用。
相关文章:

SpringBoot IOC与AOP(一)
IOC AOP 一、 分层解耦 内聚: 软件中各个功能模块内部的功能联系 耦合: 衡量软件中各个层/模块之间的依赖、关联的程度 软件设计原则:高内聚、低耦合 控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到…...
JVM运行时数据区——方法区的垃圾回收
方法区的垃圾回收主要是两部分:运行时常量池中废弃的常量和不在使用的类。 类卸载(将不在使用的类回收)的条件: 该类的所有实例均被回收。 加载该类的类加载器被回收(一般很难满足)。 类对象不再引用,通过反射也获取不到。...

LeetCode213.House-Robber-II<打家劫舍II>
题目: 思路: 在版本一中增加了一个条件 那就是首尾相关联。那么只需要进行两次循环即可。 第一次是循环是偷第一家的 那么循环到n-1 截至 并且保存一个cmp 第二次循环是不偷第一家的 循环到n截至。然后比较cmp 与 dp [n] 的最大值即可。 代码是&#…...
订单系统问题汇总
1、项目启动失败 原因是pom中既配置了mybatis又配置了mybatis-plus 2、idea连接后提示缺少MySQL驱动,直接根据提示安装就好 3、解析请求得到的json为对象时候报错,待解析的对象是泛型对象 String regionsInfo OkHttpRequestUtils.sendGetRequest(new…...
springboot热加载spring-boot-devtools:
springboot热加载 基于idea开发springboot项目使用热加载 pom依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</op…...

QT学习之旅 - 一个QT的基本项目
文章目录 定时器(时间)位置信息QTableWidget用cellwidget添加控件隐藏QTableWidget的滚动条自动调整适应大小 UDPUDP ClientUDP ServerUDP udpSocket.readDatagram重要参数使用多线程udp 自定义信号和槽UDP服务端接收数据(全局变量) QWT设置标题数轴相关设置坐标轴范围设置坐标…...

大数据课程D2——hadoop的概述
文章作者邮箱:yugongshiyesina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解hadoop的定义和特点; ⚪ 掌握hadoop的基础结构; ⚪ 掌握hadoop的常见命令; ⚪ 了解hadoop的执行流程; 一、简介 1…...

使用nginx和ffmpeg搭建HTTP FLV流媒体服务器(摄像头RTSP视频流->RTMP->http-flv)
名词解释 RTSP (Real-Time Streaming Protocol) 是一种网络协议,用于控制实时流媒体的传输。它是一种应用层协议,通常用于在客户端和流媒体服务器之间建立和控制媒体流的传输。RTSP允许客户端向服务器发送请求,如…...

揭秘APT团体常用的秘密武器——AsyncRAT
AsyncRAT 是 2019 年 1 月在 [GitHub](https://github.com/NYAN-x-CAT/AsyncRAT-C- Sharp)上开源的远控木马,旨在通过远程加密链接控制失陷主机,提供如下典型功能: 截取屏幕 键盘记录 上传/下载/执行文件 持久化 禁用 Windows Defender 关机/…...

Flutter Widget Life Cycle 组件生命周期
Flutter Widget Life Cycle 组件生命周期 视频 前言 了解 widget 生命周期,对我们开发组件还是很重要的。 今天会把无状态、有状态组件的几个生命周期函数一起过下。 原文 https://ducafecat.com/blog/flutter-widget-life-cycle 参考 https://api.flutter.dev/f…...

LeetCode面向运气之Javascript—第2600题-K件物品的最大和-94.68%
LeetCode第2600题-K件物品的最大和 题目要求 袋子中装有一些物品,每个物品上都标记着数字 1 、0 或 -1 。 四个非负整数 numOnes 、numZeros 、numNegOnes 和 k 。 袋子最初包含: numOnes 件标记为 1 的物品。numZeroes 件标记为 0 的物品。numNegOn…...

数学建模学习(4):TOPSIS 综合评价模型及编程实战
一、数据总览 需求:我们需要对各个银行进行评价,A-G为银行的各个指标,下面是银行的数据: 二、代码逐行实现 清空代码和变量的指令 clear;clc; 层次分析法 每一行代表一个对象的指标评分 p [8,7,6,8;7,8,8,7];%每一行代表一个…...

PHP之Smarty使用以及框架display和assign原理
一、Smarty的下载 进入Smarty官网下载,复制目录libs目录即可http://www.smarty.net/http://www.smarty.net/ 二、使用Smarty,创建目录demo,把libs放进去改名为Smarty 三、引入Smarty配置,创建目录,index.php文件配置 <?php…...

《TCP IP网络编程》第十一章
第 11 章 进程间通信 11.1 进程间通信的基本概念 通过管道实现进程间通信: 进程间通信,意味着两个不同的进程中可以交换数据。下图是基于管道(PIPE)的进程间通信的模型: 可以看出,为了完成进程间通信&…...

Folx Pro 5 最好用的Mac磁力链接BT种子下载工具
除了迅雷,还有哪个支持磁力链接下载?Mac电脑如何下载磁力链接?经常有小伙伴问老宅。今天,老宅给大家推荐Folx Pro For Mac,Mac系统超好用的磁力下载工具。 Folx是一款功能强大且易于使用的Mac下载管理器,并…...
Redis 数据库的高可用
文章目录 Redis 数据库的高可用一.Redis 数据库的持久化1.Redis 高可用概念2.Redis 实现高可用的技术2.1 持久化2.2 主从复制2.3 哨兵2.4 Cluster集群 3.Redis 持久化3.1 持久化的功能3.2 Redis 提供持久化的方式3.2.1 RDB 持久化3.2.2 AOF 持久化(append only file…...

elementPlus dialog组件设置可拖动,当内容高度大于视口高度拖动显示异常的解决办法
elementPlus UI的dialog弹框组件在设置了draggable属性后就可拖动弹框,但是当弹框的内容高度大于视口高度时去拖动弹框就会出现显示问题。 解决办法(修改源码) 去node_modules下面找到element-plus文件夹,按照以下路径修改onMou…...

亲测解决Git inflate: data stream error (incorrect data check)
Git inflate: data stream error (incorrect data check) error: unable to unpack… 前提是你的repository在github等服务器或者其他路径有过历史备份/副本,不要求是最新版本的,只要有就可能恢复你做的所有工作。 执行git fsck --full检查损坏的文件 在…...

Ansible 自动化运维工具
Ansible 简介 Ansible 自动化运维工具(机器管理工具)可以实现批量管理多台(成百上千)主机,应用级别的跨主机编排工具。现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点,Pubbet和Saltstac…...

node.js 爬虫图片下载
主程序文件 app.js 运行主程序前需要先安装使用到的模块: npm install superagent --save axios要安装指定版,安装最新版会报错:npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...