java之动态代理

1 代理模式

  • 代理模式提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作扩展目标对象的功能。简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。但是对于真正的调用来说, 实际上并不关心这个代理对象, 只要能够实现相应的业务逻辑就好。

  • 举个例子,我们生活中经常到火车站去买车票,但是人一多的话,就会非常拥挤,于是就有了代售点,我们能从代售点买车票了,这就是代理模式的体现,代售点代理了火车站售票对象,提供购买车票的方法。

1.1 代理模式

1.1.1 定义

(1)UML类图

  • Subject --- 抽象主题类,定义了代理对象真实对象的共同接口方法,可以理解为定义了某一种业务需求的实现规范。既可以是接口也可以是抽象类,其中声明了需要被实现的方法。

  • RealSubject --- 真实主题类,该类可以被称为被委托类或被代理类,该类定义了代理对象所表示的真实对象,实现了Subject接口方法。

  • Proxy --- 代理类,该类也被称为委托类或代理类,该类中持有一个真实主题类的引用,同样实现了Subject接口。在其实现的接口方法中调用代理类中相应的接口方法,在此基础上附加其他动作。Client端通过代理类间接调用的真实主题类中的方法,由其执行真正的业务逻辑。

  • Client --- 客户端。

要求:代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

例如:电影公司委托电影院播放电影,电影院想要在播放电影的时候,加一些广告或服务项目赚取收

益。(使用代码来模拟)

(1)静态代理服务接口: MovieService

  • 通用的接口是代理模式实现的基础。 MovieService接口代表电影播放服务

(2)静态代理服务实现类: MovieServiceImpl

  • MovieService 接口的实现类,可以当作电影公司,作为接口实现类,要求必须定义接口中声明的所有方法。

(3)服务的代理类: MovieProxy

  • MovieService 服务的代理类,就是电影服务的代理对象,当作电影院,代理了电影公司提供的电影播放服务。方法实现时,主要调用服务实现类提供的方法,并在其执行前后添加附加功能。

1.1.2相关案例

案例1:静态代理-实操

静态代理服务接口MovieService

package com.StaticProxy;
​
/*** 定义一个通用的接口 MovieService,代表电影播放服务**/
public interface MovieService {void play();
​
​
}
​

静态代理服务实现类 MovieServiceImpl,

package com.StaticProxy;
​
/*** 静态代理服务实现类 MovieServiceImpl,**/
public class MovieServiceImpl implements MovieService{/*** 定义MovieService接口的类*/
//    @Overridepublic void play() {System.out.println("Showing a movie:Tom and Jerry....");}
​
}
​

服务的代理类 MovieProxy

package com.StaticProxy;
​
/*** 服务的代理类 MovieProxy**/
public class MovieProxy implements MovieService{MovieServiceImpl movieService;
​/*public static void main(String[] args) {test1();}*//* public static void test1(){movieService.play();}*/
​public MovieProxy(MovieServiceImpl movieService) {super();this.movieService = movieService;}
​/*** 重写 play() 方法,调用MovieServiceImpl的play() 方法前后,附加广告提示*/
//    @Overridepublic void play() {advertise(true);movieService.play();advertise(false);}
​/*** 宣传方法* @param isStart*/public void advertise(boolean isStart) {if(isStart == true){System.out.println("The movie starts.");}else{System.out.println("The movie is over.");}}
}
​

测试代码

package com.StaticProxy;
​
/*** 测试代码**/
public class Demo {public static void main(String[] args) {new MovieProxy(new MovieServiceImpl()).play();}
}

输出结果

案例2

package com.StaticProxy1;
/*** 静态代理 设计模式* 1、真实角色* 2、代理角色: 持有真实角色的引用* 3、二者 实现相同的接口** @author Administrator**/
public class Demo01 {/*** @param args*/public static void main(String[] args) {//创建真实角色Marry you =new You();//创建代理角色 +真实角色的引用WeddingCompany company =new WeddingCompany(you);//执行任务company.marry();}
​
}
//接口
interface Marry{public abstract void marry();
}
//真实角色
class You implements Marry{
​public void marry() {System.out.println("you and  嫦娥结婚了....");}
​
}
//代理角色
class WeddingCompany implements Marry{private Marry you;public WeddingCompany() {}
​public WeddingCompany(Marry you) {this.you = you;}private void before(){System.out.println("布置猪窝....");
​}private void after(){System.out.println("闹玉兔....");}public void marry() {before();you.marry();after();}
}
​

输出结果

1.1.3 静态代理缺陷

  1. 代理复杂,难于管理

    • 当需要代理的目标类数量较多时,需要为每个目标类手动编写一个代理类,这会导致代码量增加,且难以统一管理和维护。

  2. 代理类依赖目标类

    • 静态代理的代理类与目标类紧密耦合,当目标类发生变化时(如增加、删除或修改方法),代理类也需要进行相应的修改,这增加了维护的复杂性。

  3. 代理类过多

    • 对于每个目标类,都需要一个与之对应的代理类。当目标类数量较多时,会导致代理类数量过多,增加了系统的复杂度。

  4. 不灵活

    • 静态代理在编译时期就确定了代理对象和目标对象,无法动态地改变代理对象。如果需要改变代理对象,需要重新编译和部署代码。

  5. 代码冗余

    • 由于每个目标对象都需要对应一个代理类,这会导致代码的冗余。特别是当有多个目标对象时,会增加代码量和维护成本。

  6. 维护困难

    • 当目标对象发生变化时,代理类也需要同步更新,维护起来相对困难。特别是在有大量代理类时,更新代理类会带来一定的工作量。

  7. 性能考虑

    • 虽然静态代理在编译时期就确定了代理对象和目标对象,因此性能相对较高,但相对于直接调用目标对象的方法,静态代理仍然增加了一层调用开销。

静态代理 vs 动态代理:

  • 静态代理需要手动编写代码让代理类实现某接口。而动态代理则可以让程序在运行时自动在内存中创建一个实现某接口的代理,而不需要去手动定义代理类。

  • 静态代理在程序运行前,代理类的class文件(类字节码)就已经存在了。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

1.2 动态代理

  • 与静态代理相比,多了InvocationHandler角色和一个Proxy角色,InvocationHandler是java提供的一个接口,我们需要定义一个类实现InvocationHandler接口,这里就叫DynamicProxy角色;Proxy是java提供用于动态生成ProxySubject的一个类,它需要ProxySubject继承。

  • 我们看到DynamicProxy在ProxySubject和RealSubject之前起到了中间人的角色,ProxySubject会把事情委托给DynamicProxy来做,而DynamicProxy最终把事情委托给RealSubject来做

动态代理的实现方式有很多种,比如 JDK 动态代理、CGLIB 动态代理等等。

1.2.1 场景实现-JDK动态代理

JDK提供了java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类。

java.lang.reflect.InvocationHandler 接口中仅声明了一个方法invoke(),第一个参数 proxy一般是指代理类,method是被代理的方法,args为方法中声明的形参。

public interface InvocationHandler{public Object invode{Object proxy,Method method, Object[] args}
}

JDK 动态代理常用的API:

  • java.lang.reflect.Proxy 动态代理类中提供的 getProxyClass() 静态方法可以用来获取一个代理Class对象,其接受的参数为类加载器和目标类实现的接口。

  • public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)Proxy类提供的另一个静态方法 newProxyInstance() 可以直接获取代理实例对象,连创建代理类对象的过程都封装起来了。

  • public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandlerh)loader是类加载器,interfaces 是代理要实现的服务接口,h是一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。

关注 Proxy.newProxyInstance() 方法

(1)判断传入的InvocationHandler实例对象是否为null,并对传入的接口进行克隆权限校验。获取系统安全接口(安全管理器),如果不为空,检查创建代理类所需的权限

(2)查找或生成指定的代理类对象,要求调用此函数之前必须调用checkProxyAccess方法执行权限检查。首先判断接口数量,过多则抛出异常。随后调用 proxyClassCache.get(loader, interfaces) 方法,参数接收类加载器和接口数组,从 proxyClassCache 缓存中获取代理类,如果找不到,则通过ProxyClassFactory创建代理类。

方法二:添加系统参数,将JDK动态代理生成的class文件保存到本地,默认保存路径为

com.sun.proxy

System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

随后反编译类文件即可。

JDK动态代理 – 源码浅析:

  • 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以 JDK的动态代理不支持对实现类的代理,只支持接口的代理。

  • 提供了一个使用InvocationHandler作为参数的构造方法

  • 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法。

  • 生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。代理类实现代理接口的play()方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。

1.2.2 场景实现-CGLib

CGLib(Code Generation Library)是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象,从而实现对目标对象功能的扩展。

CGLIB作为一个开源项目,其代码托管在github,地址为:GitHub - cglib/cglib: cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access.

CGLib vs JDK动态代理:

  • 与动态代理不同的是,动态代理是基于Java 反射机制实现的,必须实现接口的业务类才能使用这种办法生成代理对象。而 CGLib 则是基于 ASM机制实现,通过生成业务类的子类作为代理类,它允许我们在运行时对字节码进行修改和动态生成

  • 与动态代理相比,JDK动态代理限制了只能基于接口设计,对于没有接口的情况,JDK方式无法解决,而 CGLib则可以解决这一问题,可以通过继承方式实现代理

CGLib – 常用API:

  • net.sf.cglib.proxy.Enhancer 类,(字节码)增强器,可以类比于JDK中的Proxy类,与之不同的是,Enhancer既能够代理普通的java类,也能够代理接口。 Enhancer.setSuperclass() 用来设置被代理的类。 Enhancer.create()方法是用来创建增强对象。

  • Callback,即回调,它是一个标识接口(空接口,没有任何方法),它的回调时机是生成的代理类的方法被调用的时候,即生成的代理类的方法被调用的时候,Callback的实现逻辑就会被调用。Enhancer通过 setCallback() 和setCallbacks() 设置Callback,设置了多个Callback实例将会按照设置的顺序进行回调。

  • net.sf.cglib.proxy.MethodInterceptor 接口,即方法拦截器,设置了MethodInterceptor后,代理类的所有方法调用都会转而执行这个接口中的intercept方法而不是原方法。如果需要在intercept方法中执行原方法可以使用参数method基于代理实例obj进行反射调用。

例如1:

(1) 创建服务实现类:MovieServiceImpl即需要被代理的类,不需要实现顶层接口。

package com.CGLibTest;
/*** 需要被代理的服务类 MovieServiceImpl,不需要实现顶层接口**/
public class MovieServiceImpl{/*** 定义服务方法*/public void startMovie() {System.out.println("Start the movie....");
​}
​public void endMovie() {System.out.println("The movie is over");}
​public final void playFinal() {System.out.println("this is final!");}
}

(2) 创建拦截器:MyInterceptor,当我们调用被代理类中的某个方法时,实际首先调用的是拦截器的intercept方法,如果需要执行原来的方法,则调用 method.invoke(s, args);

package com.CGLibTest;
​
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/*** 拦截器**/
public class MyInterceptor implements MethodInterceptor {
​private MovieServiceImpl service;
​public MyInterceptor(MovieServiceImpl service){this.service = service;}
​public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("=====================interceptor=====================");return method.invoke(service, args);}
}

(3)测试类

package com.CGLibTest;
​
import com.CGLibTest.fianlTest.FinalInterceptor;
import com.CGLibTest.fianlTest.FinalServiceImpl;
import net.sf.cglib.proxy.Enhancer;
​
/*** 测试方法**/
public class Demo {public static void test1(){// 通过CGLIB动态代理获取代理对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MovieServiceImpl.class);enhancer.setCallback(new MyInterceptor(new MovieServiceImpl()));MovieServiceImpl helper = (MovieServiceImpl) enhancer.create();helper.startMovie();helper.endMovie();System.out.println();helper.playFinal();}
​
​
​
​public static void main(String[] args) {test1();}
}
​

每次在执行原来的方法之前,都会先执行拦截器中的扩展代码。被final修饰的方法没有被拦截,没有

执行扩展代码,仅仅执行了原来的方法。

输出结果:、

例如2:

(1)用final修饰需要被代理的服务类

package com.CGLibTest.fianlTest;
​
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/*** 拦截器**/
public class FinalInterceptor implements MethodInterceptor {
​private FinalServiceImpl service;
​public FinalInterceptor(FinalServiceImpl service){this.service = service;}
​public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("=====================interceptor=====================");return method.invoke(service, args);}
}
package com.CGLibTest.fianlTest;
​
​
/*** 需要被代理的服务类 MovieServiceImpl,不需要实现顶层接口**/
public final class FinalServiceImpl {/*** 定义服务方法*/public void startMovie() {System.out.println("Start the movie....");
​}
​public void endMovie() {System.out.println("The movie is over");}
​public final void playFinal() {System.out.println("this is final!");}
}
​
package com.CGLibTest;
​
import com.CGLibTest.fianlTest.FinalInterceptor;
import com.CGLibTest.fianlTest.FinalServiceImpl;
import net.sf.cglib.proxy.Enhancer;
​
/*** 测试方法**/
public class Demo {/** 测试代理Final修饰的类*/public static void test2(){// 通过CGLIB动态代理获取代理对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(FinalServiceImpl.class);enhancer.setCallback(new FinalInterceptor(new FinalServiceImpl()));FinalServiceImpl helper = (FinalServiceImpl) enhancer.create();helper.playFinal();}
​
​public static void main(String[] args) {test2();}
}

测试结果:

CGLIB缺点:由于CGLib是基于继承的方式实现类的动态代理,对于final方法和final类无法进行代理。

1.2.3 其他相关案例

例如:电影公司委托电影院播放电影,电影院想要在播放电影的时候,加一些广告或服务项目赚取收益。(使用代码来模拟)

服务接口: MovieService

服务实现类: MovieServiceImpl

动态代理类: MovieHandler

每个代理的实例都有一个与之关联的 InvocationHandler 接口实现类,这里实现了InvocationHandler接口,要求必须定义其声明的invoke()方法,用来反射调用执行方法。动态代理类构造器传入要代理的服务类,并使用成员变量接收,在invoke()方法中引用被代理的服务类,并调用其方法。

package com.DynamicProxy;
​
/*** 定义一个通用的接口 MovieService,代表电影播放服务**/
public interface MovieService {void play();
}
​
package com.DynamicProxy;
​
/*** 动态代理服务实现类 MovieServiceImpl**/
public class MovieServiceImpl implements MovieService {/*** 定义MovieService接口的类*/
//    @Overridepublic void play() {System.out.println("Showing a movie:Tom and Jerry....");}
}
​
package com.DynamicProxy;
​
/*** 动态代理服务实现类 MovieServiceImpl**/
public class MovieServiceImpl2 implements MovieService {/*** 定义MovieService接口的类*/
//    @Overridepublic void play() {System.out.println("Showing a movie:doraemon....");}
}
​
package com.DynamicProxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
/*** 动态代理类 MovieHandler**/
public class MovieHandler implements InvocationHandler {private Object movieService;
​public MovieHandler(Object movieService) {this.movieService = movieService;   //成员变量接收目标对象的引用}
​/*** 宣传方法* @param isStart*/public void advertise(boolean isStart) {if(isStart == true){System.out.println("The movie starts.");}else{System.out.println("The movie is over.");}}
​
//    @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {advertise(true);method.invoke(movieService,args);advertise(false);return null;}
}
​
package com.DynamicProxy;
​
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
​
/*** 测试代码**/
public class Demo {
​/*** 执行单个服务*/public static void test1(){MovieService movieService = new MovieServiceImpl();InvocationHandler handler = new MovieHandler(movieService);
​MovieService dynamicProxy = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler);dynamicProxy.play();}
​/*** 执行多个服务*/public static void test2(){List<MovieService> movieServices = new ArrayList<MovieService>();MovieService movieService = new MovieServiceImpl();MovieService movieService1 = new MovieServiceImpl2();movieServices.add(movieService);movieServices.add(movieService1);for (int i = 0; i < movieServices.size(); i++) {InvocationHandler handler = new MovieHandler(movieServices.get(i));MovieService dynamicProxy = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler);dynamicProxy.play();}/* MovieService movieService1 = new MovieServiceImpl();MovieService movieService2 = new MovieServiceImpl2();InvocationHandler handler1 = new MovieHandler(movieService1);InvocationHandler handler2 = new MovieHandler(movieService2);
​MovieService dynamicProxy1 = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(),handler1);dynamicProxy1.play();
​MovieService dynamicProxy2 = (MovieService) Proxy.newProxyInstance(MovieService.class.getClassLoader(), MovieServiceImpl2.class.getInterfaces(),handler2);dynamicProxy2.play();*/}
​/*** 代理类写入本地*/public static void test3() throws Exception {// 这里我们将jdk生成的代理类写入本地文件FileOutputStream out = null;try {byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{InvocationHandler.class});out = new FileOutputStream("E:\\java_project\\java_code_4\\code\\DynamicProxy\\target\\classes\\com\\Proxy3.class");//自行修改路径out.write(classFile);} catch (Exception e) {e.printStackTrace();} finally {try {if (out != null) {out.flush();out.close();}} catch (IOException e) {e.printStackTrace();}
​}}
​
​
​public static void main(String[] args) throws Exception {System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");test3();
//        test2();}
}
​

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

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

相关文章

网络io与select,poll,epoll

前言 网络 IO&#xff0c;会涉及到两个系统对象&#xff0c;一个是用户空间调用 IO 的进程或者线程&#xff0c;另一个是内核空间的内核系统&#xff0c;比如发生 IO 操作 read 时&#xff0c;它会经历两个阶段&#xff1a; 1. 等待数据准备就绪 2. 将数据从内核拷贝到进程或…

网络编程常见问题

1、TCP状态迁移图 2、TCP三次握手过程 2.1、握手流程 1、TCP服务器进程先创建传输控制块TCB&#xff0c;时刻准备接受客户进程的连接请求&#xff0c;此时服务器就进入了LISTEN&#xff08;监听&#xff09;状态&#xff1b; 2、TCP客户进程也是先创建传输控制块TCB&#xff…

改进经验模态分解方法-通过迭代方式(IMF振幅加权频率,Python)

一种新颖的改进经验模态分解方法-通过迭代方式&#xff08;IMF振幅加权频率&#xff09;有效缓解了模态混叠缺陷&#xff0c;以后慢慢讲&#xff0c;先占坑。 import numpy as np import matplotlib.pyplot as plt import os import seaborn as sns from scipy import stats i…

C语言图书管理系统控制台程序

程序示例精选 C语言图书管理系统控制台程序 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《C语言图书管理系统控制台程序》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读…

加密与安全_三种方式实现基于国密非对称加密算法的加解密和签名验签

文章目录 国际算法基础概念常见的加密算法及分类签名和验签基础概念常见的签名算法应用场景 国密算法对称加密&#xff08;DES/AES⇒SM4&#xff09;非对称加密&#xff08;RSA/ECC⇒SM2&#xff09;散列(摘要/哈希)算法&#xff08;MD5/SHA⇒SM3&#xff09; Code方式一 使用B…

智慧园区综合平台解决方案PPT(75页)

## 智慧园区的理解 ### 从园区1.0到园区4.0的演进 1. 园区1.0&#xff1a;以土地经营为主&#xff0c;成本驱动&#xff0c;提供基本服务。 2. 园区2.0&#xff1a;服务驱动&#xff0c;关注企业成长&#xff0c;提供增值服务。 3. 园区3.0&#xff1a;智慧型园区&#xff…

机器学习引领教育革命:智能教育的新时代

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f4d2;1. 引言&#x1f4d9;2. 机器学习在教育中的应用&#x1f31e;个性化学习&#x1f319;评估与反馈的智能化⭐教学资源的优…

STC89C52RC单片机设计的FM收音机+自动搜台+存储电台(程序+原理图+PCB)

资料下载地址&#xff1a;STC89C52RC单片机设计的FM收音机自动搜台存储电台&#xff08;程序原理图PCB) 1、实物图 2、部分程序 #include <reg52.h> #include "tea5767.h" #include "delay.h" #include "lcd1602.h" //K1:上一台 K2:下一…

mac电脑游戏推荐:NBA 2K24 街机版下载

NBA 2K24 街机版是一款由2K Sports开发并发行的篮球游戏&#xff0c;属于著名的NBA 2K系列。这款游戏为玩家提供了与NBA联赛中真实球员和球队互动的机会&#xff0c;体验篮球比赛的激情与紧张。街机版的NBA 2K24通常会在游戏厅、商场等公共场所设置&#xff0c;供玩家投币游玩。…

c++重载(运算符)

1&#xff09;C入门级小知识&#xff0c;分享给将要学习或者正在学习C开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 对于系统的所有操作符&#xff0c;一般情况下&#xff0c;只支持基本数…

AWTK 用 icon_at 属性设置图标位置

1. style 在 style 文件中通过 icon_at 属性设置图标位置。 <style name"right_bottom" icon_at"right_bottom"><normal icon"unchecked_right_bottom" /><pressed icon"unchecked_right_bottom" /><over i…

redis实战-短信登录

基于session的登录流程 session的登录流程图 1. 发送验证码 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行保存&#x…

第一节:如何开发第一个spring boot3.x项目(自学Spring boot 3.x的第一天)

大家好&#xff0c;我是网创有方&#xff0c;从今天开始&#xff0c;我会记录每篇我自学spring boot3.x的经验。只要我不偷懒&#xff0c;学完应该很快&#xff0c;哈哈&#xff0c;更新速度尽可能快&#xff0c;想和大佬们一块讨论&#xff0c;如果需要讨论的欢迎一起评论区留…

Pytorch实战(二)

文章目录 前言一、LeNet5原理1.1LeNet5网络结构1.2LeNet网络参数1.3LeNet5网络总结 二、AlexNext2.1AlexNet网络结构2.2AlexNet网络参数2.3Dropout操作2.4PCA图像增强2.5LRN正则化2.6AlexNet总结 三、实战3.1LeNet5模型搭建3.2模型训练 前言 参考原视频&#xff1a;哔哩哔哩。 …

【后端面试题】【中间件】【NoSQL】ElasticSearch面试基本思路和高可用方案(限流、消息队列、协调节点、双集群)

基本思路 业务开发面试Elasticsearch的时候基本问的是基础知识以及倒排索引。 Elasticsearch最基本的可用性保障就是分片&#xff0c;而且是主从分片&#xff0c;所以遇到Elasticsearch如何做到高可用这个问题的时候&#xff0c;首先要提到这一点。 Elasticsearch高可用的核心…

手机屏幕贴合项目(ni视觉如何找矩形的角坐标)

首先&#xff0c;我们存储了cg和dito感兴趣八个角图像的模板&#xff0c;用来匹配位置。 cover指的是cg的四个角模板&#xff0c;lcm是dito四个角匹配模板。 其次&#xff0c;我们采集的8副图像&#xff08;m_DlgCCDViewArr[2][4]&#xff09;中一定包含匹配模板的特征。 好&…

Json与Java类

简介 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写&#xff0c;同时也易于机器解析和生成。JSON数据由键值对构成&#xff0c;并以易于阅读的文本形式展现&#xff0c;支持数组、对象、字符串、数字、布尔值…

笔灵AI写作:释放创意,提升写作效率的秘诀

内容为王&#xff0c;在内容创作的世界中尤为重要。然而&#xff0c;面对写作时常常感到无从下手&#xff1a;有时缺乏灵感&#xff0c;有时难以表达清楚自己的想法。AI写作助手的出现&#xff0c;为这些问题提供了创新的解决方案&#xff0c;极大地改变了内容创作的过程。 今…

Pytest+Allure+Yaml+Jenkins+Gitlab接口自动化中Jenkins配置

一、背景 Jenkins&#xff08;本地宿主机搭建&#xff09; 拉取GitLab(服务器)代码到在Jenkins工作空间本地运行并生成Allure测试报告 二、框架改动点 框架主运行程序需要先注释掉运行代码&#xff08;可不改&#xff0c;如果运行报allure找不到就直接注释掉&#xff09; …

C++知识点总结 (02):C++中的语句(简单语句、条件语句、迭代语句、跳转语句、异常处理语句、try语句等)

文章目录 1、简单语句(1)空语句(2)复合语句 2、条件语句3、迭代语句(1)常规for循环(2)范围for循环(3)while和do...while 4、跳转语句(1)break(2)continue(3)goto 5、异常处理语句(1)标准异常(2)throw抛出异常 6、try语句 1、简单语句 (1)空语句 ; (2)复合语句 用花括号括起来的…