一文总结代理:代理模式、代理服务器
概述
代理在计算机编程领域,是一个很通用的概念,包括:代理设计模式,代理服务器等。
代理类持有具体实现类的实例,将在代理类上的操作转化为实例上方法的调用。为某个对象提供一个代理,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可以去掉功能服务或者增加额外的功能。
角色
代理模式一般涉及到的角色有:
- 对象:Client,请求客户端
 - 抽象角色:Subject,声明真实对象和代理对象的共同接口,对应代理接口;
 - 真实角色:RealSubject,代理角色所代表的真实对象,是最终要引用的对象,对应委托类;
 - 代理角色:Proxy,代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装,对应代理类,可以有未公开的方法。
 
UML类图如下:
 
 调用顺序示意图:
 
分类
代理从类型来分类:
- 虚代理:虚拟代理,Virtual Proxy,根据需要来创建开销很大的对象,该对象只有在需要时才会被真正创建,即所谓的延迟加载;
 - 远程代理:Remote Proxy,用来在不同的地址空间上代表同一个对象,这个不同的地址空间可以是在本机,也可以在其它机器上,在Java里面最典型的就是RMI技术;
 - copy-on-write代理:在客户端操作时,只有对象确实改变后,才会真的拷贝一个日标对象,算是虚代理的一个分支;
 - 保护代理:Protect Proxy,控制对原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问;
 - Cache代理:为那些昂贵操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果;
 - 防火墙代理:保护对象不被恶意用户访问和操作;
 - 同步代理:使多个用户能够同时访问目标对象而没有冲突;
 - 智能引用代理:Smart Reference Proxy,在访问对象时执行一些附加操作。比如,对指向实际对象的引用计数、第一次引用一个持久对象时,将它装入内存等
 
另外,根据代理类的生成时间的不同,可分为静态代理和动态代理。
静态代理
代理和被代理对象(目标对象)在代理之前是确定的,都实现相同的接口或者继承相同的抽象类。目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态,在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定。
实现静态代理有继承、聚合方法。
优点:业务类只需要关注业务逻辑本身,保证业务类的重用性。
缺点:
- 需要大量硬编码
 - 一个代理类只能代理一个业务类
 - 如果业务类增加方法时,相应的代理类也要增加方法
 
动态代理
动态代理类的源码是在程序运行期间由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动态代理的步骤
- 创建被代理的类以及接口;
 - 创建一个实现接口InvocationHandler,并重写invoke方法的类;
 - 调用Proxy的静态方法,创建代理类
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h); - 通过代理调用方法。
 
实例
代表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。
缺点:
- 仍有硬编码
 - 需要在对象初始化时,使用特定的方式进行初始化
 
源码分析
基于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网络拥挤的状况,提高用户访问网站的响应速度。
区别
正向代理解决的是客户端访问互联网的问题,客户端知道目标的;
 反向代理解决的是互联网收到客户端请求,如何把请求转到内网服务器的问题,不知道目标,代理的是服务端。
相关文章:
一文总结代理:代理模式、代理服务器
概述 代理在计算机编程领域,是一个很通用的概念,包括:代理设计模式,代理服务器等。 代理类持有具体实现类的实例,将在代理类上的操作转化为实例上方法的调用。为某个对象提供一个代理,以控制对这个对象的…...
探索 Kubernetes 持久化存储之 Longhorn 初窥门径
作者:运维有术星主 在 Kubernetes 生态系统中,持久化存储扮演着至关重要的角色,它是支撑业务应用稳定运行的基石。对于那些选择自建 Kubernetes 集群的运维架构师而言,选择合适的后端持久化存储解决方案是一项至关重要的选型决策。…...
全国区块链职业技能大赛样题第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(qbr)PLY网桥br-intbr-tunbr-routerbrcps常见网桥链接接口 QVOQVIQVMPatch网桥和接口的工作原理应用场景 虚拟化环境数据中心网络云计算平台 1. 引言 开放虚拟交换机(Open vSwitch,简称OVS&…...
创建最最最纯净 Windows 11/10 系统镜像!| 全网独一份
前期准备工作 1.配置系统应答文件:【点击前往】 2.系统镜像编辑器: 【点击下载】 3.Windows 系统镜像官方下载: 【Windows 11】、【Windows 10】【官方密钥】 4.翻译工具 【GitHub】 5.详细的设置教程 5.1先打开配置系统应答文件&#…...
带你学会Git必会操作
文章目录 带你学会Git必会操作1Git的安装2.Git基本操作2.1本地仓库的创建2.2配置本地仓库 3.认识一些Git的基本概念3.1操作流程: 4.一些使用场景4.1添加文件场景一4.2查看git文件4.3修改文件4.4Git版本回退4.5git撤销修改 5.分支管理5.1查看分支5.2创建本地分支5.3切…...
clickhouse处理readonly报错
1,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命令行的方式,将本地项目上传到远程仓库
在国内的开发环境中,git的使用是必不可少的。Git 是一款分布式版本控制系统,用于有效管理和追踪文件的变更历史及协作开发。本片文章就来介绍一下怎样使用git命令行的方式,将本地项目上传到远程仓库,虽然现在的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种级别,分别为强引用、软引用、弱引用以及虚引用。帮助程序更加灵活地控制对象的生命周期和JVM进行垃圾回收。 强引用 强引用是最普遍的引用,一般把一个对象赋给一个引用变量&…...
C语言100基础拔高题(3)
1.利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。 解题思路:通过反复调用一个打印最后一个元素的函数,来实现此功能。源代码如下: #include<stdio.h> void oposize(char str[], int len); int main() {//利…...
AV1技术学习:Constrained Directional Enhancement Filter
CDEF允许编解码器沿某些(可能是倾斜的)方向应用非线性消阶滤波器。它以88为单位进行。如下图所示,通过旋转和反射所示的三个模板来定义八个预设方向。 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类? 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劫持:一种网络安全威胁的深入分析 在当今网络日益发达的时代,互联网已经成为了人们日常生活中不可或缺的一部分。然而,随着网络技术的进步&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中,有多种库可用于构建卷积神经网络(CNN)。以下是几种常用的库: 1. TensorFlow TensorFlow是一个开源深度学习框架,由Google Brain团队开发。它支持构建和训练各种神经网络模型,包括卷积神经网络。…...
【前端 17】使用Axios发送异步请求
Axios 简介与使用:简化 HTTP 请求 在现代 web 开发中,发送 HTTP 请求是一项常见且核心的任务。Axios 是一个基于 Promise 的 HTTP 客户端,适用于 node.js 和浏览器,它提供了一种简单的方法来发送各种 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 官网地址: 下载jd_gui 工具 ,或者 idea 下…...
基于深度学习的复杂策略学习
基于深度学习的复杂策略学习(Complex Strategy Learning)是通过深度学习技术,特别是强化学习和模仿学习,来开发和优化解决复杂任务的策略。这类技术广泛应用于自动驾驶、游戏AI、机器人控制和金融交易等领域。以下是对这一领域的系…...
【Golang 面试 - 进阶题】每日 3 题(一)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
