Day49
Day49
代理模式proxy
概念: 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
代理模式分为静态代理和动态代理两种 。
静态代理
思路:对于同一个接口,代理类和被代理类都实现了这个接口,代理类中将被代理类对象持有为自己的属性,这样在使用方法的时候就可以在被代理类的方法前后加上增强,即自己的方法逻辑。
以Speaker接口、ChineseSpeaker、AmericaSpeaker、ChinsesSpeakerProxy、AmericaSpeakerProxy为例,其中ChinsesSpeakerProxy、AmericaSpeakerProxy分别是ChineseSpeaker、AmericaSpeaker的代理类:
Speaker:
public interface Speaker {void speak(); }
ChineseSpeaker:
public class ChineseSpeaker implements Speaker{public void speak() {System.out.println("中文演讲");} }
ChinsesSpeakerProxy:
public class ChineseSpeakerProxy implements Speaker{private ChineseSpeaker speaker;public ChineseSpeakerProxy(ChineseSpeaker speaker) {this.speaker = speaker;}@Overridepublic void speak() {System.out.println("增强处理");speaker.speak();System.out.println("增强处理");} }
可以看出,这种写法每代理一个真实类就需要写一个代理类,对于AmericaSpeaker,同样要写一个AmericaSpeakerProxy。如果对于功能增强的内容完全相同,就可以使用一个对于Speaker接口通用的代理类CommonSpeakerProxy,利用多态完成代理。
public class CommonSpeakerProxy implements Speaker {private Speaker speaker;public CommonSpeakerProxy(Speaker speaker) {this.speaker = speaker;}@Overridepublic void speak() {System.out.println("前置功能增强");speaker.speak();System.out.println("后置功能增强");} }
除了这种写法外,还可以利用反射的思想来写,利用多态通过接口实现类拿到方法,通过有参传入的类对象,用method.invoke()方法完成代理。
假设这时再添加了Seller接口、ChineseSeller、AmericaSeller类及其代理类CommonSellerProxy
public class CommonSellerProxy implements Seller{private static Method method;private Object seller;public CommonSellerProxy(Object seller){this.seller = seller;}static {try {method = Seller.class.getMethod("sell");} catch (NoSuchMethodException e) {e.printStackTrace();}}@Overridepublic void sell() {try {System.out.println("前置功能增强");method.invoke(seller);System.out.println("后置功能增强");} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);}} }
可以看出,静态代理每实现一个真实类的代理就需要写一个代理类,如果代理的功能不同,就需要针对代理功能编写多个类,十分复杂。那么有没有一种方式使得在使用到代理的时候再去编写代理的逻辑功能,而不是每次都去多写一个类呢?这就是动态代理的思想。
动态代理
动态代理又根据代理对象进行划分:
为接口做代理:JDK动态代理
为类做代理:CGLIB动态代理
JDK动态代理
由于动态代理和静态代理差别较大,这里从静态代理开始进阶优化,直到达到动态代理的范畴。
**静态代理进阶:**思路:写一个接口,接口中定义了代理重写的方法,在代理类中以匿名内部类的方式创建一个类对象作为自己持有的属性,并用全参构造要求使用时创建这个匿名内部类(即重写代理方法内容),而代理类中就只需要调用接口的实现类的方法就行,不需要再写明方法逻辑。
这个接口是jdk自带的接口,在这里自己写一遍,以更好地明白逻辑:
MethodInvocationHandler接口:
public interface MethodInvocationHandler {Object handle(Object target, Method method,Object[] args) throws Exception; }
注意:这个方法的本质是反射,利用method.invoke()方法进行调用真实类的方法,再加上代理类的方法,因此参数为method.invoke()的参数。
ChineseSpeakerProxy代理类:
public class ChineseSpeakerProxy implements Speaker{private Speaker speaker;private MethodInvocationHandler handler;private static Method method;static {try {method = Speaker.class.getMethod("speak");} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}public ChineseSpeakerProxy(Speaker speaker, MethodInvocationHandler handler) {this.speaker = speaker;this.handler = handler;}//如果有多个需要代理的方法就都要进行重写@Overridepublic void speak() {try {handler.handle(speaker,method,null);//由于真实类中的方法是无参的,所以这里的参数数组为空} catch (Exception e) {throw new RuntimeException(e);}} }
使用:
public class Test01 {public static void main(String[] args) {ChineseSpeaker chineseSpeaker = new ChineseSpeaker();ChineseSpeakerProxy chineseSpeakerProxy = new ChineseSpeakerProxy(chineseSpeaker, new MethodInvocationHandler() {@Overridepublic Object handle(Object target, Method method, Object[] args) throws Exception {System.out.println("功能增强");method.invoke(target,args);System.out.println("功能增强");return null;}});chineseSpeakerProxy.speak();}
至此,对于同一个代理类的多个功能,实现了让用户自己写增强方法的目的。但是对于一个真实类,如果要实现其代理,那还是要写一个代理类,如果真实类很多,那就需要写很多的代理类,代理繁多的问题依然存在。
如果这些代理类能够使用代码来生成,然后再编译,再加载至
JVM
中,那么再多的代理也就不是问题了。动态代理:
手动写一个能够自动创建代理类源码的类,然后手动完成编译、加载的过程。(这些功能jdk的接口都实现了,这里只手写一个自动创建代理类源码的类以便深刻理解)
因此,可以手动写一个能够自动创建代理类源码的类,然后手动完成编译、加载的过程。(这些功能jdk的接口都实现了,这里只手写一个自动创建代理类源码的类以便深刻理解)
package com.qf.proxy;import com.qf.proxy.dynamic.MethodInvocationHandler;import java.lang.reflect.Method; import java.lang.reflect.Parameter;public class MyProxy {private static String generateProxyClass(Class<?> clazz){if(!clazz.isInterface()) throw new IllegalArgumentException(clazz.getName() + " 不是接口");StringBuilder builder = new StringBuilder();builder.append("package ").append(clazz.getPackage().getName()).append(";\n");builder.append("import ").append(Method.class.getName()).append(";\n");builder.append("import ").append(MethodInvocationHandler.class.getName()).append(";\n");builder.append("import ").append(MyProxy.class.getName()).append(";\n");builder.append("public class $proxy0 extends MyProxy implements ").append(clazz.getSimpleName()).append("{\n");StringBuilder staticBuilder = new StringBuilder();staticBuilder.append("static {\n");staticBuilder.append("try {\n");StringBuilder overrideMethodBuilder = new StringBuilder();Method[] methods = clazz.getMethods();for(int i=0; i<methods.length; i++){builder.append("private static Method m").append(i).append(";\n");staticBuilder.append("m").append(i).append("=Class.forName(\"").append(clazz.getName()).append("\").getMethod(\"").append(methods[i].getName()).append("\",");overrideMethodBuilder.append("\n@Override\n");overrideMethodBuilder.append("public ").append(methods[i].getReturnType().getSimpleName()).append(" ").append(methods[i].getName()).append("(");Parameter[] parameters = methods[i].getParameters();for(Parameter parameter : parameters){staticBuilder.append(parameter.getType().getSimpleName()).append(".class,");overrideMethodBuilder.append(parameter.getType().getSimpleName()).append(" ").append(parameter.getName()).append(",");}staticBuilder.deleteCharAt(staticBuilder.length()-1);staticBuilder.append(");\n");if(parameters.length > 0)overrideMethodBuilder.deleteCharAt(overrideMethodBuilder.length()-1);overrideMethodBuilder.append("){\n");Class returnType = methods[i].getReturnType();if(returnType != Void.class && returnType != void.class)overrideMethodBuilder.append("return (").append(methods[i].getReturnType().getSimpleName()).append(")");overrideMethodBuilder.append("handler.handle(m").append(i).append(",new Object[]{");for(Parameter parameter : parameters){overrideMethodBuilder.append(parameter.getName()).append(",");}if(parameters.length > 0)overrideMethodBuilder.deleteCharAt(overrideMethodBuilder.length()-1);overrideMethodBuilder.append("});\n}");}staticBuilder.append("} catch (NoSuchMethodException e) {\ne.printStackTrace();\n}catch (ClassNotFoundException e) {\ne.printStackTrace();\n}\n");staticBuilder.append("}\n");builder.append(staticBuilder);builder.append("protected $proxy0(MethodInvocationHandler handler) {\nsuper(handler);\n}\n");builder.append(overrideMethodBuilder);builder.append("\n}");System.out.println(builder);return builder.toString();}// public static void main(String[] args) { // generateProxyClass(Seller.class); // } }
这个类完成了自动创建类源码的功能,其实现的思路就是将一个代理类中的特定类利用反射和object去替换,然后将整个类写成字符串放进StringBuilder中。
然后是编译代理类源文件、加载编译好的代理类(利用类加载器)、编写创建代理实例的方法。这些底层就不手写了。
接下来对比一下两种写法的区别(这里都实现jdk自带的InvocationHandler接口,接口内容和上面手写的MethodInvocationHandler一致,只是方法名字为invoke,我写的是handle):
手动创建ChineseSpeakerProxy(此时仍然为静态代理,因为代理类是在编译时明确定义的,并且代理类的代码是手动编写的。相对于动态代理,静态代理类在运行时不会自动生成,而是在编译时就已经存在。 ):
public class ChineseSpeakerProxy implements Speaker{private Speaker speaker;private InvocationHandler handler;private static Method method;static {try {method = Speaker.class.getMethod("speak");} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}public ChineseSpeakerProxy(Speaker speaker, InvocationHandler handler) {this.speaker = speaker;this.handler = handler;}@Overridepublic void speak() {try {handler.invoke(speaker,method,null);} catch (Throwable e) {throw new RuntimeException(e);}} }public class Test01 {public static void main(String[] args) {ChineseSpeaker chineseSpeaker = new ChineseSpeaker();ChineseSpeakerProxy chineseSpeakerProxy = new ChineseSpeakerProxy(chineseSpeaker, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {method.invoke(proxy,args);System.out.println("方法增强");return null;}});chineseSpeakerProxy.speak();}
使用jdk自带的Proxy类静态方法创建(动态代理):
public class Test01 {public static void main(String[] args) {ChineseSpeaker chineseSpeaker = new ChineseSpeaker();Speaker ChineseSpeakerProxy = (Speaker) Proxy.newProxyInstance(ChineseSpeaker.class.getClassLoader(), ChineseSpeaker.class.getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法增强");method.invoke(chineseSpeaker,args);return null;}});ChineseSpeakerProxy.speak();}
注意:使用Proxy类实现动态代理的时候,method.invoke()的第一个参数不是形参给的,而是被代理的类对象! 因为使用 Proxy.newProxyInstance动态生成的代理类会把代理实例本身传递给 InvocationHandler.invoke方法的 proxy 参数。因此,如果在 invoke 方法中再次调用 method.invoke(proxy, args),就会导致递归调用形成死循环。
总结
静态代理:
写法一:真实类和代理类实现同一个接口,代理类持有真实类对象作为属性,并在重写接口方法的时候调用其方法,再添加方法增强。
写法二:如果多个真实类需要进行的方法增强相同,则可以写一个通用的代理类,实现和写法一相同。
写法三:利用反射的思想,代理类持有真实类对象属性,并利用反射拿到方法,重写的时候用invoke(),并添加方法增强。
写法四(进阶):利用接口(这里自己写的是MethodInvocationHandler)定义重写的方法,在代理类中创建接口的实现类(匿名内部类),并通过全参构造让用户自己传入真实类对象和接口实现类(并重写代理方法),调用实现类的方法。
动态代理:自动创建代理类源码,然后完成编译、加载。 代理类在运行时根据目标对象和增强逻辑动态生成。 在使用的时候利用Proxy类的静态方法newProxyInstance()创建代理类,并 通过 InvocationHandler 接口的 invoke 方法在运行时拦截方法调用,执行增强逻辑。
RESTful风格
RESTful风格不是标准,但是在企业中经常使用RESTful风格来完成功能的开发。
REST = Representational State Transfer(表属性状态转移)
简单来说就是在编写Servlet的时候重写doGet,doPost,doPut,doDelete实现增查改删功能。
Spring IOC
Spring简介
Spring 是目前主流的 Java 开发框架,是 Java 世界最为成功的框架。其目的是用于简化企业级应用程序开发的难度和周期,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
什么是框架? 框架是一个半成品,提供了基本的运行功能,但具体业务实现需要我们去编写。
Spring体系结构
IOC概念:
IOC全称为 Inverse Of Control,表示控制反转。指的是程序员使用硬编码创建的对象转为由Spring容器来创建,对于对象生命周期的控制交给Spring容器来管理。控制反转解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健
依赖注入
DI全称为Dependency Injection,表示依赖注入。指的是在Spring创建对象的同时,为其属性赋值
设值注入:
创建一个类:
@Data public class Student {private String name;private String sex;private int age;private Date birthday; }
在xml配置文件中利用设值注入创建对象:
常见数据类型:
<!--application.xml--> <bean name="stu" class="com.qf.spring.ioc.model.Student"><property name="name" value="张三" /><property name="age" value="20" /><property name="sex" value="男" /><!--这里需要注意:日期类型的默认格式yyyy/MM/dd--><property name="birthday" value="2021/10/10" /> </bean>
使用:
@Test public void studentTest(){//应用上下文使用的是类路径下XML文档作为当前应用上下文ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");//从上下文中根据bean的名称或者ID获取bean对象Student stu = context.getBean("stu", Student.class);System.out.println(stu); }
注意:这里的name虽然是user,但是并不是指的user这个类,而是指向set方法!(理解为去掉set后的名字)设值注入本质就是通过set方法为属性注入值。设值注入必须保证存在无参构造,否则将报错。
注入数组类型:
spring 提供了 array 标签来进行数组类型的属性值的注入。
@Data public class Clazz {private int id;private String name;private Student[] students; }
<bean name="clazz" class="com.qf.spring.ioc.model.Clazz"><property name="id" value="1" /><property name="name" value="张三" /><property name="students"><array><!--引用数据类型 可以使用bean标签创建bean对象注入值--><!--<bean class=""></bean>--><!--引用数据类型 可以使用ref标签引用bean对象注入值--><ref bean="s" /><ref bean="stu" /><!--常用数据类型 可以使用value标签直接注入值--><!-- <value></value>--></array></property> </bean>
注入集合类型:
List集合
@Data @AllArgsConstructor @NoArgsConstructor public class Student {private String name;private String sex;private int age;private Date birthday;private List<Double> scores; }
<bean name="stu" class="com.qf.spring.ioc.model.Student"><property name="name" value="张三" /><property name="age" value="20" /><property name="sex" value="男" /><!--这里需要注意:日期类型的默认格式yyyy/MM/dd--><property name="birthday" value="2021/10/10" /><property name="scores"><list><value>80.0</value><value>90.0</value><value>81.0</value><value>82.0</value></list></property> </bean><bean name="s" class="com.qf.spring.ioc.model.Student"><!--这里按照顺序为属性注入值--><constructor-arg index="0" value="李四" /><constructor-arg index="1" value="女" /><constructor-arg index="2" value="22" /><constructor-arg index="3" value="2020/05/05" /><constructor-arg index="4"><list><value>80.0</value><value>90.0</value><value>81.0</value><value>82.0</value></list></constructor-arg> </bean>
Set集合
@Data public class Person {private String name;private Set<String> friendNames; }
<bean name="p" class="com.qf.spring.ioc.model.Person"><property name="name" value="李刚" /><property name="friendNames"><set><value>李四</value><value>王五</value></set></property> </bean>
注入Map
@Data public class Person {private String name;private List<String> friendNames;private Map<String, Object> map; }
<bean name="p" class="com.qf.spring.ioc.model.Person"><property name="name" value="李刚" /><property name="friendNames"><set><value>李四</value><value>王五</value></set></property><property name="map"><map><entry key="hobby" value="聊天" /><entry key="clazz" value-ref="clazz"/></map></property><property name="props"><props><prop key="desc">我很帅</prop><prop key="secret">我有两个女朋友</prop></props></property> </bean>
注入Properties
@Data public class Person {private String name;private List<String> friendNames;private Properties props; }
<bean name="p" class="com.qf.spring.ioc.model.Person"><property name="name" value="李刚" /><property name="friendNames"><set><value>李四</value><value>王五</value></set></property><property name="props"><props><prop key="desc">我很帅</prop><prop key="secret">我有两个女朋友</prop></props></property> </bean>
构造注入
构造注入指的是通过构造放入为属性注入值。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private String sex;private int age;private Date birthday;
}
<!--application.xml-->
<bean name="s" class="com.qf.spring.ioc.model.Student"><!--这里按照顺序为属性注入值--><constructor-arg index="0" value="李四" /><constructor-arg index="1" value="女" /><constructor-arg index="2" value="22" /><constructor-arg index="3" value="2020/05/05" />
</bean>
@Test
public void studentConstructorTest(){//应用上下文使用的是类路径下XML文档作为当前应用上下文ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");//从上下文中根据bean的名称或者ID获取bean对象Student stu = context.getBean("s", Student.class);System.out.println(stu);
}
相关文章:

Day49
Day49 代理模式proxy 概念: 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 代理模式分为静态代理和动态代理…...

OpenCV 车牌检测
OpenCV 车牌检测 级联分类器算法流程车牌检测相关链接 级联分类器 假设我们需要识别汽车图像中车牌的位置,利用深度学习目标检测技术可以采取基于锚框的模型,但这需要在大量图像上训练模型。 但是,级联分类器可以作为预训练文件直接使用&…...

机器学习/pytorch笔记:time2vec
1 概念部分 对于给定的标量时间概念 t,Time2Vec 的表示 t2v(t)是一个大小为 k1的向量,定义如下: 其中,t2v(t)[i]是 t2v(t)的第 i 个元素,F是一个周期性激活函数,ω和 ϕ是可学习的参数。 以下是个人理解&am…...
降低开关电源噪声的设计总结
开关电源的特征就是产生强电磁噪声,若不加严格控制,将产生极大的干扰。下面介绍的技术有助于降低开关电源噪声,能用于高灵敏度的模拟电路。 电路和器件的选择 一个关键点是保持dv/dt和di/dt在较低水平,有许多电路通过减小dv/dt和…...
rust嵌入式开发2024
老的rust embedded book 其实过时了. 正确的姿势是embassy 入手. 先说下以前rust写嵌入怎么教学小白的. 第一步,从这里 svd2rust 工具,自己生成库第二部,有了这个库,相当于就有了pac外设访问文件,然后其实就可以搞起来了. 那么为啥不好搞了. 因为太乱了. 小白喜欢你告我咋弄…...
字符串
对应练习题:力扣平台 14. 最长公共前缀 class Solution { public:string longestCommonPrefix(vector<string>& strs) {string strs1strs[0];//初始前缀字符串for (int i 1; i < strs.size(); i) {while(strs[i].find(strs1)!0)//遍历找到共同最长前…...
mysql8 锁表与解锁
方法1不行,就按方法2来执行; (一) 解锁方法1 连接mysql ,直接执行UNLOCK TABLES,细节如下: – 查询是否锁表 SHOW OPEN TABLES WHERE in_use >0 ; – 查询进程 show processlist ; – 查询到相对应的进程…...
第2篇 区块链的历史和发展:从比特币到以太坊
想象一下,你住在一个小镇上,每个人都有一个大账本,记录着所有的交易。这个账本很神奇,每当有人买卖东西,大家都会在自己的账本上记一笔,确保每个人的账本都是一致的。这就是区块链的基本思想。而区块链的故…...

从理论到实践的指南:企业如何建立有效的EHS管理体系?
企业如何建立有效的EHS管理体系?对于任何企业,没有安全就谈不上稳定生产和经济效益,因此建立EHS管理体系是解决企业长期追求的建立安全管理长效机制的最有效手段。良好的体系运转,可以最大限度地减少事故发生。 这篇借着开头这个…...
内网和外网的区别及应用
内网和外网的区别及应用 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨一下计算机网络中的内网和外网,它们的区别以及在实际应用中的…...

电驱失效类型和风险分析,如何用精益思维提升电驱可靠性?
在电动车日益普及的今天,电驱系统作为电动车的“心脏”,其可靠性直接关系到整车的性能与用户体验。然而,电驱失效问题却一直困扰着电动车行业,如何提升电驱可靠性成为了业内关注的焦点。今天,深圳天行健精益管理咨询公…...

自动扫描范围在减少剂量多相CT肝脏成像中的应用:基于CNN和高斯模型| 文献速递-深度学习自动化疾病检查
Title 题目 Automatic scan range for dose-reduced multiphase CT imaging of theliver utilizing CNNs and Gaussian models 自动扫描范围在减少剂量多相CT肝脏成像中的应用:基于CNN和高斯模型 01 文献速递介绍 肝癌是全球癌症死亡的第四大原因,每…...

【机器学习】基于层次的聚类方法:理论与实践
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 基于层次的聚类方法:理论与实践引言1. 层次聚类基础1.1 概述1.2 距离…...

C# 验证PDF数字签名的有效性
数字签名作为PDF文档中的重要安全机制,不仅能够验证文件的来源,还能确保文件内容在传输过程中未被篡改。然而,如何正确验证PDF文件的数字签名,是确保文件完整性和可信度的关键。本文将详细介绍如何使用免费.NET控件通过C#验证PDF签…...

2小时动手学习扩散模型(pytorch版)【入门版】【代码讲解】
2小时动手学习扩散模型(pytorch版) 课程地址 2小时动手学习扩散模型(pytorch版) 课程目标 给零基础同学快速了解扩散模型的核心模块,有个整体框架的理解。知道扩散模型的改进和设计的核心模块。 课程特色…...

Centos7网络配置(设置固定ip)
文章目录 1进入虚拟机设置选中【网络适配器】选择【NAT模式】2 进入windows【控制面板\网络和 Internet\网络和共享中心\更改适配器设置】设置网络状态。3 设置VM的【虚拟网络编辑器】4 设置系统网卡5 设置虚拟机固定IP 刚安装完系统,有的人尤其没有勾选自动网络配置…...
英伟达被“压制”的25年
十九世纪中叶的美国西部,掀起了一场轰轰烈烈的淘金热,但最终赚到钱的,并不是拿命去赌的淘金者。一个名叫萨姆布瑞南的商人,通过向淘金者出售铲子,成了加州历史上第一位百万富翁。 每一次风口出现时,总有企…...
windows安装Gitblit还是Bonobo Git Server
Gitblit 和 Bonobo Git Server 都是用于托管Git仓库的工具,但它们是基于不同平台的不同软件。 Gitblit 是一个纯 Java 写的服务器,支持托管 Git,Mercurial 和 SVN 仓库。它需要 Java 运行环境,适合在 Windows、Linux 和 Mac 平台…...

仪器校准的概念与定义,计量校准是什么?
仪器校准的定义,在之前所颁布的《国际计量学词汇 基础和通用概念及相关术语》文件中,已经有了明确说明,而该文件做了修改以后,在后续新的定义中,仪器校准具体被分为两部分,第一步是将被计量仪器和计量校准的…...
Vue3+Pinia
1.单纯调接口(安装pinia及引入如下第一张图) 1.npm install pinia2.在main.js里引入即可import { createPinia } from piniaapp.use(createPinia()) 1.stores建立你文件的ts、内容如下:1-1 import { defineStore } from pinia1-2 import { findPageJobSet } from …...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...