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

一文总结代理:代理模式、代理服务器

概述

代理在计算机编程领域,是一个很通用的概念,包括:代理设计模式,代理服务器等。

代理类持有具体实现类的实例,将在代理类上的操作转化为实例上方法的调用。为某个对象提供一个代理,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可以去掉功能服务或者增加额外的功能。

角色

代理模式一般涉及到的角色有:

  • 对象:Client,请求客户端
  • 抽象角色:Subject,声明真实对象和代理对象的共同接口,对应代理接口;
  • 真实角色:RealSubject,代理角色所代表的真实对象,是最终要引用的对象,对应委托类;
  • 代理角色:Proxy,代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装,对应代理类,可以有未公开的方法。

UML类图如下:
在这里插入图片描述
调用顺序示意图:
在这里插入图片描述

分类

代理从类型来分类:

  • 虚代理:虚拟代理,Virtual Proxy,根据需要来创建开销很大的对象,该对象只有在需要时才会被真正创建,即所谓的延迟加载;
  • 远程代理:Remote Proxy,用来在不同的地址空间上代表同一个对象,这个不同的地址空间可以是在本机,也可以在其它机器上,在Java里面最典型的就是RMI技术;
  • copy-on-write代理:在客户端操作时,只有对象确实改变后,才会真的拷贝一个日标对象,算是虚代理的一个分支;
  • 保护代理:Protect Proxy,控制对原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问;
  • Cache代理:为那些昂贵操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果;
  • 防火墙代理:保护对象不被恶意用户访问和操作;
  • 同步代理:使多个用户能够同时访问目标对象而没有冲突;
  • 智能引用代理:Smart Reference Proxy,在访问对象时执行一些附加操作。比如,对指向实际对象的引用计数、第一次引用一个持久对象时,将它装入内存等

另外,根据代理类的生成时间的不同,可分为静态代理和动态代理。

静态代理

代理和被代理对象(目标对象)在代理之前是确定的,都实现相同的接口或者继承相同的抽象类。目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态,在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定。

实现静态代理有继承、聚合方法。

优点:业务类只需要关注业务逻辑本身,保证业务类的重用性。

缺点:

  1. 需要大量硬编码
  2. 一个代理类只能代理一个业务类
  3. 如果业务类增加方法时,相应的代理类也要增加方法

动态代理

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。优势在于可以很方便的对代理类的函数进行统一的处理,添加方法调用次数、添加日志功能等,而不用修改每个代理类的函数。分为JDK动态代理和cglib动态代理。

实现

一般有JDK和cglib等实现方式。

JDK

基于反射,核心API包括:
java.lang.reflect.Proxy,Java动态代理机制生成的所有动态代理类的父类,提供一组静态方法来为一组接口动态地生成代理类及其对象,共4个static方法:

public class Proxy implements java.io.Serializable {// 用于获取指定代理对象所关联的调用处理器public static InvocationHandler getInvocationHandler(Object proxy)// 用于获取关联于指定类装载器和一组接口的动态代理类的类对象public static class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)// 用于判断指定类对象是否是一个动态代理类public static boolean isProxyClass(Class<?> cl)// 用于为指定类装载器、一组接口及调用处理器生成动态代理类实例public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
}

InvocationHandler接口主要用来处理执行逻辑,源码:

public interface InvocationHandler {// obj指代理类,method指被代理的方法,args为该参数的方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

使用JDK动态代理的步骤

  1. 创建被代理的类以及接口;
  2. 创建一个实现接口InvocationHandler,并重写invoke方法的类;
  3. 调用Proxy的静态方法,创建代理类newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
  4. 通过代理调用方法。

实例

代表Subject的接口:

public interface Movable {void move();
}

Car实现Movable接口,是要代理的实际对象,对应RealSubject:

@Slf4j
public class Car implements Movable {@Overridepublic void move() {// 实现开车try {Thread.sleep(new Random().nextInt(1000));System.out.println("汽车行驶中....");} catch (InterruptedException e) {log.error("thread fail", e);}}
}

对应于Proxy的TimeHandler类实现InvocationHandler接口,并在invoke()方法中添加额外的逻辑,用于在代理对象方法调用前后执行:

public class TimeHandler implements InvocationHandler {private final Object target;TimeHandler(Object target) {super();this.target = target;}/*** 参数:* proxy:被代理对象* method:被代理对象的方法* args:方法的参数* res:方法的返回值*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();System.out.println("汽车开始行驶....");Object res = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println("汽车结束行驶....  汽车行驶时间:" + (endTime - startTime) + "毫秒!");return res;}
}

JDK动态代理测试类,也就是上图中的Client类:

public class Test {public static void main(String[] args) {Car car = new Car();InvocationHandler h = new TimeHandler(car);Class<?> cls = car.getClass();/** loader:类加载器* interfaces:实现接口* h:InvocationHandler*/Movable m = (Movable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);m.move();}
}

使用Proxy.newProxyInstance()方法创建代理对象,指定Movable接口作为代理对象类型,并将TimeHandler对象作为代理对象的InvocationHandler。

缺点:

  1. 仍有硬编码
  2. 需要在对象初始化时,使用特定的方式进行初始化

源码分析

基于JDK-22,以Proxy.newProxyInstance()方法为切入点:

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {Objects.requireNonNull(h);@SuppressWarnings("removal")final Class<?> caller = System.getSecurityManager() == null ? null : Reflection.getCallerClass();// 查找或生成指定的代理类及其构造函数Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);return newProxyInstance(caller, cons, h);
}

基于源码的注释,进一步查看getProxyConstructor代码:

private static Constructor<?> getProxyConstructor(Class<?> caller, ClassLoader loader, Class<?>... interfaces) {// optimization for single interfaceif (interfaces.length == 1) {Class<?> intf = interfaces[0];if (caller != null) {checkProxyAccess(caller, loader, intf);}return proxyCache.sub(intf).computeIfAbsent(loader, (ld, clv) -> new ProxyBuilder(ld, clv.key()).build());} else {// interfaces clonedfinal Class<?>[] intfsArray = interfaces.clone();if (caller != null) {checkProxyAccess(caller, loader, intfsArray);}final List<Class<?>> intfs = Arrays.asList(intfsArray);return proxyCache.sub(intfs).computeIfAbsent(loader, (ld, clv) -> new ProxyBuilder(ld, clv.key()).build());}
}

核心方法是构建ProxyBuilder实例,ProxyBuilder是java.lang.reflect.Proxy的静态内部类,利用构造器模式:

ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {// 在模块系统完全初始化之前不支持代理if (!VM.isModuleSystemInited()) {throw new InternalError("Proxy is not supported until module system is fully initialized");}// 接口数不得超过65535个if (interfaces.size() > 65535) {throw new IllegalArgumentException("interface limit exceeded: " interfaces.size());}Set<Class<?>> refTypes = referencedTypes(loader, interfaces);// IAE if violates any restrictions specified in newProxyInstancevalidateProxyInterfaces(loader, interfaces, refTypes);this.interfaces = interfaces;this.context = proxyClassContext(loader, interfaces, refTypes);assert getLoader(context.module()) == loader;
}

核心方法之一,referencedTypes检查是否为static方法:

private static Set<Class<?>> referencedTypes(ClassLoader loader, List<Class<?>> interfaces) {var types = new HashSet<Class<?>>();for (var intf : interfaces) {for (Method m : intf.getMethods()) {// 不能为static方法if (!Modifier.isStatic(m.getModifiers())) {addElementType(types, m.getReturnType());addElementTypes(types, m.getSharedParameterTypes());addElementTypes(types, m.getSharedExceptionTypes());}}}return types;
}

validateProxyInterfaces方法检查是否是接口,

private static void validateProxyInterfaces(ClassLoader loader, List<Class<?>> interfaces, Set<Class<?>> refTypes) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size());for (Class<?> intf : interfaces) {// 检查是否为接口if (!intf.isInterface()) {throw new IllegalArgumentException(intf.getName() + " is not an interface");}// 检查是否为隐藏类:JDK15引入新特性if (intf.isHidden()) {throw new IllegalArgumentException(intf.getName() + " is a hidden interface");}// 检查是否是密封类:JDK17引入新特性if (intf.isSealed()) {throw new IllegalArgumentException(intf.getName() + " is a sealed interface");}// 验证类加载器是否将此接口的名称解析为同一个Class对象,下同ensureVisible(loader, intf);// 检查是否已经生成过此接口的代理类if (interfaceSet.put(intf, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + intf.getName());}}for (Class<?> type : refTypes) {ensureVisible(loader, type);}
}

为什么JDK动态代理只能代理接口

面试时常见的问题之一,参考上面的源码分析,实际上还可以补充回答:JDK动态代理对密封类,隐藏类不生效,即不能代理密封类,隐藏类。

cglib

Code Generation Library,一款高性能Code生成类库的开源组件,可在运行期扩展Java类与实现Java接口,很多其他开源组件都在使用cglib

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调类型,经常被基于代理的AOP用来实现拦截方法的调用,接口只定义一个方法:

public interface MethodInterceptor extends Callback {// object是代理对像,method是拦截方法,args是方法参数。原来的方法可通过使用Method对象的一般反射调用,或使用MethodProxy对象调用,后者更快Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}	

实例

创建代理类:

public class CglibProxy implements MethodInterceptor {private final Enhancer enhancer = new Enhancer();Object getProxy(Class<?> clazz) {// 设置创建子类的类enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}/*** 拦截所有目标类方法的调用*/@Overridepublic Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("日志开始...");// 代理类调用父类的方法Object res = proxy.invokeSuper(obj, args);System.out.println("日志结束...");return res;}
}

测试类:

public class Client {public static void main(String[] args) {CglibProxy proxy = new CglibProxy();Train t = (Train) proxy.getProxy(Train.class);t.move();}static class Train {void move() {System.out.println("火车行驶中...");}}
}

源码分析

基于cglib最新版3.3.0来分析,从enhancer.create()入手,调用createHelper方法:

private Object createHelper() {// 校验callbackTypes、filter是否为空,及相应处理策略preValidate();Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,ReflectUtils.getNames(interfaces),filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),callbackTypes,useFactory,interceptDuringConstruction,serialVersionUID);this.currentKey = key;Object result = super.create(key);return result;
}

核心方法是create:

protected Object create(Object key) {try {ClassLoader loader = getClassLoader();// 查询缓存Map<ClassLoader, ClassLoaderData> cache = CACHE;ClassLoaderData data = cache.get(loader);// DCLif (data == null) {synchronized (AbstractClassGenerator.class) {cache = CACHE;data = cache.get(loader);if (data == null) {// 构建缓存Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);data = new ClassLoaderData(loader);newCache.put(loader, data);CACHE = newCache;}}}this.key = key;Object obj = data.get(this, getUseCache());if (obj instanceof Class) {// 用于向后兼容return firstInstance((Class) obj);}// 真正创建代理对象return nextInstance(obj);} catch (RuntimeException e) {throw e;} catch (Error e) {throw e;} catch (Exception e) {throw new CodeGenerationException(e);}
}

不管是firstInstance还是nextInstance,最后都是调用ReflectUtils.newInstance方法:

public static Object newInstance(final Constructor cstruct, final Object[] args) {boolean flag = cstruct.isAccessible();try {if (!flag) {cstruct.setAccessible(true);}// 使用JDKreturn cstruct.newInstance(args);} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {throw new CodeGenerationException(e);} finally {if (!flag) {cstruct.setAccessible(flag);}}
}

最后使用JDK源码Constructor.newInstance(args);,因此cglib不能对声明为final的方法进行代理,因为cglib原理是动态生成被代理类的子类。

区别

主要区别:

  • JDK:利用拦截器(实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理;
  • cglib:利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

具体来说:
JDK动态代理只能针对实现接口的类生成代理(实例化一个类)。此时代理对象和目标对象实现相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

cglib是针对类实现代理,主要是对指定的目标类生成一个子类(没有实例化一个类),覆盖其中的方法,通过方法拦截技术拦截所有父类方法的调用。

使用区别:

  • JDK不能用于非接口类、隐藏类、(未经允许扩展的)密封类(的子类)
  • cglib不能用于final方法、隐藏类、同上

Spring AOP

Spring AOP基于JDK Proxy和cglib来生成代理对象,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认策略是如果目标类是接口,则使用JDK动态代理,如果目标对象没有实现接口,则默认会采用cglib代理。

代理模式将继承模式和关联模式结合在一起使用,是两者的综合体,不过这个综合体的作用倒不是解决对象注入的问题,而是为具体操作对象找到一个保姆或者是秘书,对外代表具体的实例对象,实例对象的入口和出口都是通过这个二号首长,具体的实例对象是一号首长,一号首长是要干大事的,所以一些事务性,重复性的工作例如泡茶,安排车子,这样的工作是不用劳烦一号首长的大驾,而是二号首长帮忙解决的,这就是AOP的思想。AOP解决程序开发里事务性,和核心业务无关的问题,但这些问题对于业务场景的实现是很有必要的,在实际开发里AOP也是节省代码的一种方式。

AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,大中型应用都会涉及到的持久化、事务、安全、日志和调试等。

实现AOP的技术,主要分为两大类:

  • 动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
  • 静态织入的方式,引入特定的语法创建Aspect,从而使得编译器可以在编译期间织入有关Aspect代码。

拓展

代理服务器

一般有正向代理、反向代理。

正向代理

一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。如通过Chrome的SwitchSharp访问外网。

反向代理

反向代理:以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。这个服务器没有保存任何网页的真实数据,所有的静态网页或者CGI程序,都保存在内部的Web服务器上。因此对反向代理服务器的攻击并不会使得网页信息遭到破坏,这样就增强Web服务器的安全性。

反向代理经常和CDN一起工作,其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置反向代理节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决Internet网络拥挤的状况,提高用户访问网站的响应速度。

区别

正向代理解决的是客户端访问互联网的问题,客户端知道目标的;
反向代理解决的是互联网收到客户端请求,如何把请求转到内网服务器的问题,不知道目标,代理的是服务端。

相关文章:

一文总结代理:代理模式、代理服务器

概述 代理在计算机编程领域&#xff0c;是一个很通用的概念&#xff0c;包括&#xff1a;代理设计模式&#xff0c;代理服务器等。 代理类持有具体实现类的实例&#xff0c;将在代理类上的操作转化为实例上方法的调用。为某个对象提供一个代理&#xff0c;以控制对这个对象的…...

探索 Kubernetes 持久化存储之 Longhorn 初窥门径

作者&#xff1a;运维有术星主 在 Kubernetes 生态系统中&#xff0c;持久化存储扮演着至关重要的角色&#xff0c;它是支撑业务应用稳定运行的基石。对于那些选择自建 Kubernetes 集群的运维架构师而言&#xff0c;选择合适的后端持久化存储解决方案是一项至关重要的选型决策。…...

全国区块链职业技能大赛样题第9套智能合约+数据库表设计

后端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746050 前端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746216 智能合约+数据库表设计:https://blog.csdn.net/Qhx20040819/article/details/140746646 nice.sql /* Navicat MySQ…...

常见OVS网桥及其链接接口详解

目录 引言OVS简介常见OVS网桥 QBR&#xff08;qbr&#xff09;PLY网桥br-intbr-tunbr-routerbrcps常见网桥链接接口 QVOQVIQVMPatch网桥和接口的工作原理应用场景 虚拟化环境数据中心网络云计算平台 1. 引言 开放虚拟交换机&#xff08;Open vSwitch&#xff0c;简称OVS&…...

创建最最最纯净 Windows 11/10 系统镜像!| 全网独一份

前期准备工作 1.配置系统应答文件&#xff1a;【点击前往】 2.系统镜像编辑器&#xff1a; 【点击下载】 3.Windows 系统镜像官方下载&#xff1a; 【Windows 11】、【Windows 10】【官方密钥】 4.翻译工具 【GitHub】 5.详细的设置教程 5.1先打开配置系统应答文件&#…...

带你学会Git必会操作

文章目录 带你学会Git必会操作1Git的安装2.Git基本操作2.1本地仓库的创建2.2配置本地仓库 3.认识一些Git的基本概念3.1操作流程&#xff1a; 4.一些使用场景4.1添加文件场景一4.2查看git文件4.3修改文件4.4Git版本回退4.5git撤销修改 5.分支管理5.1查看分支5.2创建本地分支5.3切…...

clickhouse处理readonly报错

1&#xff0c;clickhouse执行 SYSTEM RESTORE REPLICA db_com.dwd_com_t_judge_result_local; SYSTEM RESTORE REPLICA db_com.dwd_com_t_judge_result_local Query id: 70669be0-eef8-41da-b761-4980ce48ece2 0 rows in set. Elapsed: 0.001 sec. Received exception fro…...

使用git命令行的方式,将本地项目上传到远程仓库

在国内的开发环境中&#xff0c;git的使用是必不可少的。Git 是一款分布式版本控制系统&#xff0c;用于有效管理和追踪文件的变更历史及协作开发。本片文章就来介绍一下怎样使用git命令行的方式&#xff0c;将本地项目上传到远程仓库&#xff0c;虽然现在的IDE中基本都配置了g…...

jetbrains InterlliJ IDEA 2024.1 版本最新特性一览: Java 相关内容

简简单单 Online zuozuo:欢迎商业合作 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo :联系我们:VX :tja6288 / EMAIL: 347969164@qq.com 文章目录 jetbrains InterlliJ …...

百日筑基第三十四天-JAVA中的强/软/弱/虚引用

百日筑基第三十四天-JAVA中的强/软/弱/虚引用 Java对象的引用被划分为4种级别&#xff0c;分别为强引用、软引用、弱引用以及虚引用。帮助程序更加灵活地控制对象的生命周期和JVM进行垃圾回收。 强引用 强引用是最普遍的引用&#xff0c;一般把一个对象赋给一个引用变量&…...

C语言100基础拔高题(3)

1.利用递归函数调用方式&#xff0c;将所输入的5个字符&#xff0c;以相反顺序打印出来。 解题思路&#xff1a;通过反复调用一个打印最后一个元素的函数&#xff0c;来实现此功能。源代码如下: #include<stdio.h> void oposize(char str[], int len); int main() {//利…...

AV1技术学习:Constrained Directional Enhancement Filter

CDEF允许编解码器沿某些(可能是倾斜的)方向应用非线性消阶滤波器。它以88为单位进行。如下图所示&#xff0c;通过旋转和反射所示的三个模板来定义八个预设方向。 Templates of preset directions and their associated directions. The templates correspond to directions of…...

C++的STL简介(一)

目录 1.什么是STL 2.STL的版本 3.STL的六大组件 4.string类 4.1为什么学习string类&#xff1f; 4.2string常见接口 4.2.1默认构造 ​编辑 4.2.2析构函数 Element access: 4.2.3 [] 4.2.4迭代器 ​编辑 auto 4.2.4.1 begin和end 4.2.4.2.regin和rend Capacity: 4.2.5…...

DNS劫持

目录 一、DNS的基本概念 二、DNS劫持的工作原理 三、DNS劫持的影响 四、DNS劫持的防范措施 DNS劫持&#xff1a;一种网络安全威胁的深入分析 在当今网络日益发达的时代&#xff0c;互联网已经成为了人们日常生活中不可或缺的一部分。然而&#xff0c;随着网络技术的进步&am…...

Centos7解决网关ens33的静态地址配置

原因复现: 我登录一段时间之后我ens33的网关ip地址发生了改变 原ip地址配置 现有地址: 根据文心一言提示 修改配置文件 sudo vi /etc/sysconfig/network-scripts/ifcfg-ens33 我的原配置 [rootlocalhost ~]# sudo vi /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"…...

python中常用于构建cnn的库有哪些

在Python中&#xff0c;有多种库可用于构建卷积神经网络&#xff08;CNN&#xff09;。以下是几种常用的库&#xff1a; 1. TensorFlow TensorFlow是一个开源深度学习框架&#xff0c;由Google Brain团队开发。它支持构建和训练各种神经网络模型&#xff0c;包括卷积神经网络。…...

【前端 17】使用Axios发送异步请求

Axios 简介与使用&#xff1a;简化 HTTP 请求 在现代 web 开发中&#xff0c;发送 HTTP 请求是一项常见且核心的任务。Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;适用于 node.js 和浏览器&#xff0c;它提供了一种简单的方法来发送各种 HTTP 请求。本文将介绍 Axio…...

Unity Android接入SDK 遇到的问题

1. buildtools、platformtools、commandline tools 以及compiled sdk version、buildtools sdk version、target sdk version 的说明 Android targetSdkVersion了解一下 - 简书 2. 查看.class 和.jar文件 jd_gui 官网地址&#xff1a; 下载jd_gui 工具 &#xff0c;或者 idea 下…...

基于深度学习的复杂策略学习

基于深度学习的复杂策略学习&#xff08;Complex Strategy Learning&#xff09;是通过深度学习技术&#xff0c;特别是强化学习和模仿学习&#xff0c;来开发和优化解决复杂任务的策略。这类技术广泛应用于自动驾驶、游戏AI、机器人控制和金融交易等领域。以下是对这一领域的系…...

【Golang 面试 - 进阶题】每日 3 题(一)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…...

周报 Week 3:

补题链接&#xff1a; Week 3 DAY 1-CSDN博客 河南萌新联赛2024第&#xff08;二&#xff09;场&#xff1a;南阳理工学院-CSDN博客 Week 3 DAY 5:-CSDN博客 Week 3 DAY 6-CSDN博客 这周题单是动态规划——&#xff08;背包问题&#xff0c;线性dp&#xff09;&#xff1a…...

开源消息队列比较

目录 1. Apache Kafka 1.1安装步骤 1.1.1使用Docker安装 1.1.1手动安装 1.2 C#使用示例代码 1.2.1 安装Confluent.Kafka 1.2.2生产者代码示例 1.2.3消费者代码示例 1.3特点 1.4使用场景 2. RabbitMQ 2.1安装步骤 2.1.1使用Docker安装 2.1.2手动安装 2.2 C#使用示…...

【前端逆向】最佳JS反编译利器,原来就是chrome!

有时候需要反编译别人的 min.js。 比如简单改库、看看别人的 min,js 干了什么&#xff0c;有没有重复加载&#xff1f;此时就需要去反编译Javascript。 Vscode 里面有一些反编译插件&#xff0c;某某Beautify等等。但这些插件看人品&#xff0c;运气不好搞的话&#xff0c;反…...

微信小程序根据动态权限展示tabbar

微信小程序自定义 TabBar 后根据权限动态展示tabbar 在微信小程序开发中,自定义 TabBar 可以让应用更具灵活性和个性化。特别是在用户根据不同权限展示不同的 TabBar 内容时,正确的实现方法能够提升用户体验。本篇文章将分享如何使用事件总线实现权限变动时动态更新自定义 T…...

开源安全信息和事件管理(SIEM)平台OSSIM

简介 OSSIM&#xff0c;开源安全信息和事件管理&#xff08;SIEM&#xff09;产品&#xff0c;提供了经过验证的核心SIEM功能&#xff0c;包括事件收集、标准化和关联。 OSSIM作为一个开源平台&#xff0c;具有灵活性和可定制性高的优点&#xff0c;允许用户根据自己的特定需…...

【DP】01背包

算法-01背包 前置知识 DP 思路 01背包一般分为两种&#xff0c;不妨叫做价值01背包和判断01背包。 价值01背包 01背包问题是这样的一类问题&#xff1a;给定一个背包的容量 m m m 和 n n n 个物品&#xff0c;每个物品有重量 w w w 和价值 v v v&#xff0c;求不超过背…...

50、PHP 实现选择排序

题目&#xff1a; PHP 实现选择排序 描述&#xff1a; n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果&#xff1a;(1)初始状态&#xff1a;无序区为R[1…n]&#xff0c;有序区为空。(2)第1趟排序在无序区R[1…n]中选出关键字最小的记录R[k]&#xff0c;将…...

17.延迟队列

介绍 延迟队列&#xff0c;队列内部是有序的&#xff0c;延迟队列中的元素是希望在指定时间到了以后或之前取出和处理。 死信队列中&#xff0c;消息TTL过期的情况其实就是延迟队列。 使用场景 1.订单在十分钟内未支付则自动取消。 2.新创建的店铺&#xff0c;如果十天内没…...

KCache-go本地缓存,支持本地缓存过期、缓存过期自维护机制。

GitHub - kocor01/kcache: go 本地缓存解决方案&#xff0c;支持本地缓存过期、缓存过期自维护机制。 最近系统并发很高&#xff0c;单接口10W的 QPS&#xff0c;对 redis 压力很大&#xff0c;大量的热KEY导致 redis 分片CPU资源经常告警。计划用 go 本地缓存缓解 redis 的压…...

斯坦福UE4 C++课学习补充 14:UMG-优化血量条

文章目录 一、优化执行效率二、简单脉冲动画 一、优化执行效率 绑定事件需要每一帧检查绑定对象是否有变化&#xff0c;势必造成CPU资源的浪费&#xff0c;因此优化执行效率的思路是&#xff1a;UI组件不再自行每帧查询血量&#xff0c;而是让血量自己在发生变化的同时通知UI进…...

在生信分析中大家需要特别注意的事情​

在生信分析中大家需要特别注意的事情 标准的软件使用和数据分析流程 1. 先看我的b站教学视频 2. 先从我的百度网盘把演示数据集下载下来&#xff0c;先把要运行的模块的演示数据集先运行一遍 3. 前两步都做完了&#xff0c;演示数据集也运行成功了&#xff0c;并且知道了软件…...

Java工厂模式详解:方法工厂模式与抽象工厂模式

Java工厂模式详解&#xff1a;方法工厂模式与抽象工厂模式 一、引言 在Java开发中&#xff0c;设计模式是解决常见软件设计问题的一种有效方式。工厂模式作为创建型设计模式的一种&#xff0c;提供了灵活的对象创建机制&#xff0c;有助于降低代码的耦合度&#xff0c;提高系…...

springSecurity学习之springSecurity用户单设备登录

用户只能单设备登录 有时候在同一个系统中&#xff0c;只允许一个用户在一个设备登录。 之前的登陆者被顶掉 将最大会话数设置为1就可以保证用户只能同时在一个设备上登录 Override protected void configure(HttpSecurity http) throws Exception {http..anyRequest().aut…...

微信小程序实现聊天界面,发送功能

.wxml <scroll-view scroll-y"true" style"height: {{windowHeight}}px;"><view wx:for"{{chatList}}" wx:for-index"index" wx:for-item"item" style"padding-top:{{index0?30:0}}rpx"><!-- 左…...

【强化学习的数学原理】课程笔记--5(值函数近似,策略梯度方法)

目录 值函数近似一个例子TD 算法的值函数近似形式Sarsa, Q-learning 的值函数近似形式Deep Q-learningexperience replay 策略梯度方法&#xff08;Policy Gradient&#xff09;Policy Gradient 的目标函数目标函数 1目标函数 2两种目标函数的同一性 Policy Gradient 目标函数的…...

前端Long类型精度丢失:后端处理策略

文章目录 精度丢失的具体原因解决方法1. 使用 JsonSerialize 和 ToStringSerializer2. 使用 JsonFormat 注解3. 全局配置解决方案 结论 开发商城管理系统的品牌管理界面时&#xff0c;发现一个问题&#xff0c;接口返回品牌Id和页面展示的品牌Id不一致&#xff0c;如接口返回的…...

C++ | Leetcode C++题解之第300题最长递增子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:int lengthOfLIS(vector<int>& nums) {int len 1, n (int)nums.size();if (n 0) {return 0;}vector<int> d(n 1, 0);d[len] nums[0];for (int i 1; i < n; i) {if (nums[i] > d[len])…...

springboo 整合 redis

springBoot 整合 redis starter启动依赖。—包含自动装配类—完成相应的装配功能。 引入依赖 <!--引入了redis整合springboot 的依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…...

dpdk编译安装以及接收udp报文(基于ubuntu)

目录 1、编译 2、设置运行环境 3、使用dpdk接收udp报文 3.1、设置发送端arp信息 3.2、测试 3.3、代码 4、其他 1、编译 代码下载&#xff1a; DPDK 下载版本&#xff1a;DPDK 19.08.2 export RTE_SDK/root/dpdk-stable-19.08.2/ export RTE_TARGETx86_64-native-li…...

【计算机网络】OSPF单区域实验

一&#xff1a;实验目的 1&#xff1a;掌握在路由器上配置OSPF单区域。 2&#xff1a;学习OSPF协议的原理&#xff0c;及其网络拓扑结构改变后的变化。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS交换机、网线、内网网卡接口、Windows 2019操作系统的计算机等。…...

Java聚合快递小程序对接云洋系统程序app源码

​一场物流效率的革命 引言&#xff1a;物流新时代的序章 在数字化浪潮席卷各行各业的今天&#xff0c;物流行业也迎来了前所未有的变革。为了进一步提升物流效率&#xff0c;优化用户体验&#xff0c;聚合快递系统与云洋系统小程序的对接成为了行业内外关注的焦点。这一创新…...

【React】详解组件通信:从基础到进阶的全面指南

文章目录 一、父组件向子组件传递数据1. 基本概念2. 示例代码3. 详解定义子组件 Son定义父组件 App导出父组件 App数据流props 的内容 二、子组件向父组件传递数据1. 基本概念2. 示例代码3. 详解引入React库和useState钩子定义子组件 Son定义父组件 App导出父组件 App数据流 三…...

【vluhub】zabbix漏洞

介绍&#xff1a; zabbix是对服务器资源状态例如、内存空间、CPU、程序运行状态进行检测、设置预警值、短信设置等功能等一款开源工具。配置不当存在未授权,SQL注入漏洞 弱口令 nameadmin&passwordzabbix nameguest&password POST /index.php HTTP/1.1 Host: 192.1…...

openGauss触发器详解

openGauss 是一款开源关系型数据库管理系统&#xff0c;广泛应用于企业级应用中。随着数据量的增长和业务逻辑的复杂化&#xff0c;数据库管理和操作的自动化需求越来越高。触发器&#xff08;Triggers&#xff09;作为数据库中重要的编程工具&#xff0c;能够极大地简化复杂操…...

抄作业-跟着《React通关秘籍》捣鼓React-playground-上集

文章目录 前言1. 搭建react 开发环境2、react hooks 知识3. 目标&#xff1a;跟着小册实现 react-playground3.1 整体布局初始化项目使用Alloment 来实现左右分屏的拖拉功能 3.2 代码编辑器Monaco Editor 3.3 实现了多文件的切换用 useContext 来共享数据。优化 tab的样式&…...

80后最后的书信 年代

当时11亿人口只有1.8万部固定电话 中国几千年来 鱼传尺素 雁寄鸿书 写信最后要写 亲啓 如有照片&#xff0c;封面要写内有照片&#xff0c;请勿折叠 信的开头应该是 见字如面&#xff0c;展信舒颜 如果拜托别人做事情&#xff0c;最后要写为盼 最后要写 某某草 书未尽…...

软考-软件设计师(4)-计算机网络与安全:OSI七层、子网划分、网络安全控制技术、网络安全协议、网络安全威胁、对称与非对称加密等高频考点

场景 软考-软件设计师-计算机网络与信息安全模块高频考点整理。 以下为高频考点、知识点汇总,不代表该模块所有知识点覆盖,请以官方教程提纲为准。 注: 博客:霸道流氓气质-CSDN博客 实现 知识点 OSI/RM七层模型 注意各层的主要功能,特别是表示层负责数据的加密、压…...

Unity横板动作游戏 -为什么我又开始学习Unity,而不是Godot。

Readme 最近开始学习Unity制作2D动作游戏&#xff0c;由于一些操作第一次接触&#xff0c;为了加深印象&#xff0c;准备写这样一篇同步教程的笔记。 之前也接触过Unity&#xff0c;用 Unity 制作过一个非常简单的小游戏 Flappy Bird&#xff0c;并且魔改成了泰拉瑞亚的版本。…...

什么是NIO

NIO&#xff08;New Input/Output&#xff09;&#xff0c;也称为Java非阻塞IO&#xff0c;是从Java 1.4版本开始引入的一个新的IO API&#xff0c;旨在提供一种比传统的阻塞IO更高效、更灵活的IO操作方式。 一 NIO用法的详细介绍 NIO支持面向缓冲区的、基于通道的IO操作&…...

PHP switch 替代品 match

match 是 PHP 8 中引入的新特性。在 PHP 8 中&#xff0c;match 用作新的类型安全的替代 switch 语句。它提供了更清晰、更简洁的语法&#xff0c;同时还支持表达式作为条件&#xff0c;可以更轻松地处理复杂的条件逻辑。 在 match 表达式中&#xff0c;每个分支都是一个条件和…...