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

Spring AOP(详解)

目录

1.AOP概述

 2.AOP相关术语

3.Spring AOP的原理机制

3.1JDK动态代理

3.2 CGLIB动态代理

3.3简单代码展示

3.3.1JDK动态代理

3.3.2CGLIB动态代理

4.Spring的AOP配置

4.1pom.xml

4.2增强方法

4.3切点

 4.4切面

5.基于注解的AOP配置

5.1.创建工程

5.2.增强

5.3AOP配置

5.3.1常用注解


1.AOP概述

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对程序进行增强:权限校验,日志记录,性能监控,事务控制.

 2.AOP相关术语

(1)横切关注点

跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志、安全、缓存、事务等等。

(2)连接点

连接点是在应用执行中能够插入切面的一个点。即程序执行过程中能够应用通知的所有点。

(3)切点

切点是真正需要插入切面的一个或多个连接点。即通知被应用的具体位置(在哪些连接点)。通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点(比如Aspect切点表达式)。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。

(4)通知

切面的工作被称为通知。即包含了需要用于多个应用对象的横切行为。

通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。它应该应用在某个方法被调用之前?之后?之前和之后都调用?还是只在方法抛出异常时调用?

Spring切面可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能。
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
  • 返回通知(After-returning):在目标方法成功执行之后调用通知。
  • 异常通知(After-throwing)):在目标方法抛出异常后调用通知。
  • 环绕通知(Around) :通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

(5)切面

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

(6)织入

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:

  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。Aspect的织入编译器就是以这种方式织入切面的。
  • 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader) ,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving, LTW)就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时, AOP容器会为目标对象动态地创建一个代理对象(动态代理)。Spring AOP就是以这种方式织入切面的。

(7)引入

引入指的是向现有的类添加新方法或属性。

(8 )目标对象

代理的目标对象

3.Spring AOP的原理机制

Spring 的AOP 部分使用使用JDK动态代理,部分使用CGLIB来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理;如果目标对象没有实现任何接口,则会创建CGLIB动态代理。CGLIB是第三方包,从Spring4.3开始就无需再次导入包了。

3.1JDK动态代理

(1)实现原理

  JDK的动态代理是基于反射实现。JDK通过反射,生成一个代理类,这个代理类实现了原来那个类的全部接口,并对接口中定义的所有方法进行了代理。当我们通过代理对象执行原来那个类的方法时,代理类底层会通过反射机制,回调我们实现的InvocationHandler接口的invoke方法。并且这个代理类是Proxy类的子类(记住这个结论,后面测试要用)。这就是JDK动态代理大致的实现方式。

(2)优点

  1. JDK动态代理是JDK原生的,不需要任何依赖即可使用;
  2. 通过反射机制生成代理类的速度要比CGLib操作字节码生成代理类的速度更快;

(3)缺点

  1. 如果要使用JDK动态代理,被代理的类必须实现了接口,否则无法代理;
  2. JDK动态代理无法为没有在接口中定义的方法实现代理,假设我们有一个实现了接口的类,我们为它的一个不属于接口中的方法配置了切面,Spring仍然会使用JDK的动态代理,但是由于配置了切面的方法不属于接口,为这个方法配置的切面将不会被织入。
  3. JDK动态代理执行代理方法时,需要通过反射机制进行回调,此时方法执行的效率比较低;

3.2 CGLIB动态代理

(1)实现原理

  CGLib实现动态代理的原理是,底层采用了ASM字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并重写了类的所有可以重写的方法,在重写的过程中,将我们定义的额外的逻辑(简单理解为Spring中的切面)织入到方法中,对方法进行了增强。而通过字节码操作生成的代理类,和我们自己编写并编译后的类没有太大区别。

(2)优点

  1. 使用CGLib代理的类,不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类;
  2. CGLib生成的代理类是原来那个类的子类,这就意味着这个代理类可以为原来那个类中,所有能够被子类重写的方法进行代理;
  3. CGLib生成的代理类,和我们自己编写并编译的类没有太大区别,对方法的调用和直接调用普通类的方式一致,所以CGLib执行代理方法的效率要高于JDK的动态代理;

(3)缺点

  1. 由于CGLib的代理类使用的是继承,这也就意味着如果需要被代理的类是一个final类,则无法使用CGLib代理;
  2. 由于CGLib实现代理方法的方式是重写父类的方法,所以无法对final方法,或者private方法进行代理,因为子类无法重写这些方法;
  3. CGLib生成代理类的方式是通过操作字节码,这种方式生成代理类的速度要比JDK通过反射生成代理类的速度更慢;

3.3简单代码展示

3.3.1JDK动态代理

(1)抽象角色

public interface Star {/*** 唱歌*/void sing();
}

(2)真正角色

package com.by.JdkProxy;//真实角色(周杰伦)
public class RealStar implements Star {//优点:此时代码不再重复public void sing() {System.out.println("周杰伦:快使用双截棍,哼哼哈嘿....");}
}

(3)代理角色

//代理类工厂
public class ProxyFactory {//优点:此时可以代理任意类型的对象//真实角色(周杰伦)private Object realObj;public ProxyFactory(Object realObj) {this.realObj = realObj;}//获得代理对象public Object getProxyObject(){/*** Proxy:作用创建代理对象*      ClassLoader loader:类加载器*      Class<?>[] interfaces:真实角色实现的接口,根据接口生成代理类*      InvocationHandler h:增强的逻辑,即如何代理(宋吉吉要做的事)*/return Proxy.newProxyInstance(realObj.getClass().getClassLoader(),realObj.getClass().getInterfaces(),new InvocationHandler() {/**** @param proxy:代理类,一般不用* @param method:要调用的方法* @param args:调用方法时的参数* @return* @throws Throwable*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("真正的方法执行前!");System.out.println("面谈,签合同,预付款,订机票");Object result = method.invoke(realObj, args);System.out.println("真正的方法执行后!");System.out.println("收尾款");return result;}});}
}

(4)测试

public class Client {public static void main(String[] args) {//获得代理对象Star proxyObject = (Star) new ProxyFactory(new RealStar()).getProxyObject();System.out.println(proxyObject.getClass());//class com.sun.proxy.$Proxy0proxyObject.sing();}
}

3.3.2CGLIB动态代理

cglib与动态代理最大的区别就是:

  • 使用jdk动态代理的对象必须实现一个接口

  • 使用cglib代理的对象则无需实现接口

CGLIB是第三方提供的包,所以需要引入jar包的坐标:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version>
</dependency>

如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

(1)真正角色

public class RealStar{public void sing() {System.out.println("RealStar(周杰伦本人).sing()");}
}

(2)代理角色

//代理工厂
public class ProxyFactory implements MethodInterceptor {//真实角色private Object realObj;public ProxyFactory(Object realObj) {this.realObj = realObj;}/**'* 获得子类代理对象* @return*/public Object getProxyObject() {//工具类Enhancer en = new Enhancer();//设置父类en.setSuperclass(realObj.getClass());//设置回调函数en.setCallback(this);//创建子类代理对象return en.create();}/*在子类中调用父类的方法intercept方法参数说明:obj : 代理对象method : 真实对象中的方法的Method实例args : 实际参数methodProxy :代理对象中的方法的method实例*/public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)throws Throwable {System.out.println("真正的方法执行前!");System.out.println("面谈,签合同,预付款,订机票");Object result = method.invoke(realObj, args);System.out.println("真正的方法执行后!");System.out.println("收尾款");return object;}
}

(3)测试

package com.by.proxy.CglibProxy;//测试类
public class Client {public static void main(String[] args) {//获取代理对象RealStar proxyObject = (RealStar) new ProxyFactory(new RealStar()).getProxyObject();proxyObject.sing();}
}

4.Spring的AOP配置

4.1pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.by</groupId><artifactId>Spring_AOP_Xml</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- Spring常用依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.8.RELEASE</version></dependency><!--支持切点表达式 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.1.8.RELEASE</version></dependency></dependencies>
</project>

4.2增强方法

(1)创建增强类

public class MyLogAdvice {//前置通知public void before(){System.out.println("前置通知");}//后置通知【try】public void afterReturning(){System.out.println("后置通知");}//异常通知【catch】public void afterThrowing(){System.out.println("异常通知");}//最终通知【finally】public void after(){System.out.println("最终通知");}//环绕通知public void around(ProceedingJoinPoint joinPoint){try {System.out.println("方法执行前的环绕通知");joinPoint.proceed();System.out.println("方法执行后的环绕通知");} catch (Throwable throwable) {throwable.printStackTrace();}}
}

(2)配置增强类

<!--增强-->
<bean id="myLogger" class="com.by.advice.MyLogger"></bean>

4.3切点

  1. 切点表达式

    表达式语法:

    execution([修饰符] 返回值类型 包名.类名.方法名(参数))

    例如:

    execution(* com.by.service.UserService.add(..))

    execution(* com.by.service.UserService.*(..))

    execution(* com.by.service.*.*(..))

  2. 配置切点

<aop:config><!--切点--><aop:pointcut id="pointcut" expression="execution(* com.by.service.*.*(..))"/>
</aop:config>

 4.4切面

(1)增强的类型

  • aop:before:用于配置前置通知

  • aop:after-returning:用于配置后置【try】通知,它和异常通知只能有一个执行

  • aop:after-throwing:用于配置异常【catch】通知,它和后置通知只能执行一个

  • aop:after:用于配置最终【finally】通知

  • aop:around:用于配置环绕通知

 

(2)配置切面  

<!--切面-->
<aop:aspect ref="myLogger"><!-- 用于配置前置通知:指定增强的方法在切入点方法之前执行 method:用于指定通知类中的增强方法名称ponitcut-ref:用于指定切入点--><aop:before method="before" pointcut-ref="pointcut"/><aop:after-returning method="afterReturning" pointcut-ref="pointcut"/><aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/><aop:after method="after" pointcut-ref="pointcut"/><aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>

5.基于注解的AOP配置

5.1.创建工程

(1)pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.by</groupId><artifactId>Spring_AOP_Annotation</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- Spring常用依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.1.8.RELEASE</version></dependency></dependencies>
</project>

(2)dao

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.by</groupId><artifactId>Spring_AOP_Annotation</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- Spring常用依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.1.8.RELEASE</version></dependency></dependencies>
</project>

(3)service

@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;public void addUser() {userDao.addUser();}
}

(4)applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.by"></context:component-scan>
</beans>

(5)测试

/*** 模拟表现层*/
public class Client {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");//使用对象UserService userService = ac.getBean("userServiceImpl",UserService.class);userService.addUser();}
}

5.2.增强

(1)applicationContext.xml

<!-- 开启spring对注解AOP的支持 -->
<aop:aspectj-autoproxy/>

5.3AOP配置

5.3.1常用注解

  • @Aspect:把当前类声明为切面类

  • @Before:前置通知,可以指定切入点表达式

  • @AfterReturning:后置【try】通知,可以指定切入点表达式

  • @AfterThrowing:异常【catch】通知,可以指定切入点表达式

  • @After:最终【finally】通知,可以指定切入点表达式

  • @Around:环绕通知,可以指定切入点表达式

5.3.2注解方式实现aop  

@Component
@Aspect
public class MyLogger {@Before("execution(* com.by.service.*.*(..))")public void before(){System.out.println("方法开始时间:"+new Date());}@After("execution(* com.by.service.*.*(..))")public void after(){System.out.println("方法结束时间:"+new Date());}
}

相关文章:

Spring AOP(详解)

目录 1.AOP概述 2.AOP相关术语 3.Spring AOP的原理机制 3.1JDK动态代理 3.2 CGLIB动态代理 3.3简单代码展示 3.3.1JDK动态代理 3.3.2CGLIB动态代理 4.Spring的AOP配置 4.1pom.xml 4.2增强方法 4.3切点 4.4切面 5.基于注解的AOP配置 5.1.创建工程 5.2.增强 5.3AOP…...

Linux系统编程之进程

目录 1、进程关键概念 1.什么是程序&#xff0c;什么是进程&#xff0c;有什么区别 2.如何查看系统中有那些进程 3.什么是进程标识符 4.什么叫父进程&#xff0c;什么叫子进程 5.C语言的存储空间是如何分配的 2、进程创建 1.fork函数创建进程 2.vfork函数创建进程 3、…...

Vue中使用require.context自动引入组件的方法介绍

我们项目开发中&#xff0c;经常需要import或者export各种模块&#xff0c;那么有没有什么办法可以简化这种引入或者导出操作呢&#xff1f;答案是肯定的&#xff0c;下面就为大家介绍一下require.context require.context 是 webpack 提供的一个 API&#xff0c;用于创建 con…...

Java 监控诊断利器 Arthas monitor/watch/trace 命令使用详解

目录 一、命令介绍二、测试Demo三、命令使用示例3.1、monitor 命令3.1.1、监控primeFactors方法调用情况&#xff08;5秒一个周期&#xff0c;每过5秒将这5秒统计的信息输出&#xff09;3.1.2、监控primeFactors方法调用情况&#xff08;5秒一个周期&#xff0c;每过5秒将这5秒…...

论文阅读:基于MCMC的能量模型最大似然学习剖析

On the Anatomy of MCMC-Based Maximum Likelihood Learning of Energy-Based Models 相关代码&#xff1a;点击 本文只介绍关于MCMC训练的部分&#xff0c;由此可知&#xff0c;MCMC常常被用于训练EBM。最后一张图源于Implicit Generation and Modeling with Energy-Based Mod…...

【Verilog】期末复习——设计一个带异步复位端且高电平有效的32分频电路

系列文章 数值&#xff08;整数&#xff0c;实数&#xff0c;字符串&#xff09;与数据类型&#xff08;wire、reg、mem、parameter&#xff09; 运算符 数据流建模 行为级建模 结构化建模 组合电路的设计和时序电路的设计 有限状态机的定义和分类 期末复习——数字逻辑电路分…...

基于springboot的java读取文档内容(超简单)

读取一个word文档里面的内容&#xff0c;并取出来。 代码&#xff1a; SneakyThrowsGetMapping(value "/readWordDoc")ApiOperationSupport(order 1)ApiOperation(value "文档读取 ", notes "文档读取 ")public R ReadWordDoc () {System.o…...

K8S亲和性,反亲和性,及污点

nodeName&#xff1a;硬匹配&#xff0c;不走调度策略 nodeSelector&#xff1a;根据节点的标签选择&#xff0c;会走调度的算法 只要是走调度算法&#xff0c;在不满足预算策略的情况下&#xff0c;所有pod都是pending node节点的亲和性&#xff1a; 硬策略&#xff1a;必…...

2024年,AI、Web3、区块链、元宇宙:有没有“相互成就“的可能性?

加密圈最近有点冷清&#xff0c;曾经是科技界的宠儿&#xff0c;去年中旬开始一直在被SEC的诉讼困扰着&#xff0c;而且正处冷清的熊市&#xff0c;被迫居于 AI 后面的次要地位。 曾在 Web3 领域活跃并具有影响力的企业家 Jeremiah Owyang 住在旧金山&#xff0c;目前也深入研…...

Mac电脑好用的修图软件:Affinity Photo 2中文 for Mac

Affinity Photo 2提供了广泛的图像编辑和调整工具&#xff0c;使用户能够对照片进行精确的编辑和改进。它支持图像裁剪、旋转、缩放、变形等操作&#xff0c;以及曝光、色彩、对比度、饱和度等调整。 非破坏性编辑&#xff1a;软件采用非破坏性编辑方式&#xff0c;即对原始图…...

数据结构之Radix和Trie

数据结构可视化演示链接&#xff0c;也就是视频中的网址 Radix树&#xff1a;压缩后的Trie树 Radix叫做基数树&#xff08;压缩树&#xff09;&#xff0c;就是有相同前缀的字符串&#xff0c;其前缀可以作为一个公共的父节点。同时在具体存储上&#xff0c;Radix树的处理是以…...

ctrl+c与kill -2的区别

单进程场景 在单进程的情况下&#xff0c;ctrlc和kill -2是一模一样的&#xff0c;都是向指定的进程发送SIGINT信号. 如果进程中注册了捕捉SIGINT信号的处理函数&#xff0c;那么这个信号会被进程处理&#xff0c;例如&#xff1a; void processB() {// Set signal handler …...

每日算法打卡:分巧克力 day 9

文章目录 原题链接题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 题目分析示例代码 原题链接 1227. 分巧克力 题目难度&#xff1a;简单 题目来源&#xff1a;第八届蓝桥杯省赛C A/B组,第八届蓝桥杯省赛Java A/B/C组 题目描述 儿童节那天有 …...

Golang switch 语句

简介 switch 语句提供了一种简洁的方式来执行多路分支选择 基本使用 基本语法如下&#xff1a; switch expression { case value1:// 当 expression 的值等于 value1 时执行 case value2:// 当 expression 的值等于 value2 switch 的每个分支自动提供了隐式的 break&#x…...

可碧教你C++——位图

本章节是哈希的延申 可碧教你C——哈希http://t.csdnimg.cn/3R8TU 一文详解C——哈希 位图 位图是基于哈希表的原理产生的一种新的container——bitset 基于哈希映射的原理&#xff0c;我们在查找的时候&#xff0c;可以直接去定址到元素的具体位置&#xff0c;然后直接访问该…...

2024年虚拟DOM技术将何去何从?

从诞生之初谈起&#xff0c;从命令式到声明式&#xff0c;Web开发的演变之路 Web开发的起源与jQuery的统治 在Web开发的早期阶段&#xff0c;操作DOM元素主要依赖命令式编程。当时&#xff0c;jQuery因其易用性而广受欢迎。使用jQuery&#xff0c;开发者通过具体的命令操作DOM&…...

基于51单片机的恒温淋浴器控制电路设计

标题&#xff1a;基于51单片机的智能恒温淋浴器控制系统设计与实现 摘要&#xff1a; 本论文主要探讨了一种基于STC89C51单片机为核心控制器的恒温淋浴器控制系统的详细设计与实现。系统通过集成温度传感器实时监测水温&#xff0c;结合PID算法精确控制加热元件工作状态&#…...

【redis】redis的bind配置

在配置文件redis.conf中&#xff0c;默认的bind 接口是127.0.0.1&#xff0c;也就是本地回环地址。这样的话&#xff0c;访问redis服务只能通过本机的客户端连接&#xff0c;而无法通过远程连接&#xff0c; 这样可以避免将redis服务暴露于危险的网络环境中&#xff0c;防止一些…...

C++ 继承

目录 一、继承的概念及定义 1、继承的概念 2、继承定义 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员 七、复杂的菱形继承及菱形虚拟继承 1、菱形继承 2、虚拟继承 3、例题 八、继承的总结和反思…...

了解ASP.NET Core 中的文件提供程序

写在前面 ASP.NET Core 通过文件提供程序来抽象化文件系统访问。分为物理文件提供程序(PhysicalFileProvider)和清单嵌入的文件提供程序(ManifestEmbeddedFileProvider)还有复合文件提供程序(CompositeFileProvider )&#xff1b;其中PhysicalFileProvider 提供对物理文件系统…...

竞赛保研 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…...

JavaScript音视频,JavaScript简单获取电脑摄像头画面并播放

前言 本章实现JavaScript简单获取电脑摄像头画面并播放的功能 兼容性(不支持Node.js) 需要注意的是,由于涉及到用户的隐私和安全,获取用户媒体设备需要用户的明确同意,并且可能需要在用户的浏览器中启用相关的权限。在某些浏览器中,可能需要用户手动开启摄像头权限。 …...

《JVM由浅入深学习【五】 2024-01-08》JVM由简入深学习提升分享

目录 JVM何时会发生堆内存溢出&#xff1f;1. 堆内存溢出的定义2. 内存泄漏的原因3. 堆内存溢出的常见场景4. JVM参数调优5. 实际案例分析 JVM如何判断对象可以回收1.可达性分析的基本思路2.实际案例3.可以被回收的对象4.拓展&#xff0c; 谈谈 Java 中不同的引用类型? 结语感…...

FastDFS之快速入门、上手

知识概念 分布式文件系统 通过计算机网络将各个物理存储资源连接起来。通过分布式文件系统&#xff0c;将网络上任意资源以逻辑上的树形结构展现&#xff0c;让用户访问网络上的共享文件更见简便。 文件存储的变迁&#xff1a; 直连存储&#xff1a;直接连接与存储&#xf…...

Vue 中的 ref 与 reactive:让你的应用更具响应性(中)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

【数据库基础】Mysql与Redis的区别

看到一篇不错的关于“Mysql与Redis的区别”的文章&#xff0c;转过来记录下~ 文章目录 一、数据库类型二、运行机制三、什么是缓存数据库呢&#xff1f;四、优缺点比较五、区别总结六、数据可以全部直接用Redis储存吗&#xff1f;参考资料 一、数据库类型 Redis&#xff1a;NOS…...

JVM工作原理与实战(六):类的生命周期-连接阶段

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、类的生命周期 1.加载&#xff08;Loading&#xff09; 2.连接&#xff08;Linking&#xff09; 3.初始化&#xff08;Initialization&#xff09; 4.使用&#xff08;Using&…...

【OCR】 - Tesseract OCR在Windows系统中安装

Tesseract OCR 在Windows环境下安装Tesseract OCR&#xff08;Optical Character Recognition&#xff09;通常包括以下几个步骤&#xff1a; 下载Tesseract 访问Tesseract的GitHub发布页面&#xff1a;https://github.com/tesseract-ocr/tesseract/releases找到适合你操作系…...

YOLOv8改进 | 损失函数篇 | SlideLoss、FocalLoss分类损失函数助力细节涨点(全网最全)

一、本文介绍 本文给大家带来的是分类损失 SlideLoss、VFLoss、FocalLoss损失函数,我们之前看那的那些IoU都是边界框回归损失,和本文的修改内容并不冲突,所以大家可以知道损失函数分为两种一种是分类损失另一种是边界框回归损失,上一篇文章里面我们总结了过去百分之九十的…...

计算机网络试题——填空题(附答案)

在OSI模型中&#xff0c;第一层是____________层。 答案&#xff1a;物理&#xff08;Physical&#xff09; TCP协议是一种_____________连接的协议。 答案&#xff1a;面向连接&#xff08;Connection-oriented&#xff09; IPv6地址的位数是____________。 答案&#xff1a;1…...

北京做网站男生工资/大亚湾发布

报表开发过程中&#xff0c;我们经常会需要根据所选择的不同指标&#xff0c;展示不同的报表&#xff01;例如&#xff1a; 显示指标有&#xff1a;金额与合同数&#xff0c;可以根据显示指标选择的内容进行相应报表数据展示 一、环境准备 create table crm_info( crm_name var…...

网站里的横幅怎么做/百度竞价外包

Img格式文件可以使用ArcGis或者envi软件打开&#xff0c;这里介绍envi软件的安装过程。 1. 安装环境 操作系统&#xff1a;win10 软件版本&#xff1a;5.1 软件下载地址&#xff1a; 2. 安装步骤 进入软件安装包路径&#xff1b;2. 双击IDL83ENVI51win64.exe开始安装&…...

网站翻页功能/免费私人网站建设

窗体抖动案例 首先将窗体在当前屏幕居中 其次使用for循环实现都行的次数 最后利用left,top实现窗体的抖动 private void Form2_Load(object sender, EventArgs e){this.CenterToScreen();//将窗体在当前屏幕居中}private void button1_Click(object sender, EventArgs e)//…...

杭州e时代网站建设/佛山百度关键词seo外包

vue添加二级路由 1.在router文件夹下的index.js const routes [{path:/xxx,component: () > import(xxx),//添加二级路由children:[//嵌套的默认路径{path:component: () > import(xxx),redirect:}&#xff0c; {path:xxx,component: () > import(xxx),},...]},{}.…...

医院网站云服务器配置/百度关键词热搜

Linux系统中的权限管理 1.权限读取及查看 &#xff08;1&#xff09;权限查看 ls -l file 查看文件权限 ls -ld dir 查看目录权限 &#xff08;2&#xff09;权限读取 文件属性被叫作文件的元数据&#xff08;meta&#xff09; 对于文件&#xff1a; | - |rw-r--r--|…...

网站建设条件/百度推广登录入口官网

6490来自&#xff1a;上海注册&#xff1a;2009-07-05发帖&#xff1a;25&#xff0b;25840多岁开始0基础学习&#xff0c;去数据分析&#xff0c;制作网页等&#xff0c;还有救吗&#xff1f;------------------------------------------------------------------------------…...