当前位置: 首页 > news >正文

Spring AOP(1)

目录

一、AOP 概述

什么是Spring AOP?

二、Spring AOP 快速入门

1、引入AOP依赖

2、编写AOP程序

三、Spring AOP 详解

1、Spring AOP的核心概念

(1)切点(Pointcut)

(2)连接点(Join Point)

(3)通知(Advice)

(4)切面(Aspect)

(5)总结

2、通知类型

(1)正常运行的情况

(2)运行失败的情况

(3)@Around 通知类型

(4)注意事项

3、@PointCut

4、切面优先级 @Order

5、切点表达式

(1)execution 表达式

切点表达式

(2)@annotation

① 自定义注解 @MyAspect

② 切面类

③ 添加自定义注解

6、Spring AOP 的实现方式(常见面试题)


一、AOP 概述

        AOP 是 Spring 框架 的第二大核心(第一大核心是 IoC)。

        AOP 的全称Aspect Oriented Programming(面向切面编程)什么是面向切面编程呢?切面就是指某一类特定问题,所以 AOP 也可以理解为 面向特定方法编程

        什么是面向特定方法编程呢?比如之前图书馆管理系统的 “登录校验”,就是一类特定问题。登录校验拦截器,就是对 “登录校验” 这类问题的统一处理。所以,拦截器也是 AOP 的一种应用。AOP 是一种思想,拦截器是 AOP 思想的一种实现。Spring 框架实现了这种思想,提供了拦截器技术的相关接口。

        同样的,统一数据返回格式 和 统一异常处理,也是 AOP 思想的一种实现。

        简单来说:AOP 是一种思想,是对某一类事情的集中处理

什么是Spring AOP?

        AOP 是一种思想,它的实现方法有很多,有Spring AOP,也有 AspectJ、CGLIB等。

        Spring AOP 是其中的一种实现方式。学会了统一功能之后,是不是就学会了Spring AOP 呢?当然不是。

        拦截器作用的维度是 URL(依次请求和响应),@ControllerAdvice 应用场景主要是全局异常处理(配合自定义异常效果更佳),数据绑定,数据预处理。AOP作用的维度更加细致(可以根据包、类、方法名、参数等进行拦截),能够实现更加复杂的业务逻辑。

        举个例子:我们现在有一个项目,项目中开发了很多功能。如图:

        现在有一些业务的执行效率比较低,耗时较长,我们需要对接口进行优化。第一步就需要定位出执行耗时比较长的业务方法,再针对该业务方法来进行优化。如何定位呢?我们就需要统计当前项目中每一个业务方法的执行耗时。

        如何统计呢?可以在业务方法运行前和运行后,记录下方法的开始时间和结束时间,两者之差就是这个方法的耗时。如图:

        上面这种方法是可以解决问题的,但一个项目中会包含很多业务模块,每个业务模块又有很多接口,一个接口又包含很多方法,如果我们要在每个业务方法中都记录方法的耗时,对于程序员而言,会增加很多的工作量。

        而 AOP 就可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增强(AOP的作用程序运行期间,在不修改源代码的基础上对已有方法进行增强 ——> 无入侵性:解耦)


二、Spring AOP 快速入门

1、引入AOP依赖

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

2、编写AOP程序

@Slf4j
@Component
@Aspect
public class TimeRecordAspect {/*** 记录耗时*/@Around("execution(* com.example.books_management_system.controller.*.*(..))")public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {//记录开始时间long star = System.currentTimeMillis();//执行目标方法Object proceed = joinPoint.proceed();//记录结束时间long end = System.currentTimeMillis();//日志打印耗时log.info("耗时时间: " + (end - star) + "ms");return proceed;}
}

        运行程序,观察日志:

        上面的切点是:com.example.books_management_system.controller.*.*  ,指的是 ...controller包下的所有类和所有方法,都要执行上面的方法(也称为通知)

        对程序进行简单的讲解:

1、@Aspect标识这是一个切面类

2、@Around环绕通知,在目标方法的前后都会被执行。后面的表达式表示对哪些方法进行增强

3、ProceedingJoinPoint.proceed()让原始方法执行

        整个代码划分为三部分

        通过上面的程序,我们可以感受到AOP面向变成的一些优势:

1、代码无侵入:不修改原始的业务方法,就可以对原始的业务方法进行了功能的增强或者是功能的改变。

2、减少了重复代码

3、提高开发效率

4、方便维护


三、Spring AOP 详解

1、Spring AOP的核心概念

(1)切点(Pointcut)

        也称之为 “切入点”,Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述),告诉程序对哪些方法来进行功能增强

        上面的表达式:execution(* com.example.books_management_system.controller.*.*(..)) ,就是切点表达式

(2)连接点(Join Point)

        满足切点表达式规则的方法,就是连接点。也就是可以被AOP控制的方法。

        以入门程序举例,所有 com.example.books_management_system.controller 路径下的方法,都是连接点。

        

(3)通知(Advice)

        通知就是具体要做的工作,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法),比如上述程序中记录业务方法的耗时时间,就是通知。

        在AOP面向切面编程当中,我们把这部分重复的代码逻辑取出来单独定义,这部分代码就是通知的内容。

(4)切面(Aspect)

        切面(Aspect)= 切点(Pointcut) + 通知(Advice)

        通过切面就能够描述当前AOP程序需要针对于哪些方法,在什么时候执行什么样的操作

        切面所在的类,我们一般称为切面类(被@Aspect注解表示的类)。

(5)总结

        切点就是一规则,连接点就是符合这个规则的对象,通知就是对象做的事情,切面就是符合规则的所有对象做事

        举个栗子:报名蓝桥杯的学生在 2024-04-13 参比赛。

切点:报名蓝桥杯的学生。

连接点:这些学生具体的每一个人。

通知:在 2024-04-13 参加比赛。

切面:报名蓝桥杯的学生在 2024-04-13 参比赛。

2、通知类型

        上面我们讲了什么是通知,接下来学习通知的类型。@Around 就是其中一种通知类型,表示环绕通知。Spring 中 AOP 的通知类型有以下几种:

@Around环绕通知,此注解标注的通知方法在目标方法前、后都被执行

@Before前置通知,此注解标注的通知方法在目标方法前被执行

@After后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行

@AfterReturning返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行

@AfterThrowing异常后通知,此注解标注的通知方法发生异常后执行

        接下来测试这些通知类型,代码如下:

@Slf4j
@Aspect
@Component
public class AspectDemo {//前置通知@Before("execution(* com.example.springaop.controller.*.*(..))")public void doBefore() {log.info("do before");}//后置通知@After("execution(* com.example.springaop.controller.*.*(..))")public void doAfter() {log.info("do after");}//添加环绕通知@Around("execution(* com.example.springaop.controller.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("do around before");Object result = joinPoint.proceed();log.info("do around after");return result;}//返回后通知@AfterReturning("execution(* com.example.springaop.controller.*.*(..))")public void doAfterReturning() {log.info("do after returning");}//抛出异常后通知@AfterThrowing("execution(* com.example.springaop.controller.*.*(..))")public void doAfterThrowing() {log.info("do after throwing");}
}

        测试接口:

@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {@RequestMapping("/t1")public String t1() {log.info("执行t1方法...");return "t1";}@RequestMapping("/t2")public Boolean t2() {int a = 10 / 0;return true;}
}

(1)正常运行的情况

        接口:http://127.0.0.1:8080/test/t1 ,测试结果如下:

        执行的顺序是 Around Before -> Before -> AfterReturning -> After -> Around After,如图:

        程序正常运行的情况下,AfterThrowing 标识的通知方法不会执行。

(2)运行失败的情况

        接口:http://127.0.0.1:8080/test/t2 ,测试结果如下:

        执行顺序:Around Before -> Before -> AfterThrowing-> After,如图:

        可以看到,因为有异常,所以会执行 AfterThrowing,没有执行 AfterReturning,改成了 AfterThrowing而 After 无论是否有异常都会执行因为有异常,所以执行完目标方法后,就不会执行 AroundAfter 了

(3)@Around 通知类型

        其中单独测试一下 @Around 通知类型,有返回Object类型 和 没有返回Object类型的区别,代码如下:

        无返回Object类型:

    @Around("execution(* com.example.springaop.controller.*.*(..))")public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("do around before");log.info("do around after");}

        又返回Object类型:

    @Around("execution(* com.example.springaop.controller.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("do around before");Object result = joinPoint.proceed();log.info("do around after");return result;}

        无返回类型 和 有返回类型 的区别图:

        所以,@Around 环绕通知方法的返回值,必须指定为 Object 类型。

(4)注意事项

1、@Around 环绕通知需要调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行。

2、@Around 环绕通知方法的返回值,必须指定为Object 类型,来接收原始方法的返回值,否则原始方法执行完毕,使获取不到返回值的。

3、一个切面类可以有多个切点。


3、@PointCut

        上面代码存在一个问题,就是存在大量重复的切点表达式:

execution(* com.example.springaop.controller.*.*(..)),Spring 提供了 @PointCut 注解,把公共的切点表达式提取出来,需要用到时引入该切入点表达式即可

        上面代码就可以修改为:

@Slf4j
@Aspect
@Component
public class AspectDemo {@Pointcut("execution(* com.example.springaop.controller.*.*(..))")private void pt(){}//public void pt(){} 其他类要使用pt()时,使用public修饰//前置通知@Before("pt()")public void doBefore() {log.info("do before");}//后置通知@After("pt()")public void doAfter() {log.info("do after");}//添加环绕通知@Around("pt()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("do around before");Object result = joinPoint.proceed();log.info("do around after");return result;}//返回后通知@AfterReturning("pt()")public void doAfterReturning() {log.info("do after returning");}//抛出异常后通知@AfterThrowing("pt()")public void doAfterThrowing() {log.info("do after throwing");}
}

        当切点定义使用 private 修饰时,仅能在当前切面类中使用,当其他切面类也要使用当前切点定义时,就需要把 private 改为 public引用方式全限定类名.方法名()

        当其他切面类使用上面这个PointCut时,代码如下:

@Slf4j
@Aspect
@Component
public class AspectDemo2 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo2 -> Before ⽅法");}
}

        测试接口:http://127.0.0.1:8080/test/t1,日志如下:

 

4、切面优先级 @Order

        当我们在一个项目中,定义了多个切面类时,并且这些切面类的多个切入点都匹配到了同一个目标方法。当目标方法运行的时候,这些切面类中的通知方法都会执行,那么这几个通知方法的执行顺序是什么样的呢?

        那么不同类的 通知 运行的顺序是怎么样的呢?现在切面类有下面几个:

@Slf4j
@Aspect
@Component
public class AspectDemo2 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo2 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo2 -> After ⽅法");}
}@Slf4j
@Aspect
@Component
public class AspectDemo3 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo3 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo3 -> After ⽅法");}
}@Slf4j
@Aspect
@Component
public class AspectDemo4 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo4 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo4 -> After ⽅法");}
}

        测试顺序如下:

        可以看到 默认给我们的排序是按切面类名大小进行排序的。存在多个切面类时,默认按照切面类的类名字母排序

@Before 通知字母排名靠前的先执行

@After 通知字母排名靠前的后执行

        那如果我们不想按这个顺序,按照自定义顺序行不行?当然可以了,下面是@Order注解的使用(@Order注解 的括号里面放数字)

@Slf4j
@Aspect
@Order(3)
@Component
public class AspectDemo2 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo2 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo2 -> After ⽅法");}
}@Slf4j
@Aspect
@Order(2)
@Component
public class AspectDemo3 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo3 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo3 -> After ⽅法");}
}@Slf4j
@Aspect
@Order(1)
@Component
public class AspectDemo4 {@Before("com.example.springaop.aspect.AspectDemo.pt()")public void doBefore() {log.info("执⾏ AspectDemo4 -> Before ⽅法");}@After("com.example.springaop.aspect.AspectDemo.pt()")public void doAfter() {log.info("执⾏ AspectDemo4 -> After ⽅法");}
}

        运行观察日志,如图:

        

        通过上述程序的运行结果,得出结论,@Order 注解标识的切面类,执行顺序如下:

@Before 通知数字小 的 先执行

@After 通知数字大 的先执行

        @Order 控制切面的 优先级,先执行优先级较高的切面,再执行优先级较低的切面,最终执行目标方法。如图:

5、切点表达式

        上面的代码中,我们一直在使用切点表达式来描述切点,下面进行介绍切点表达式的语法,切点表达式常见有两种表达方式:

1execution(......):根据方法的签名来匹配

2@annotation(......):根据注解匹配

(1)execution 表达式

        execution() 是最常用的切点表达式,用来匹配方法,语法为:

execution( <访问修饰符>  <返回类型>  <包名.类名.方法(方法参数)> <异常> )

上面的切点表达式意思是:任意的返回类型,在....controller包下的任意类方法(任意方法参数都行)

        其中:访问修饰符和异常可以省略。

        切点表达式支持通配符:

1、* 匹配任意字符,只匹配一个元素(返回类型,包,类名,方法或者方法参数)

a、包名使用 * 表示任意包(一层包使用一个 *)。

b、类名使用 * 表示任意类。

c、返回值使用 * 表示任意返回值类型。

d、方法名使用 * 表示任意方法。

e、参数使用 * 表示一个任意类型的参数。

2、..匹配多个连续的任意符号,可以通配任意层级的包,或任意类型,任意个数的参数

a、使用 .. 配置包名,标识此包以及此包下的所有子包。

b、可以使用 .. 配置参数,任意个任意类型的参数。

切点表达式

TestController 下的 public 修饰,返回类型为String 、方法名为t1、无参方法:

execution(public String com.example.demo.controller.TestController.t1())

省略访问修饰符:

execution(String com.example.demo.controller.TestController.t1())

匹配所有返回类型:

execution(* com.example.demo.controller.TestController.t1())

匹配TestController 下的所有⽆参方法:

execution(* com.example.demo.controller.TestController.*())

 匹配TestController 下的所有方法:

execution(* com.example.demo.controller.TestController.*(..))

匹配controller包下所有的类的所有方法:

execution(* com.example.demo.controller.*.*(..))

匹配所有包下⾯的TestController:

execution(* com..TestController.*(..))

匹配com.example.demo包下,子孙包下的所有类的所有⽅法:

execution(* com.example.demo..*(..))

(2)@annotation

        execution 表达式更适用有规则的,如果我们要匹配多个无规则的方法呢?比如:TestController 中的 t1() 和 UserController 中的 u1() 这两个方法。

        这个时候我们使用 execution 这种 切点表达式来描述就很不方便了。

        这时我们就可以借助自定义注解的方式以及另一种切点表达式 @annotation 来描述这一类的切点

        实现步骤:

1编写自定义注解

2使用 @annotation 表达式来描述切点

3在连接点的方法上添加自定义注解

准备测试代码:

@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {@RequestMapping("/t1")public String t1() {log.info("执行t1方法...");return "t1";}@RequestMapping("/t2")public Boolean t2() {log.info("执行t2方法...");return true;}
}@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@RequestMapping("/u1")public String u1() {log.info("执行u1方法...");return "u1";}@RequestMapping("/u2")public String u2() {log.info("执行u2方法...");return "u2";}
}
① 自定义注解 @MyAspect

        创建一个注解类(和创建 Class 文件一样的流程,选择 Annotation 就可以了)

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 MyAspect {
}

        代码的简单说明:

1@Target 标识了 Annotation 所修饰的对象范围,即该注解可以用在什么地方

  常用取值:

        ElementType.TYPE用于描述类、接口(包括注解类型) 或 enum声明
        ElementType.METHOD描述方法

        ElementType.PARAMETER描述参数

        ElementType.TYPE_USE可以标注任意类型
2@Retention 指 Annotation 被保留的时间长短,标明注解的生命周期

        ①RentionPolicy.SOURCE:表示注解仅存在于源代码中,编译成字节码后会被丢弃。这意味着在运⾏时⽆法获取到该注解的信息,只能在编译时使用。比如@SuppressWarnings ,以及lombok提供的注解 @Data ,@Slf4j。

        ②RetentionPolicy.CLASS编译时注解。表示注解存在于源代码和字节码中,但在运⾏时会被丢弃。这意味着在编译时和字节码中可以通过反射获取到该注解的信息,但在实际运行时⽆法获取。通常⽤于⼀些框架和⼯具的注解。

        ③RetentionPolicy.RUNTIME运⾏时注解。表示注解存在于源代码,字节码和运⾏时中。这意味着在编译时,字节码中和实际运⾏时都可以通过反射获取到该注解的信息。通常用于⼀些需要在运⾏时处理的注解,如Spring的 @Controller  @ResponseBody。

② 切面类

        使用 @annotation 切点表达式定义切点,只对 @MyAspect生效,代码如下:

@Slf4j
@Component
@Aspect
public class MyAspectDemo {@Around("@annotation(com.example.springaop.config.MyAspect)")public Object doAround(ProceedingJoinPoint joinPoint) {log.info("do around before");Object o = null;try {o = joinPoint.proceed();} catch (Throwable e) {log.error("发生异常, e:" + e);}log.info("do around after");return o;}
}

        上面的通知类型使用 @annotation注解后,注解括号里的 MyAspect,表示谁使用 @MyAspect注解,就会执行下面代码

③ 添加自定义注解

        在 TestController 中的 t1() 和 UserController 中的 u1 这两个方法上添加自定义注解 @MyAspect,其他方法不添加。(已把之前的AspectDemo的@Comment注解给注释掉了)

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@MyAspect@RequestMapping("/u1")public String u1() {log.info("执行u1方法...");return "u1";}
}
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {@MyAspect@RequestMapping("/t1")public String t1() {log.info("执行t1方法...");return "t1";}
}

        运行程序,测试接口:

        
127.0.0.1:8080/test/t1
 

        

        控制台日志如下:

        127.0.0.1:8080/user/u1

        可以看到,通过自定义注解的方式,就可以匹配多个无规则的方法。

6、Spring AOP 的实现方式(常见面试题)

(1)基于注解 @Aspect (参考上述)

(2)基于自定义注解(参考自定义注解 @annotation 部分的内容)

(3)基于 Spring API(通过 xml 配置的方式,自从SpringBoot 广泛使用之后,这种方法几乎看不到了)

(4)基于代理来实现(更加久远的一种实现方式,写法笨重,不建议使用)

参考:面试官:谈谈你对IOC和AOP的理解及AOP四种实现方式[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com)

相关文章:

Spring AOP(1)

目录 一、AOP 概述 什么是Spring AOP&#xff1f; 二、Spring AOP 快速入门 1、引入AOP依赖 2、编写AOP程序 三、Spring AOP 详解 1、Spring AOP的核心概念 &#xff08;1&#xff09;切点&#xff08;Pointcut&#xff09; &#xff08;2&#xff09;连接点&#xff…...

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ ssh -p 37367 rootssh.intern-ai.org.cn -CNg -L 7860:127.0.0.1:7860 -o StrictHostKeyCheckingno可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 …...

tensorflow keras Model.fit returning: ValueError: Unrecognized data type

题意&#xff1a;TensorFlow Keras 的 Model.fit 方法返回了一个 ValueError&#xff0c;提示数据类型无法识别 问题背景&#xff1a; Im trying to train a keras model with 2 inputs: an image part thats a tf.data.Dataset and a nor mal part represented by a pd.DataF…...

虚拟机固定配置IP

在Hyper-V中&#xff0c;vEthernet (Default Switch) 是Hyper-V自带的默认虚拟交换机&#xff0c;它允许虚拟机直接连接到宿主机网络或外部网络。这个虚拟交换机可以通过Hyper-V管理器或PowerShell等工具进行管理和配置。以下是具体的操作步骤&#xff1a; 一、通过Hyper-V管理…...

【Pytorch实用教程】pytorch中random_split用法的详细介绍

在 PyTorch 中,torch.utils.data.random_split 是一个非常有用的函数,用于将数据集随机分割成多个子集。这在机器学习和深度学习中非常常见,特别是当你需要将数据集分割成训练集和测试集或验证集时。这里是 random_split 的详细用法介绍: 功能 random_split 用于随机地将…...

第二讲:NJ网络配置

Ethernet/IP网络拓扑结构 一. NJ EtherNet/IP 1、网络端口位置 NJ的CPU上面有两个RJ45的网络接口,其中一个是EtherNet/IP网络端口(另一个是EtherCAT的网络端口) 2、网络作用 如图所示,EtherNet/IP网络既可以做控制器与控制器之间的通信,也可以实现与上位机系统的对接通…...

pytorch中常见的模型3种组织方式 nn.Sequential(OrderedDict)

在nn.Sequential中嵌套OrderedDict组织网络,以对层进行命名 import torch import torch.nn as nn from collections import OrderedDictclass OrderedDictCNN(nn.Module):def __init__(self):super(OrderedDictCNN, self).__init__()# 使用 OrderedDict 定义网络层self.model …...

达梦数据库DM8-索引篇

目录 一、前景二、名词三、语法1、命令方式创建索引1.1 创建索引空间1.2.1 创建普通索引并指定索引数据空间1.2.2 另一种没验证&#xff0c;官方写法1.3 复合索引1.4 唯一索引1.5 位图索引1.6 函数索引 2、创建表时候创建索引3、可视化方式创建索引3.1 打开DM管理工具3.2 找到要…...

【中项】系统集成项目管理工程师-第4章 信息系统架构-4.5技术架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…...

随机梯度下降 (Stochastic Gradient Descent, SGD)

SGD 是梯度下降法的一种变体。与批量梯度下降法不同&#xff0c;SGD 在每次迭代中仅使用一个样本&#xff08;或一个小批量样本&#xff09;的梯度来更新参数。它能更快地更新参数&#xff0c;并且可以更容易地跳出局部最优解。 原理 SGD 的基本思想是通过在每次迭代中使用不…...

TDengine 3.3.2.0 发布:新增 UDT 及 Oracle、SQL Server 数据接入

经过数月的开发和完善&#xff0c;TDengine 3.3.2.0 版本终于问世了。这一版本中既有针对开源社区的功能优化&#xff0c;也有从企业级用户需求出发做出的功能调整。在开源版本中&#xff0c;我们增强了系统的灵活性和兼容性&#xff1b;而在企业级版本中&#xff0c;新增了关键…...

Ubuntu 24.04 LTS 无法打开Chrome浏览器

解决办法&#xff1a; 删除本地配置文件&#xff0c;再次点击Chrome图标&#xff0c;即可打开。 rm ~/.config/google-chrome/ -rf ref: Google chrome not opening in Ubuntu 22.04 LTS - Ask Ubuntu...

linux中RocketMQ安装(单机版)及springboot中的使用

文章目录 一、安装1.1、下载RocketMQ1.2、将下载包上传到linux中&#xff0c;然后解压1.3、修改runserver.sh的jvm参数大小&#xff08;根据自己服务器配置来修改&#xff09;1.4、启动mqnamesrv &#xff08;类似于注册中心&#xff09;1.5、修改runbroker.sh的jvm参数大小&am…...

亚信安全终端一体化解决方案入选应用创新典型案例

近日&#xff0c;由工业和信息化部信息中心主办的2024信息技术应用创新发展大会暨解决方案应用推广大会成功落幕&#xff0c;会上集中发布了一系列技术水平先进、应用效果突出、产业带动性强的信息技术创新工作成果。其中&#xff0c;亚信安全“终端一体化安全运营解决方案”在…...

Django视图与URLs路由详解

在Django Web框架中&#xff0c;视图&#xff08;Views&#xff09;和URLs路由&#xff08;URL routing&#xff09;是Web应用开发的核心概念。它们共同负责将用户的请求映射到相应的Python函数&#xff0c;并返回适当的响应。本篇博客将深入探讨Django的视图和URLs路由系统&am…...

怎么关闭 Windows 安全中心,手动关闭 Windows Defender 教程

Windows 安全中心&#xff08;也称为 Windows Defender Security Center&#xff09;是微软 Windows 操作系统内置的安全管理工具&#xff0c;用于监控和控制病毒防护、防火墙、应用和浏览器保护等安全功能。然而&#xff0c;在某些情况下&#xff0c;用户可能需要关闭 Windows…...

洛谷看不了别人主页怎么办

首先&#xff0c;我们先点进去 可以看到&#xff0c;看不了一点 那我们看向上方&#xff0c;就可以发现&#xff0c;我们那有个URL&#xff0c;选中 把光标插到n和/中间 把.cn删了&#xff0c;变成国际服 我们就可以看了 但是国际服还没搭建完&#xff0c;跳转的时候可能503&a…...

邮件安全篇:企业电子邮件安全涉及哪些方面?

1. 邮件安全概述 企业邮件安全涉及多个方面&#xff0c;旨在保护电子邮件通信的机密性、完整性和可用性&#xff0c;防止数据泄露、欺诈、滥用及其他安全威胁。本文从身份验证与防伪、数据加密、反垃圾邮件和反恶意软件防护、邮件内容过滤与审计、访问控制与权限管理、邮件存储…...

软件测试09 自动化测试技术(Selenium)

重点/难点 重点&#xff1a;理解自动化测试的原理及其流程难点&#xff1a;Selinum自动化测试工具的使用 目录 系统测试 什么是系统测试什么是功能测试什么是性能测试常见的性能指标有哪些 自动化测试概述 测试面临的问题 测试用例数量增多&#xff0c;工作量增大&#xff…...

记录解决springboot项目上传图片到本地,在html里不能回显的问题

项目场景&#xff1a; 项目场景&#xff1a;在我的博客系统里&#xff1a;有个相册模块&#xff1a;需要把图片上传到项目里&#xff0c;在html页面上显示 解决方案 1.建一个文件夹 例如在windows系统下。可以在项目根目录下建个photos文件夹&#xff0c;把上传的图片文件…...

C++ 中 const 关键字

C 中 const 关键字 2009-02-19 2024-07-23 补充C11后的做法 在 C 中&#xff0c;const 是一个关键字&#xff08;也称为保留字&#xff09;&#xff0c;它用于指定变量或对象的值在初始化后不能被修改。关键字是编程语言中具有特殊含义的词汇&#xff0c;编译器会识别这些词并…...

客梯自动监测识别摄像机

当今社会&#xff0c;随着城市建设的快速发展&#xff0c;客梯作为现代化建筑不可或缺的一部分&#xff0c;其安全性与效率显得尤为重要。为了提升客梯的安全管理水平&#xff0c;智能监测技术应运而生&#xff0c;尤其是客梯自动监测识别摄像机系统的应用&#xff0c;为乘客和…...

为什么那么多人学习AI绘画?工资香啊!

在当今这个科技日新月异的时代&#xff0c;AI绘画作为数字艺术与人工智能融合的璀璨成果&#xff0c;正吸引着无数人投身其中&#xff0c;而“工资香啊&#xff01;”无疑是这一热潮背后不可忽视的驱动力之一。 AI绘画的高薪待遇是吸引众多学习者的关键因素。随着市场对AI艺术…...

国产JS库(js-tool-big-box)7月度总结

js-tool-big-box开发已经有3个月了&#xff0c;团队内的小伙伴进行了热烈的讨论&#xff0c;持续做了功能迭代。小伙伴们也做了艰苦卓绝的文档分享&#xff0c;有纯功能分享类的&#xff0c;有带有小故事的&#xff0c;有朋友们利用自己独自网站分发分享的。7月份快要结束了&am…...

c++ 高精度加法(只支持正整数)

再给大家带来一篇高精度&#xff0c;不过这次是高精度加法&#xff01;话不多说&#xff0c;开整&#xff01; 声明 与之前那篇文章一样&#xff0c;如果看起来费劲可以结合总代码来看 定义 由于加法进位最多进1位&#xff0c;所以我们的结果ans[]的长度定义为两个加数中最…...

python键盘操作工具:ctypes、pyautogui

这里模拟 Win Ctrl L 组合键 1、ctypes ctypes库&#xff0c;它允许我们直接调用Windows API来模拟键盘输入。 import ctypes import time# 定义所需的常量和结构 LONG ctypes.c_long DWORD ctypes.c_ulong ULONG_PTR ctypes.POINTER(DWORD) WORD ctypes.c_ushortclass…...

计算机网络发展历史

定义和基本概念 计算机网络是由多个计算设备通过通信线路连接起来的集合&#xff0c;这些设备能够互相交换数据、消息和资源。计算机网络的核心功能是实现数据的远程传输和资源共享&#xff0c;它使得地理位置的限制被大大减弱&#xff0c;极大地促进了信息的自由流动和人类社…...

记录安装android studio踩的坑 win7系统

最近在一台新电脑上安装android studio,报了很多错误&#xff0c;也是费了大劲才解决&#xff0c;发出来大家一起避免一些问题&#xff0c;找到解决方法。 安装时一定要先安装jdk&#xff0c;cmd命令行用java -version查当前的版本&#xff0c;没有的话&#xff0c;先安装jdk,g…...

Python图形编程-PyGame快速入门

PyGame快速入门 文章目录 PyGame快速入门1、什么是PyGame2、安装PyGame3、创建PyGame窗口4、处理事件5、绘制对象6、移动对象7、加载和显示图像8、播放声音9、处理用户输入10、碰撞检测11、动画精灵12、管理游戏状态13、Pygame 中的典型主游戏循环1、什么是PyGame Pygame 是一…...

邦芒宝典:8种方法调整职场心态

在职场中拼斗当然要有好的心态&#xff0c;您知道职场心态如何调整吗&#xff1f; ​ ​方法1&#xff1a;自我调整 ​“思想可以使天堂变成地狱&#xff0c;也可以使地狱变成天堂。”你不能样样顺利&#xff0c;但可以事事尽心;你不能左右天气&#xff0c;但可以改变心情;你…...

华为OD2024D卷机试题汇总,含D量50%+,按算法分类刷题,事半功倍

目录 专栏导读华为OD机试算法题太多了&#xff0c;知识点繁杂&#xff0c;如何刷题更有效率呢&#xff1f; 一、逻辑分析二、数据结构1、线性表① 数组② 双指针 2、map与list3、队列4、链表5、栈6、滑动窗口7、二叉树8、并查集9、矩阵 三、算法1、基础算法① 贪心思维② 二分查…...

Unity UGUI 之 Graphic Raycaster

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 首先手册连接如下&#xff1a; Unity - Manual: Graphic Raycaster 笔记来源于&#xff…...

类和对象——相关的零碎知识

前提提示&#xff1a; 其实C中的类和对象&#xff0c;最重要的是6个默认函数&#xff0c;如有忘记&#xff0c;请移步到&#xff1a;类和对象。本章是对于一些细节知识的补充和拓展。 1. 隐示类型转换 在运算时&#xff0c;运算符左右两边的操作数的类型不同&#xff0c;编译器…...

【hadoop大数据集群 1】

hadoop大数据集群 1 文章目录 hadoop大数据集群 1一、环境配置1.安装虚拟机2.换源3.安装工具4.安装JDK5.安装Hadoop 一、环境配置 折腾了一下午/(ㄒoㄒ)/~~ 1.安装虚拟机 参考视频&#xff1a;https://www.bilibili.com/video/BV18y4y1G7JA?p17&vd_sourcee15e83ac6b22a…...

TQSDRPI开发板教程:实现PL端的UDP回环与GPSDO

本教程将完成一个全面的UDP运行流程与GPSDO测试&#xff0c;从下载项目的源代码开始&#xff0c;通过编译过程&#xff0c;最终将项目部署到目标板卡上运行演示。此外&#xff0c;我们还介绍如何修改板卡的IP地址&#xff0c;以便更好地适应您的网络环境或项目需求。 首先从Gi…...

array.some() ==> 查找数组list中,是否有包含与当前currKey的值不一样的misId

需求&#xff1a; const list [ {misId: e, name: 小白}, {misId: e, name: 小白白}, {misId: r, name: 小王}, {misId: r, name: 小小王} ] let currKey r 查找数组list中&#xff0c;是否有包含与当前currKey的值不一样的misId 解决&#xff1a; 要查找数组lis…...

最简单的typora+gitee+picgo配置图床

typoragiteepicgo图床 你是否因为管理图片而感到头大&#xff1f;是时候了解一下 Typora、Gitee 和 PicGo 这个超级三剑客了&#xff0c;它们可以帮你轻松打造自己的图床&#xff0c;让你的博客图片管理变得简单又有趣。让我们开始这场神奇的图床之旅吧&#xff01; Typora …...

【黄啊码】GPT的相关名词解释

GPT是一种基于互联网的、可用数据来训练的、文本生成的深度学习模型 GPT的核心技术是‌变换器&#xff08;Transformer&#xff09;&#xff0c;这是一种神经网络结构&#xff0c;可以有效地处理序列数据&#xff0c;比如文本、语音、图像等。GPT使用了大量的预训练数据&#…...

git stash 命令详解

git stash 描述 git stash 命令用于将当前工作目录中的未提交更改&#xff08;包括暂存区和工作区的更改&#xff09;保存到一个栈中&#xff0c;并恢复工作目录到干净的 HEAD 状态。这样您可以在不提交当前更改的情况下&#xff0c;切换到其他分支或进行其他操作。后续可以通…...

txt格式单词导入有道词典生词本 (java代码方式)

txt格式单词导入有道词典生词本 (java代码方式) 首先要求txt文档里单词的格式&#xff0c;大概需要像这种&#xff1a; 每行是一个单词&#xff0c;格式为&#xff1a;英文单词空格词性单词意思。 注意 导出单词本的名字就是你 txt 文件的名字 我这里是 公共英语三级 单词本 …...

轨迹优化 | 基于ESDF的共轭梯度优化算法(附ROS C++/Python仿真)

目录 0 专栏介绍1 数值优化&#xff1a;共轭梯度法2 基于共轭梯度法的轨迹优化2.1 障碍约束函数2.2 曲率约束函数2.3 平滑约束函数 3 算法仿真3.1 ROS C实现3.2 Python实现 0 专栏介绍 &#x1f525;课程设计、毕业设计、创新竞赛、学术研究必备&#xff01;本专栏涉及更高阶的…...

深入浅出WebRTC—ALR

ALR&#xff08;Application Limited Region&#xff09;指的是网络传输过程中&#xff0c;由于应用层的限制&#xff08;而非网络拥塞&#xff09;导致带宽未被充分利用的情况。在这种情况下&#xff0c;应用层可能因为处理能力、手动配置或其他因素无法充分利用可用带宽&…...

BSV区块链技术现实应用原理解析

BSV区块链以其卓越的可扩展性、坚如磐石的安全性、极低的交易成本等特性&#xff0c;成为满足企业当下需求并为企业未来成功奠基铺路的理想技术。 BSV协会近期发布了一个题为《驾驭数字化转型&#xff1a;在自动化世界中建立信任——区块链在数据保护和交易优化中的角色》的报…...

七大基于比较的排序算法

目录 一、基于比较的排序算法概述 1. 插入排序&#xff08;Insertion Sort&#xff09; 2. 选择排序&#xff08;Selection Sort&#xff09; 3. 冒泡排序&#xff08;Bubble Sort&#xff09; 4. 归并排序&#xff08;Merge Sort&#xff09; 5. 快速排序&#xff08;Qu…...

web前端 React 框架面试200题(四)

面试题 97. React 两种路由模式的区别&#xff1f;hash和history&#xff1f; 参考回答&#xff1a; 1: hash路由 hash模式是通过改变锚点(#)来更新页面URL&#xff0c;并不会触发页面重新加载&#xff0c;我们可以通过window.onhashchange监听到hash的改变&#xff0c;从而处…...

5.Fabric的共识机制

在Fabric中,有以下3中典型共识机制。 Solo共识 solo共识机制只能用于单节点模式,即只能有一个Orderer节点,因此,其共识过程很简单,每接收到一个交易信息,就在共识模块的控制下产生区块并广播给节点存储到账本中。 Solo 模式下的共识只适用于一个Orderer节点,所以可以在…...

【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决

在safari浏览器中&#xff0c;可能会遇到异步时间差的问题&#xff0c;导致状态没有及时更新到state&#xff0c;引起传参错误。 PS&#xff1a;由于useState是一个普通的函数&#xff0c; 定义为() > void;因此此处不能用await/async替代setTimeout&#xff0c;只能用在返…...

京准:GPS北斗卫星授时信号安全隔离防护装置

京准&#xff1a;GPS北斗卫星授时信号安全隔离防护装置 京准&#xff1a;GPS北斗卫星授时信号安全隔离防护装置 1、主要特点 ★信号加固功能&#xff1a; GPS/BDS单系统信号拒止情况下&#xff08;包含受到GPS L1欺骗干扰、GPS L1压制干扰、BDS B1欺骗干扰、BDS B1压制干扰&…...

解决方案架构师系列 - AWS - Pinpoint

AWS Pinpoint介绍 Amazon Pinpoint 为营销人员和开发人员提供了一款可自定义的工具&#xff0c;助力他们大规模地开展跨渠道、行业和活动的客户通信。 Amazon Pinpoint是一个全面的客户参与平台&#xff0c;‌旨在帮助营销人员和开发人员大规模地开展跨渠道、‌行业和活动的客…...

MF173:将多个工作表转换成PDF文件

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…...