Spring面向切面编程

目录

1.AOP概述及Spring AOP实现原理

AOP概述 

AOP的应用场景 

 AOP的作用

Spring AOP概述

 Spring AOP的实现原理

 Spring AOP中Advice的分类

 2. 通过xml配置实现AOP

实现步骤:

 新增模块:

导入相关依赖:

新增实体类User 

 新增业务类UserService

定义切面类LogAspect 

 添加Spring核心配置文件

AOP配置说明 

注册切面类

配置切面

Spring配置文件中完成切面配置

编写测试类,验证效果

运行结果:

当前的目录结构:

​编辑 

3. 通过注解实现AOP

Spring AOP注解

 通过以下注解来定义通知 

用例设计(采用注解):

 实现步骤:

新增模块:

导入相关依赖: 

新增实体类User 

新增业务类UserService 

定义切面类LogAspect 

如何获取连接点信息 

@AfterReturning 

@Around

Spring配置文件中配置AspectJ自动代理 

编写测试类 

 运行结果:

当前的目录结构如下: 


1.AOP概述及Spring AOP实现原理

AOP概述 

AOP (Aspect Oriented Programming) 面向 切面编程
AOP 是一种编程的 思想
AOP 是对 OOP ( Object Oriented Programming ,面向对象 编程 ) 补充和 完善
利用 " 横切 " 技术 ,剖解开封装的对象内部,并将那些 与业务无关 ,但却 影响多 个类的 公共行为 封装到一个 可重用模块 ,并将其命名 Aspect 切面
作用 AOP 可以减少系统的重复代码,降低模块之间的耦合度,并有利于提升项目的可操作性和 可维护性

AOP的应用场景 

日志记录 :定义切面在方法执行前、执行后或异常抛出时记录日志
事务处理 :定义切面在方法开始前开启事务,在方法执行完毕后提交事务,在方法出现异常时回滚事务。
安全控制 :定义切面在方法执行前进行权限判断,如果用户没有权限,则抛出异常或转向到错误页面,以防止未经授权的访问。
缓存控制 :定义切面在方法执行前查询缓存中是否有数据,如果有则返回,否则执行方法并将方法返回值存入缓存中。
异常处理 :定义切面在方法执行过程中,如果出现异常,则进行 异常处理

 AOP的作用

不改变原有代码前提下,增加新功能

横切关注点:跨越应用程序多个模块。与业务逻辑无关处设置需关注部分,就是横切关注点。如日志,安全,缓存,事务等等

切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。

通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

目标(Target):被通知对象。

代理(Proxy):向目标对象应用通知之后创建的对象。

切入点(PointCut):切面通知 执行的 “地点”的定义。

连接点(JointPoint):与切入点匹配的执行点。

Spring AOP概述

Spring AOPSpring框架中的一个模块,是基于AOP思想通过整合AspectJ框架实现的面向切面编程技术

AspectJ是一个面向切面编程的具体实现框架,定义了AOP的语法

 Spring AOP的实现原理

Spring AOP是基于动态代理技术实现的

在程序运行过程中,SpringAOP内部会基于JDK动态代理技术和cglib动态代理技术为目标对象生成代理对象

程序调用目标对象方法时,不是直接调用目标对象方法,而是先调用代理对象的方法,再调用目标对象的方法,从而对目标方法进行增强

 

 Spring AOP中Advice的分类

Spring AOP 通过 Advice 定义横切逻辑
支持 5 种类型的 Advice:

 

 2. 通过xml配置实现AOP

基于 Spring AOP 技术 在项目中配置 切面 实现 日志记录 的功能。
日志记录功能的具体要求如下:

1)当应用程序调用业务逻辑层组件方法之前,在控制台中打印出“开始调用方法

2)当应用程序调用业务逻辑层组件方法之后,在控制台中打印出“结束调用方法

3)当应用程序调用业务逻辑层组件方法出现了异常,在控制台中打印出“调用方法出现异常

实现步骤:

新建项目模块
整合 Spring AOP 框架 依赖
定义 切面类以及通知 方法
Spring 配置文件中完成 切面配置
运行测试类完成 切面测试

 新增模块:

打开上节的项目 spring6
新增模块 spring- aop -xml

 

导入相关依赖:

修改模块 spring- aop -xml pom.xml ,导入依赖
引入 spring-context 依赖 后,根据依赖的传递性,会自动引入 spring- aop 依赖
引入 Spring AspectJ 框架的整合依赖 spring-aspects ,因为我们要使用 AspectJ 框架的语法来进行配置切面

 xml配置如下:

<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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.flowerfog</groupId><artifactId>Spring6</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>spring-aop-xml</artifactId><packaging>war</packaging><name>spring-aop-xml Maven Webapp</name><url>http://maven.apache.org</url><dependencies><!--spring context依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.2</version></dependency><!--spring和AspectJ整合依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version></dependency><!--junit5测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version></dependency><!--lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency></dependencies><build><finalName>spring-aop-xml</finalName></build>
</project>

新增实体类User 

package org.flowerfog.pojo;import lombok.Data;@Data
public class User {private Integer id;private String name;private String account;private String password;private Integer status;
}

 新增业务类UserService

package org.flowerfog.Service;import org.flowerfog.pojo.User;public class UserService {public void add(User user) {System.out.println("新增用户" + user);}public void removeById(Integer id) {System.out.println("删除Id=" + id + "的用户");}
}

定义切面类LogAspect 

package org.flowerfog.comm;public class LogAspect {// 前置通知public void before(){System.out.println("开始调用方法");}// 后置通知public void after(){System.out.println("结束调用方法");}// 异常通知public void exception(Exception ex){System.out.println("调用方法出席异常"+ex.getMessage());}
}

 添加Spring核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

AOP配置说明 

注册切面类

配置切面

标签元素

作用

<aop:config>

AOP配置顶层节点,一个配置文件中可以包含多个<aop:config>节点

<aop:aspect>

配置切面该元素会将Spring容器中的Bean转换成切面Bean

<aop:pointcut>

配置切点,通过id属性指定切点唯一标识,通过expression属性指定切点表达式

 

 

Spring配置文件中完成切面配置

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注册Bean--><bean id="userService" class="org.flowerfog.Service.UserService" /><bean id="logAspect" class="org.flowerfog.comm.LogAspect" /><!--AOP配置,需导入aop约束--><aop:config><!--配置切点--><aop:pointcut id="pointcut" expression="execution(* org.flowerfog.Service.*.*(..))"/><!--配置切面Bean--><aop:aspect ref="logAspect"><aop:before method="before" pointcut-ref="pointcut" /><aop:after method="after" pointcut-ref="pointcut" /><aop:after-throwing method="exception" pointcut-ref="pointcut" throwing="ex" /></aop:aspect></aop:config>
</beans>

编写测试类,验证效果


import org.flowerfog.Service.UserService;
import org.flowerfog.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {@Testpublic void add() {// 加载Spring核心配置文件ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");// 获取bean对象UserService userService = (UserService) ctx.getBean("userService");User user = new User();user.setName("张三");user.setAccount("111");user.setPassword("123456");user.setStatus(0);userService.add(user);}
}

运行结果:

当前的目录结构:

 

3. 通过注解实现AOP

Spring 基于注解配置 AOP 需要 启用 AspectJ 自动代理 功能
启用 该功能后, Spring 框架会自动扫描应用程序中所有被 AOP 注解标记的类 , 并自动创建 AOP 代理 对象
Spring 配置文件中添加如下配置:

Spring AOP注解

@Aspect定义切面

切面类需注册到Spring容器@Aspect注解才能生效

@Pointcut定义切点

切面类中定义一个空方法并使用@Pointcut注解来定义切点

然后在@Pointcut注解中定义切点表达式用来匹配切入的目标类和方法

空方法的方法名就是切点的唯一标识id

 通过以下注解来定义通知 

 

用例设计(采用注解):

基于 Spring AOP 技术 在项目中配置 切面 实现 日志记录 的功能。
日志记录功能的具体要求如下:

1)当应用程序调用业务逻辑层组件方法之前,在控制台中打印出“开始调用方法

2)当应用程序调用业务逻辑层组件方法之后,在控制台中打印出“结束调用方法

3)当应用程序调用业务逻辑层组件方法出现了异常,在控制台中打印出“调用方法出现异常

 

 实现步骤:

新建项目模块

整合Spring AOP框架依赖

定义切面类以及通知方法

添加注解完成切面配置

运行测试类完成切面测试

新增模块:

新增模块 spring- aop -annotation

导入相关依赖: 

修改模块的 pom.xml ,导入依赖
引入 spring-context 依赖 后,根据依赖的传递性,会自动引入 spring- aop 依赖
引入 Spring AspectJ 框架的整合依赖 spring-aspects ,因为我们要使用 AspectJ 框架的语法来进行配置切面

 

<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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.flowerfog</groupId><artifactId>Spring6</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>spring-aop-annotation</artifactId><packaging>war</packaging><name>spring-aop-annotation Maven Webapp</name><url>https://maven.apache.org</url><dependencies><!--spring context依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.2</version></dependency><!--spring和AspectJ整合依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.2</version></dependency><!--junit5测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version></dependency><!--lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency></dependencies><build><finalName>spring-aop-annotation</finalName></build>
</project>

新增实体类User 

package org.flowerfog.pojo;import lombok.Data;@Data
public class User {private Integer id;private String name;private String account;private String password;private Integer status;
}

新增业务类UserService 

package org.flowerfog.Service;import org.flowerfog.pojo.User;public class UserService {public void add(User user) {System.out.println("新增用户" + user);}public void removeById(Integer id) {System.out.println("删除Id=" + id + "的用户");}
}

定义切面类LogAspect 

package org.flowerfog.comm;import org.aspectj.lang.annotation.*;// 定义切面
@Aspect
public class LogAspect {// 定义切点,其id为pointcut@Pointcut("execution(* org.flowerfog.Service.*.*(..))")public void pointcut(){}// 前置通知@Before("pointcut()")public void before(){System.out.println("开始调用方法");}// 后置通知@After("pointcut()")public void after(){System.out.println("结束调用方法");}// 异常通知@AfterThrowing(value = "pointcut()",throwing = "ex")public void exception(Exception ex){System.out.println("调用方法出现异常"+ex.getMessage());}
}

如何获取连接点信息 

通过切面对象方法的形参能获取连接点信息
数据类型为 JoinPoint

 

环绕通知可使用增强类型 ProceedingJoinPoint ,其 proceed() 执行连接点拦截到的方法

@AfterReturning 

在切面类中添加返回通知的代码

 LogAspect当前代码如下:

package org.flowerfog.comm;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.util.ObjectUtils;import java.lang.reflect.Method;// 定义切面
@Aspect
public class LogAspect {// 定义切点,其id为pointcut@Pointcut("execution(* org.flowerfog.Service.*.*(..))")public void pointcut(){}// 前置通知@Before("pointcut()")public void before(){System.out.println("开始调用方法");}// 后置通知@After("pointcut()")public void after(){System.out.println("结束调用方法");}// 异常通知@AfterThrowing(value = "pointcut()",throwing = "ex")public void exception(Exception ex){System.out.println("调用方法出现异常"+ex.getMessage());}// 返回通知@AfterReturning("pointcut()")public void afterReturn(JoinPoint joinPoint){MethodSignature signature=(MethodSignature)joinPoint.getSignature(); // 获得目标对象的签名,及当前拦截到的方法Method method=signature.getMethod();String longString = joinPoint.toLongString();// 获得连接点的扩展全命名Object[] args = joinPoint.getArgs();// 返回连接点的参数数组Object target = joinPoint.getTarget();// 获得目标对象Object aThis = joinPoint.getThis();// 获得正在执行的目标对象JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();// 获得连接点的静态部分SourceLocation sourceLocation = joinPoint.getSourceLocation();// 获得连接点对应的方法源地址String shortString = joinPoint.toShortString();// 获得连接点的缩写命名String kind = joinPoint.getKind();// 返回连接点的类型System.out.println("method:"+method+"\r\nlongString:"+longString);if (!ObjectUtils.isEmpty(args)) {for (Object arg : args) {System.out.println(arg);}}System.out.println("调用方法ok");}}

@Around

在切面类中添加环绕通知的代码

 最终LogAspect代码如下:

package org.flowerfog.comm;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.util.ObjectUtils;import java.lang.reflect.Method;// 定义切面
@Aspect
public class LogAspect {// 定义切点,其id为pointcut@Pointcut("execution(* org.flowerfog.Service.*.*(..))")public void pointcut(){}// 前置通知@Before("pointcut()")public void before(){System.out.println("开始调用方法");}// 后置通知@After("pointcut()")public void after(){System.out.println("结束调用方法");}// 异常通知@AfterThrowing(value = "pointcut()",throwing = "ex")public void exception(Exception ex){System.out.println("调用方法出现异常"+ex.getMessage());}// 返回通知@AfterReturning("pointcut()")public void afterReturn(JoinPoint joinPoint){MethodSignature signature=(MethodSignature)joinPoint.getSignature(); // 获得目标对象的签名,及当前拦截到的方法Method method=signature.getMethod();String longString = joinPoint.toLongString();// 获得连接点的扩展全命名Object[] args = joinPoint.getArgs();// 返回连接点的参数数组Object target = joinPoint.getTarget();// 获得目标对象Object aThis = joinPoint.getThis();// 获得正在执行的目标对象JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();// 获得连接点的静态部分SourceLocation sourceLocation = joinPoint.getSourceLocation();// 获得连接点对应的方法源地址String shortString = joinPoint.toShortString();// 获得连接点的缩写命名String kind = joinPoint.getKind();// 返回连接点的类型System.out.println("method:"+method+"\r\nlongString:"+longString);if (!ObjectUtils.isEmpty(args)) {for (Object arg : args) {System.out.println(arg);}}System.out.println("调用方法ok");}@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {//开始时间long beginTime = System.currentTimeMillis();//执行目标方法Object result = joinPoint.proceed();//执行时长(毫秒)long time = System.currentTimeMillis()-beginTime;System.out.println("执行时长(毫秒):"+time);return  result;}}

Spring配置文件中配置AspectJ自动代理 

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注册Bean--><bean id="userService" class="org.flowerfog.Service.UserService" /><bean id="logAspect" class="org.flowerfog.comm.LogAspect" /><!--启用AspectJ自动代理--><aop:aspectj-autoproxy />
</beans>

编写测试类 


import org.flowerfog.Service.UserService;
import org.flowerfog.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserServiceTest {@Testpublic void add() {// 加载Spring核心配置文件ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");// 获取bean对象UserService userService = (UserService) ctx.getBean("userService");User user = new User();user.setName("李四");user.setAccount("222");user.setPassword("123456");user.setStatus(0);userService.add(user);}
}

 运行结果:

当前的目录结构如下: 

至此, AOP演示结束。。。。。。。。

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

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

相关文章

Javaweb选课系统-开源计划-起源-001-完全免费开源

项目部署&#xff0c;效果视频 https://www.bilibili.com/video/BV1LMDUY8Ef7/?spm_id_from333.880.my_history.page.click&vd_source17d16b2e328f19328e077e9cb07565ef项目地址&#xff1a; https://gitee.com/lucky-six/Javaweb-xuanke

【简信CRM-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

Linux云计算 |【第五阶段】PROJECT3-DAY1

主要内容&#xff1a; 跳板机&#xff08;堡垒机&#xff09;的概念、部署JumpeServer 一、跳板机&#xff08;堡垒机&#xff09;的概念 跳板机&#xff08;Jump Server 或 Bastion Host&#xff09;是一种网络安全设备或服务器&#xff0c;也称堡垒机&#xff0c;是一类可作…

宠物空气净化器哪个牌子好?希喂、352两款产品吸力、噪音真实测试

我身为养宠博主&#xff0c;这些年用过不少宠物空气净化器&#xff0c;花费了1w&#xff0c;对很多产品都进行过测评。正值双十一&#xff0c;很多朋友都在问我宠物空气净化器到底有没有必要买&#xff1f;答案毫无疑问是有必要&#xff01; 相比较于其他清理工具&#xff0c;…

Clang-Tidy 是什么?如何让你的代码更干净无瑕

Clang-Tidy&#xff1a;让你的代码更干净&#xff0c;让潜在问题无处遁形 在现代软件开发中&#xff0c;代码质量不再仅仅体现在功能实现上&#xff0c;还包括其可维护性、可读性和潜在问题的检测。clang-tidy 是一款功能强大的静态分析工具&#xff0c;专为 C/C 代码而生&…

微服务中常用分布式锁原理及执行流程

1.什么是分布式锁 分布式锁是一种在分布式系统环境下实现的锁机制&#xff0c;它主要用于解决&#xff0c;多个分布式节点之间对共享资源的互斥访问问题&#xff0c;确保在分布式系统中&#xff0c;即使存在有多个不同节点上的进程或线程&#xff0c;同一时刻也只有一个节点可…

【算法】(Python)动态规划

动态规划&#xff1a; dynamic programming。"programming"指的是一种表格法&#xff0c;而非编写计算机程序。通常解决最优化问题&#xff08;optimization problem&#xff09;。将问题拆分成若干个子问题&#xff0c;求解各子问题来得到原问题的解。适用于多阶段…

PySpark本地开发环境搭建

一.前置事项 请注意&#xff0c;需要先实现Windows的本地JDK和Hadoop的安装。 二.windows安装Anaconda 资源&#xff1a;Miniconda3-py38-4.11.0-Windows-x86-64&#xff0c;在window使用的Anaconda资源-CSDN文库 右键以管理员身份运行&#xff0c;选择你的安装路径&#x…

深度学习经典模型之ZFNet

1 ZFNet 1.1 模型介绍 ​ ZFNet是由 M a t t h e w Matthew Matthew D . Z e i l e r D. Zeiler D.Zeiler和 R o b Rob Rob F e r g u s Fergus Fergus在AlexNet基础上提出的大型卷积网络&#xff0c;在2013年ILSVRC图像分类竞赛中以11.19%的错误率获得冠军&#xff08;实际…

2024网盘搜索引擎合集推荐:高效搜索资源的利器

2024网盘搜索引擎合集推荐&#xff1a;高效搜索资源的利器 在这个信息爆炸的时代&#xff0c;找到合适的资源变得越来越重要。以下是一些网盘搜索引擎的推荐&#xff0c;它们可以帮助您快速找到所需的文件和资料。 咔帕搜索&#xff1a;简单高效的云盘搜索 网址&#xff1a;…

最新榜单!国内免费好用的OA协同软件前十名

在现代企业管理中&#xff0c;OA&#xff08;Office Automation&#xff09;协同软件已成为提升工作效率、简化沟通流程的重要工具。OA协同软件的主要功能涵盖任务管理、文件共享、审批流程、日程安排等&#xff0c;从而帮助企业更高效地进行跨部门协作、信息传递和项目跟踪。在…

Java自动点名器实现案例详解

Java自动点名器实现案例详解 在教学管理中&#xff0c;点名是一项重要的任务。随着技术的发展&#xff0c;使用编程语言实现自动化的点名器不仅可以提高效率&#xff0c;还能增加课堂的互动性和趣味性。本文将详细介绍三个案例&#xff0c;分别是简单随机点名器、带有权重的随…

揭秘规则引擎:如何实现多版本无感切换与数据源同步

在现代业务系统中&#xff0c;规则决策引擎能够自动化处理复杂的业务逻辑。为了满足不断变化的业务需求&#xff0c;同时确保系统运行的连续性和稳定性&#xff0c;在JVS规则引擎中提供了多版本无感发布和数据源变更日志同步功能。 多版本无感发布 多版本无感发布主要适用于已…

【Python3】【力扣题】409. 最长回文串

【力扣题】题目描述&#xff1a; &#xff08;题意理解&#xff09;统计如下&#xff1a; ① 字母个数本身是偶数。 ② 字母个数是奇数&#xff0c;统计奇数中的偶数部分&#xff0c;例如&#xff1a;字母个数为3&#xff0c;统计其中的2。 ③ 中间可以有一个奇数字母。即只要有…

010 Editor下载安装和使用

010 Editor下载安装和使用 010 Editor&#xff08;也称为 SweetScape 010 Editor&#xff09;是一款功能强大的二进制文件编辑器和文本编辑器。它主要用于查看、编辑和分析各种二进制文件和文本文件&#xff0c;特别适用于处理数据恢复、磁盘编辑、编程和系统管理等领域。 1 …

【安装教程】统信UOS1070上使用vsftpd服务上传下载文件

原文链接&#xff1a;【安装教程】统信UOS1070上使用vsftpd服务上传下载文件 Hello&#xff0c;大家好啊&#xff01;今天带来一篇关于在统信UOS 1070上使用vsftpd服务实现加密文件上传和下载的文章。默认的FTP传输是不加密的&#xff0c;但在数据传输时&#xff0c;安全性尤为…

Linux之实战命令70:chcon应用实例(一百零四)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

99.9%高质量Tick数据复盘回测ea必备工具:Tick Data Suite 使用教程

Tick Data Suite 是一款高质量的99.9% Tick 数据回测工具&#xff0c;功能强大&#xff0c;适用于进行EA回测。它具有以下主要优势&#xff1a;Tick 数据占用硬盘空间较小&#xff0c;可模拟滑点和实盘延时&#xff0c;还能设置持仓过夜费和交易手续费。Tick 数据来源多样&…

算法练习:1004. 最大连续1的个数 III

题目链接&#xff1a;1004. 最大连续1的个数 III。 题目要求&#xff0c;给定一个数组&#xff0c;这个数组里面只有0或1&#xff0c;然后计算有多少个连续的1的最大长度&#xff0c;同时给了一个条件就是&#xff0c;可以把k个0变成1&#xff0c;然后来计算长度。 暴力解法&a…

Unity网络开发基础(part5.网络协议)

目录 前言 网络协议概述 OSI模型 OSI模型的规则 第一部分 物理层 数据链路层 网络层 传输层 第二部分 ​编辑 应用层 表示层 会话层 每层的职能 TCP/IP协议 TCP/IP协议的规则 TCP/IP协议每层的职能 TCP/IP协议中的重要协议 TCP协议 三次握手 四次挥手 U…