SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(二)
文章目录
- 系列文档索引
- 四、Spring AOP的使用入门
- 1、激活AspectJ模块
- (1)注解激活
- (2)XML激活
- 2、创建 @AspectJ 代理(了解)
- (1)编程方式创建 @AspectJ 代理实例
- (2)XML 配置创建 AOP 代理
- (3)标准代理工厂 API
- 3、Pointcut 使用
- (1)Pointcut 指令与表达式
- (2)XML 配置 Pointcut
- (3)API 实现 Pointcut
- 4、拦截动作
- (1)注解方式实现
- (2)XML配置方式实现
- (3)API方式实现
- (4)同一个@Before执行顺序
- 未完待续
- 参考资料
系列文档索引
SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(一)
SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(二)
SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(三)
SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(四)
四、Spring AOP的使用入门
1、激活AspectJ模块
激活AspectJ模块分两种方式,一种是使用注解方式,一种使用xml方式。
• 注解激活 - @EnableAspectJAutoProxy
• XML 配置 - <aop:aspectj-autoproxy/>
(1)注解激活
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Aspect // 声明为 Aspect 切面
@Configuration // Configuration class
@EnableAspectJAutoProxy // 激活 Aspect 注解自动代理
public class AspectJAnnotationDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(AspectJAnnotationDemo.class);context.refresh();AspectJAnnotationDemo aspectJAnnotationDemo = context.getBean(AspectJAnnotationDemo.class);System.out.println(aspectJAnnotationDemo.getClass());context.close();}
}
以上是使用注解激活的实例,使用@EnableAspectJAutoProxy即可激活Aspect注解自动代理。
该AspectJAnnotationDemo类使用@Configuration标注代表是一个配置类,Spring中的配置类都会被代理,默认是使用CGLIB代理。
@Aspect表示该类是一个切面类。
(2)XML激活
在xml文件中使用该标签,即可激活Aspect自动代理:
<aop:aspectj-autoproxy/>
该标签与注解的@EnableAspectJAutoProxy效果相同。
2、创建 @AspectJ 代理(了解)
(1)编程方式创建 @AspectJ 代理实例
实现类: org.springframework.aop.aspectj.annotation.AspectJProxyFactory
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.framework.AopContext;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class AspectJAnnotationUsingAPIDemo {public static void main(String[] args) {// 通过创建一个 HashMap 缓存,作为被代理对象Map<String, Object> cache = new HashMap<>();// 创建 Proxy 工厂(AspectJ)AspectJProxyFactory proxyFactory = new AspectJProxyFactory(cache);// 增加 Aspect 配置类,暂时不需要
// proxyFactory.addAspect(AspectConfiguration.class);// 设置暴露代理对象到 AopContextproxyFactory.setExposeProxy(true);proxyFactory.addAdvice(new MethodBeforeAdvice() {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {if ("put".equals(method.getName()) && args.length == 2) {Object proxy = AopContext.currentProxy();System.out.printf("[MethodBeforeAdvice] 当前存放是 Key: %s , Value : %s ," +"代理对象:%s\n", args[0], args[1], proxy);}}});// 添加 AfterReturningAdviceproxyFactory.addAdvice(new AfterReturningAdvice() {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target)throws Throwable {if ("put".equals(method.getName()) && args.length == 2) {System.out.printf("[AfterReturningAdvice] 当前存放是 Key: %s , 新存放的 Value : %s , 之前关联的 Value : %s\n ",args[0], // keyargs[1], // new valuereturnValue // old value);}}});// 通过代理对象存储数据Map<String, Object> proxy = proxyFactory.getProxy();proxy.put("1", "A");proxy.put("1", "B");System.out.println(cache.get("1"));}
}
(2)XML 配置创建 AOP 代理
<aop:aspectj-autoproxy/><bean id="echoService" class="com.demo.DefaultEchoService"></bean><!--拦截器-->
<bean id="echoServiceMethodInterceptor"class="com.demo.interceptor.EchoServiceMethodInterceptor"/><bean id="echoServiceProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="targetName" value="echoService"/> <!--指定targetName为需要代理的bean的Id--><property name="interceptorNames"> <!--指定拦截器--><value>echoServiceMethodInterceptor</value></property>
</bean>
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;public class EchoServiceMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();System.out.println("拦截 EchoService 的方法:" + method);return invocation.proceed();}
}
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;@Aspect // 声明为 Aspect 切面
@Configuration // Configuration class
public class ProxyFactoryBeanDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/META-INF/spring-aop-context.xml");EchoService echoService = context.getBean("echoServiceProxyFactoryBean", EchoService.class);System.out.println(echoService.echo("Hello,World"));System.out.println(echoService.getClass());context.close();}
}
我们发现,这种方式与编程的方式创建代理是差不多的,只不过是对象的创建交给Spring来处理了。
(3)标准代理工厂 API
实现类 - org.springframework.aop.framework.ProxyFactory
上面XML配置的方式创建ProxyFactoryBean,更多用于Spring中的应用,而ProxyFactory更偏底层。
import org.springframework.aop.framework.ProxyFactory;/*** ProxyFactory使用示例*/
public class ProxyFactoryDemo {public static void main(String[] args) {DefaultEchoService defaultEchoService = new DefaultEchoService();// 注入目标对象(被代理)ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);//proxyFactory.setTargetClass(DefaultEchoService.class);// 添加 Advice 实现 MethodInterceptor < Interceptor < AdviceproxyFactory.addAdvice(new EchoServiceMethodInterceptor());// 获取代理对象EchoService echoService = (EchoService) proxyFactory.getProxy();System.out.println(echoService.echo("Hello,World"));}
}
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;public class EchoServiceMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();System.out.println("拦截 EchoService 的方法:" + method);return invocation.proceed();}
}
3、Pointcut 使用
Spring中的Pointcut只支持方法级别的定义,也就是说只支持Bean的方法拦截。
Pointcut 只是一个筛选,并没有具体的动作。
Advice才是具体的动作,一个Pointcut 可以对应多个Advice。
(1)Pointcut 指令与表达式
Spring AOP 之 aspect表达式详解
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** Pointcut 示例*/
@Configuration // Configuration class
@EnableAspectJAutoProxy // 激活 Aspect 注解自动代理
public class AspectJAnnotatedPointcutDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(AspectJAnnotatedPointcutDemo.class,AspectConfiguration.class);context.refresh();AspectJAnnotatedPointcutDemo aspectJAnnotationDemo = context.getBean(AspectJAnnotatedPointcutDemo.class);aspectJAnnotationDemo.execute();context.close();}public void execute() {System.out.println("execute()...");}
}
/*** Aspect 配置类*/
@Aspect
public class AspectConfiguration {@Pointcut("execution(public * *(..))") // 匹配 Join Pointprivate void anyPublicMethod() { // 方法名即 Pointcut 名System.out.println("@Pointcut at any public method."); // 方法通常设置为空的,不会有具体的动作}@Before("anyPublicMethod()") // Join Point 拦截动作public void beforeAnyPublicMethod() {System.out.println("@Before any public method.");}}
Pointcut定义在切面类的私有方法上,该方法没有任何的动作,只是筛选要切入的方法。该方法名即为Pointcut名。
(2)XML 配置 Pointcut
<!--定义配置类-->
<bean id="aspectXmlConfig" class="com.demo.AspectXmlConfig"/><aop:config><aop:aspect id="AspectXmlConfig" ref="aspectXmlConfig"><!--引用配置类--><aop:pointcut id="anyPublicMethod" expression="execution(public * *(..))"/><!--Pointcut--><aop:before method="beforeAnyPublicMethod" pointcut-ref="anyPublicMethod"/><!--配置类的方法--></aop:aspect>
</aop:config>
public class AspectXmlConfig {public void beforeAnyPublicMethod() {System.out.println("@Before any public method.");}
}
(3)API 实现 Pointcut
核心 API - org.springframework.aop.Pointcut
• org.springframework.aop.ClassFilter
• org.springframework.aop.MethodMatcher
适配实现 - DefaultPointcutAdvisor
public static void main(String[] args) {EchoServicePointcut echoServicePointcut = new EchoServicePointcut("echo", EchoService.class);// 将 Pointcut 适配成 AdvisorDefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(echoServicePointcut, new EchoServiceMethodInterceptor());DefaultEchoService defaultEchoService = new DefaultEchoService();ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);// 添加 AdvisorproxyFactory.addAdvisor(advisor);// 获取代理对象EchoService echoService = (EchoService) proxyFactory.getProxy();System.out.println(echoService.echo("Hello,World"));
}
public class EchoServicePointcut extends StaticMethodMatcherPointcut {private String methodName;private Class targetClass;public EchoServicePointcut(String methodName, Class targetClass) {this.methodName = methodName;this.targetClass = targetClass;}@Overridepublic boolean matches(Method method, Class<?> targetClass) {return Objects.equals(methodName, method.getName())&& this.targetClass.isAssignableFrom(targetClass);}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Class getTargetClass() {return targetClass;}public void setTargetClass(Class targetClass) {this.targetClass = targetClass;}
}
public class EchoServiceMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();System.out.println("拦截 EchoService 的方法:" + method);return invocation.proceed();}
}
4、拦截动作
Around环绕动作。
Before前置动作。
After后置动作:
• 方法返回后:AfterReturning
• 异常发生后:AfterThrowing
• finally 执行:After
(1)注解方式实现
@Aspect
@Order
public class AspectConfiguration {@Pointcut("execution(public * *(..))") // 匹配 Join Pointprivate void anyPublicMethod() { // 方法名即 Pointcut 名System.out.println("@Pointcut at any public method.");}@Around("anyPublicMethod()") // Join Point 拦截动作public Object aroundAnyPublicMethod(ProceedingJoinPoint pjp) throws Throwable {System.out.println("@Around any public method.");return pjp.proceed();}@Before("anyPublicMethod()") // Join Point 拦截动作public void beforeAnyPublicMethod() {Random random = new Random();if (random.nextBoolean()) {throw new RuntimeException("For Purpose.");}System.out.println("@Before any public method.");}@After("anyPublicMethod()")public void finalizeAnyPublicMethod() {System.out.println("@After any public method.");}@AfterReturning("anyPublicMethod()")// AspectJAfterReturningAdvice is AfterReturningAdvice// 一个 AfterReturningAdviceInterceptor 关联一个 AfterReturningAdvice// Spring 封装 AfterReturningAdvice -> AfterReturningAdviceInterceptor// AfterReturningAdviceInterceptor is MethodInterceptor// AfterReturningAdviceInterceptor// -> AspectJAfterReturningAdvice// -> AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgspublic void afterAnyPublicMethod() {System.out.println("@AfterReturning any public method.");}@AfterThrowing("anyPublicMethod()")public void afterThrowingAnyPublicMethod() {System.out.println("@AfterThrowing any public method");}public String toString() {return "AspectConfiguration";}private int getValue() {return 0;}
}
(2)XML配置方式实现
<aop:config><!-- <aop:pointcut id="allPointcut" expression="execution(* * *(..))"/>--><aop:aspect id="AspectXmlConfig" ref="aspectXmlConfig"><aop:pointcut id="anyPublicMethod" expression="execution(public * *(..))"/><aop:around method="aroundAnyPublicMethod" pointcut-ref="anyPublicMethod"/><aop:around method="aroundAnyPublicMethod" pointcut="execution(public * *(..))"/><aop:before method="beforeAnyPublicMethod" pointcut-ref="anyPublicMethod"/><aop:before method="beforeAnyPublicMethod" pointcut="execution(public * *(..))"/><aop:after method="finalizeAnyPublicMethod" pointcut-ref="anyPublicMethod"/><aop:after-returning method="afterAnyPublicMethod" pointcut-ref="anyPublicMethod"/><aop:after-throwing method="afterThrowingAnyPublicMethod" pointcut-ref="anyPublicMethod"/></aop:aspect>
</aop:config>
public class AspectXmlConfig {public Object aroundAnyPublicMethod(ProceedingJoinPoint pjp) throws Throwable {Random random = new Random();if (random.nextBoolean()) {throw new RuntimeException("For Purpose from XML configuration.");}System.out.println("@Around any public method : " + pjp.getSignature());return pjp.proceed();}public void beforeAnyPublicMethod() {System.out.println("@Before any public method.");}public void finalizeAnyPublicMethod() {System.out.println("@After any public method.");}public void afterAnyPublicMethod() {System.out.println("@AfterReturning any public method.");}public void afterThrowingAnyPublicMethod() {System.out.println("@AfterThrowing any public method.");}
}
(3)API方式实现
为什么 Spring AOP 不需要设计 Around Advice
• AspectJ @Around 与 org.aspectj.lang.ProceedingJoinPoint 配合执行被代理方法
• ProceedingJoinPoint#proceed() 方法类似于 Java Method#invoke(Object,Object…)
• Spring AOP 底层 API ProxyFactory 可通过 addAdvice 方法与 Advice 实现关联
• 接口 Advice 是 Interceptor 的父亲接口,而接口 MethodInterceptor 又扩展了 Interceptor
• MethodInterceptor 的invoke 方法参数 MethodInvocation 与 ProceedingJoinPoint 类似
API 实现 Before Advice
核心接口 - org.springframework.aop.BeforeAdvice
类型:标记接口,与 org.aopalliance.aop.Advice 类似
方法 JoinPoint 扩展 - org.springframework.aop.MethodBeforeAdvice
接受对象 - org.springframework.aop.framework.AdvisedSupport
• 基础实现类 - org.springframework.aop.framework.ProxyCreatorSupport
• 常见实现类:org.springframework.aop.framework.ProxyFactory;org.springframework.aop.framework.ProxyFactoryBean;org.springframework.aop.aspectj.annotation.AspectJProxyFactory
API 实现三种 After Advice
核心接口 - org.springframework.aop.AfterAdvice
类型:标记接口,与 org.aopalliance.aop.Advice 类似
扩展
• org.springframework.aop.AfterReturningAdvice
• org.springframework.aop.ThrowsAdvice
接受对象 - org.springframework.aop.framework.AdvisedSupport
• 基础实现类 - org.springframework.aop.framework.ProxyCreatorSupport
• 常见实现类:org.springframework.aop.framework.ProxyFactory;org.springframework.aop.framework.ProxyFactoryBean;org.springframework.aop.aspectj.annotation.AspectJProxyFactory
// 通过创建一个 HashMap 缓存,作为被代理对象
Map<String, Object> cache = new HashMap<>();
// 创建 Proxy 工厂(AspectJ)
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(cache);
// 增加 Aspect 配置类,此处不需要
// proxyFactory.addAspect(AspectConfiguration.class);
// 设置暴露代理对象到 AopContext
proxyFactory.setExposeProxy(true);
proxyFactory.addAdvice(new MethodBeforeAdvice() {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {if ("put".equals(method.getName()) && args.length == 2) {Object proxy = AopContext.currentProxy();System.out.printf("[MethodBeforeAdvice] 当前存放是 Key: %s , Value : %s ," +"代理对象:%s\n", args[0], args[1], proxy);}}
});// 添加 AfterReturningAdvice
proxyFactory.addAdvice(new AfterReturningAdvice() {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target)throws Throwable {if ("put".equals(method.getName()) && args.length == 2) {System.out.printf("[AfterReturningAdvice] 当前存放是 Key: %s , 新存放的 Value : %s , 之前关联的 Value : %s\n ",args[0], // keyargs[1], // new valuereturnValue // old value);}}
});// 通过代理对象存储数据
Map<String, Object> proxy = proxyFactory.getProxy();
proxy.put("1", "A");
proxy.put("1", "B");
System.out.println(cache.get("1"));
(4)同一个@Before执行顺序
注解驱动:使用@Order注解标注切面类,同一类中的顺序无法保证。
XML驱动:按照先后顺序执行。
未完待续
参考资料
极客时间《小马哥讲 Spring AOP 编程思想》
相关文章:
SpringAOP从入门到源码分析大全,学好AOP这一篇就够了(二)
文章目录系列文档索引四、Spring AOP的使用入门1、激活AspectJ模块(1)注解激活(2)XML激活2、创建 AspectJ 代理(了解)(1)编程方式创建 AspectJ 代理实例(2)XM…...
华为OD机试 - 斗地主(C++) | 附带编码思路 【2023】
刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…...
【存储】etcd的存储是如何实现的(3)-blotdb
前两篇分别介绍了etcd的存储模块以及mvcc模块。在存储模块中,提到了etcd kv存储backend是基于boltdb实现的,其在boltdb的基础上封装了读写事务,通过内存缓存批量将事务刷盘,提升整体的写入性能。botldb是etcd的真正的底层存储。本…...
基于MATLAB开发AUTOSAR软件应用层模块-part21.SR interface通信介绍(包括isupdated判断通信)
这篇文章我们介绍最后一种interface,即Sender-Receiver Interface,这种通信方式是autosar架构中最常用的的通信方式,即一个SWC发送数据,另一个SWC接收数据,实现数据交互。下边我们介绍下这篇文章主要介绍的内容: 目录如下: 如何配置SR interface,实现SR 通信介绍含有…...
Kotlin新手教程八(泛型)
一、泛型 1.泛型类的创建与实例化 kotlin中泛型类的创建与实例化与Java中相似: class A<T>(t:T){var valuet }fun main() {var a:A<Int> A<Int>(11) }Kotlin中存在类型推断,所以创建实例可以写成: var aA(11)2.泛型约束…...
性能测试知多少?怎样开展性能测试
看到好多新手,在性能需求模糊的情况下,随便找一个性能测试工具,然后就开始进行性能测试了,在这种情况下得到的性能测试结果很难体现系统真实的能力,或者可能与系统真实的性能相距甚远。 与功能测试相比,性能…...
code-breaking之javacon
JAVACON 题目 此题 来自P神 的code-breaking中的一道Java题,名为javacon,题目知识点为SpEL注入 题目下载地址:https://www.leavesongs.com/media/attachment/2018/11/23/challenge-0.0.1-SNAPSHOT.jar 运行环境 java -jar challenge-0.…...
Android 字符串替换,去除空格等操作
今天在写代码的时候,需要对String进行一些操作,例如变小写,去除所有空格 于是熟练的使用String的replaceAll,却发现没这个方法。 后面才发现Kotlin使用的是自己的String,有自己的方法,用String的replace(…...
因“AI”而“深” 第四届OpenI/O 启智开发者大会高校开源专场25日开启!
中国算力网资源不断开发,开源社区治理及AI开源生态引来众多有才之士参与建设,国家级开放创新应用平台、NLP大模型等高新技术内容逐渐走向科研舞台上聚光灯的中心,新时代的大门缓缓打开。在启智社区,有一群人,他们年纪轻…...
CATCTF wife原型链污染
CATCTF wife原型链污染 原型链污染原理:https://drun1baby.github.io/2022/12/29/JavaScript-%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93/ 如下代码,prototype是newClass类的一个属性。newClass 实例化的对象 newObj 的 .__proto__ 指向 newClass…...
浅谈Java线程池中的ThreadPoolExecutor工具类
目录 ThreadPoolExecutor的构造函数 关于线程池的一些补充 线程池运行原理分析 概念原理解释 整个流程图如下: 一点补充 创建线程池主要有两种方式: 通过Executor工厂类创建,创建方式比较简单,但是定制能力有限通过ThreadPoo…...
分析过程:服务器被黑安装Linux RootKit木马
前言 疫情还没有结束,放假只能猫家里继续分析和研究最新的攻击技术和样本了,正好前段时间群里有人说服务器被黑,然后扔了个样本在群里,今天咱就拿这个样本开刀, 给大家研究一下这个样本究竟是个啥,顺便也给…...
运动型蓝牙耳机推荐哪款、最新运动蓝牙耳机推荐
提起运动耳机,如今很多运动爱好者和职业教练员们,都会向萌新推荐骨传导运动耳机。骨传导耳机解决了入耳式蓝牙耳机掉落的问题,佩戴相当舒服。骨传导耳机在佩戴过程中解放了双耳,不会因为耳机堵住耳朵,听不到环境音&…...
Python爬虫(9)selenium爬虫后数据,存入mongodb实现增删改查
之前的文章有关于更多操作方式详细解答,本篇基于前面的知识点进行操作,如果不了解可以先看之前的文章 Python爬虫(1)一次性搞定Selenium(新版)8种find_element元素定位方式 Python爬虫(2)-Selenium控制浏览…...
gulimall技术栈笔记
文章目录1.项目背景1.1电商模式1.2谷粒商城2.项目架构图3.项目技术&特色4.项目前置要求5.分布式基础概念5.1微服务5.2集群&分布式&节点5.3远程调用5.4负载均衡5.5服务注册/发现&注册中心5.6配置中心5.7服务熔断&服务降级5.7.1服务熔断5.7.2服务降级5.8API网…...
vue3生命周期钩子以及使用方式
按照生命周期的顺序来排列: onBeforeMount() DOM挂载前调用 注册一个钩子,在组件被挂载之前被调用。 当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。 onMount(…...
以假乱真的手写模拟器?
前些时候给大家推荐了一款word插件叫做“不坑盒子”,这款盒子不仅方便了word的操作,还附带了手写模拟器这样的效果只是在使用的时候不仅需要手动下载字体,而且效果也并不是太理想。 今天小编找到了一款软件--手写模拟器,不仅一键生…...
每日一题——L1-069 胎压监测(15)
L1-069 胎压监测 分数 15 小轿车中有一个系统随时监测四个车轮的胎压,如果四轮胎压不是很平衡,则可能对行车造成严重的影响。 让我们把四个车轮 —— 左前轮、右前轮、右后轮、左后轮 —— 顺次编号为 1、2、3、4。本题就请你编写一个监测程序&#…...
17_FreeRTOS事件标志组
目录 事件标志组 事件标志组与队列、信号量的区别 事件标志组相关API函数介绍 实验源码 事件标志组 事件标志位:用一个位,来表示事件是否发生 事件标志组是一组事件标志位的集合,可以简单的理解事件标志组,就是一个整数。 事件标志组的特点: 它的每一个位表示一个事件(…...
美团前端常考手写面试题总结
实现观察者模式 观察者模式(基于发布订阅模式) 有观察者,也有被观察者 观察者需要放到被观察者中,被观察者的状态变化需要通知观察者 我变化了 内部也是基于发布订阅模式,收集观察者,状态变化后要主动通知观…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...
验证redis数据结构
一、功能验证 1.验证redis的数据结构(如字符串、列表、哈希、集合、有序集合等)是否按照预期工作。 2、常见的数据结构验证方法: ①字符串(string) 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...
STL 2迭代器
文章目录 1.迭代器2.输入迭代器3.输出迭代器1.插入迭代器 4.前向迭代器5.双向迭代器6.随机访问迭代器7.不同容器返回的迭代器类型1.输入 / 输出迭代器2.前向迭代器3.双向迭代器4.随机访问迭代器5.特殊迭代器适配器6.为什么 unordered_set 只提供前向迭代器? 1.迭代器…...
CppCon 2015 学习:Simple, Extensible Pattern Matching in C++14
什么是 Pattern Matching(模式匹配) ❝ 模式匹配就是一种“描述式”的写法,不需要你手动判断、提取数据,而是直接描述你希望的数据结构是什么样子,系统自动判断并提取。❞ 你给的定义拆解: ✴ Instead of …...
智警杯备赛--excel模块
数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中,点击确定 这是最终结果,但是由于环境启不了,这里用的是自己的excel,真实的环境中的excel根据实训…...
Axure Rp 11 安装、汉化、授权
Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接:https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...
