橘子学Mybatis03之代理模式

news/2024/5/18 2:04:07/文章来源:https://blog.csdn.net/liuwenqiang1314/article/details/127149368

一、什么是代理模式,为啥需要代理模式

1、问题

在JAVAEE的MVC分层开发中,哪个层级对我们来说最重要?

DAO ------> Service --------> ControllerJAVAEE分层开发中,最为重要的是Service层。这个也可以理解,因为Service是完成业务的层,你做项目不就是完成业务吗。

Service层中包含了哪些代码?

Service层中 = 核心功能(几十行上百行代码) + 额外功能(附加功能)
1、核心功能一般是业务逻辑,DAO调用等等。
2、额外功能一般下面三个特点.1、不属于业务2、可有可无3、代码量很小
# 比如像:事务,日志,性能 ...
日志一般就是输出一些流程信息,重要的需要,其余的都不用,所以也是可有可无的,其实也和业务没关。
性能就是输出一些性能信息,没啥。也是有的地方用,与业务无关。
但是事务很多人觉得重要,但是事务首先不是每一个地方都有,其次事务和业务也无关。
以上三个代码量都也不多。

那么额外功能写在Service层中到底好不好?

Service层的调用者的角度上看(也就是Controller):需要在Service层书写额外功能。
因为作为调用者,我们担心的比较多,我们怕出问题,所以想加上事务来维护。
从软件设计者的角度来看:Service层不需要加那些额外功能,因为额外不是必须的,加上了就不好维护,一会要加上,一会又要去掉,设计者不想这么麻烦。
所以这就出现了矛盾。下面我们就来解决矛盾。

2、解决方式

现实生活中的解决方式

其实现实生活中也有这个问题,我们来复盘一下。
比如说租房,有这么几个参与者,房客,房东。
租房这个业务的核心业务就是签合同收钱,额外的业务还有就是广告看房,对于房东来说就想签合同收钱,不想累死累活带着客户看房,对于客户来说你特么房都不看就想收老子钱,你去抢吧。这不就是调用者设计者对于核心业务和额外业务的矛盾出现了。
对于房东这个业务设计者来说,他只想做核心业务,不想做额外功能,对于业务使用者来说,他是需要额外功能的。

那现实是怎么解决这个问题的呢?

现实中增加了一个角色,叫中介(Proxy),你也可以叫做代理。
中介暴露出来的方法和房东那边是一样的,这样客户才会找你,你暴露出来的缺三缺四的谁还找你,代理言外之意就是表面上啥都一样,房东不愿意干的事,代理中可以去做,那些额外方法可以实现在代理中,就像中介带着客户去看房就行。
但是最后签合同这一步属于核心业务,你一个中介是没这个权限的,代理只是为了把额外业务剥离出来,不和核心代码耦合,所以此时核心业务还是要原始类去实现的,怎么实现呢?也很简单就是在中介类里声明原始类的引用,直接调呗。就是中介的类里面有一个房东的类引用,调用核心业务还是房东类调用的。
以后要是觉得代理不行了,再换一个新的代理修改实现就行了。(换个中介公司)
基于上面的分析其实我们的类结构就很清晰了,

  • 核心类:你的业务所在类
  • 代理类:里面有一些额外功能,并且持有了核心类的引用,这个引用去完成核心业务的调用

基于这个设计,于是引出了两种代理设计模式,一个是静态代理,一个是动态代理。

二、静态代理模式

1、概念

上面分析可知,我们得通过代理类为原始类(目标类)增加额外的功能
好处就是利于原始类(目标类)的维护,解开核心代码和额外代码的耦合。解开耦合自然利于维护。

2、名词解释

1、目标类|原始类指的是完成核心业务类那些(核心功能所在,-----》业务运算,DAO调用的)
2、目标方法|原始方法指的是目标类(原始类)中的方法,就是目标方法(原始方法)
3、额外功能|附加功能就是上面说的日志,事务,性能。
代理就是为了原始类增加额外功能的。

3、代理开发的核心要素

我们比如房东的功能类是UserService,因为我们说面向接口编程,我们一般把UserService声明成接口,里面定义核心方法,比如说签合同付钱。
UserServiceImpl implements UserService这个是实现类,就是房东的实现类,就是完成核心功能的。
前面我们说了,代理类(中介)表现出来的要和房东方法得一致,房东有的你得有,然后你才能出去拉客人,这就很自然了,代理类直接也实现原始类就行了,JAVA有这个机制直接保持。
UserServiceProxy implements UserService,然后你自己在这里添加附加功能即可。
# 代理类三要素 = 目标类(原始类)得有  + 额外功能 + 原始类(目标类)实现相同接口

多说无益,上代码。

4、编码实现

实体类

package com.yx.staticProxy;/*** @author: levi* @description: TODO* @date: 2022-10-3 9:47* @version: 1.0*/
public class User {private String name;private String password;// get set省略
}

核心类的接口,也就是原始类

/*** @author: levi* @description: 原始类接口* @date: 2022-10-3 9:47* @version: 1.0*/
public interface UserService {//核心功能,注册public void register(User user);// 核心功能,登录public boolean login(String name,String password);
}

核心类的接口实现

/*** @author: levi* @description: 原始类实现,里面是核心业务代码* @date: 2022-10-3 9:48* @version: 1.0*/
public class UserServiceImpl implements UserService{@Overridepublic void register(User user) {System.out.println("注册这个用户" + user.toString());}@Overridepublic boolean login(String name, String password) {System.out.println("登录用户" + name);return false;}
}

代理类,负责增强核心业务

/*** @description:代理类,完成额外代码的实现,同时里面调用核心业务,核心* 业务不是代理完成的,只是他在这用了,这样的好处就是,我们核心的代码不变* 你额外的想改就去改,维护方便,解开耦合。只要核心代码稳定,这个你不想用额外* 的都能去掉。把核心业务和额外的分开维护,互不影响。只是在代理里调用一下。以后核心改了* 不影响代理,代理改了不影响核心。* @author:levi* @version:1.0*/
public class UserServiceProxy implements UserService {// 持有核心类的引用,spring环境的时候可以注入,不要newprivate UserServiceImpl userService = new UserServiceImpl();@Overridepublic void register(User user) {// 增强日志业务System.out.println("---------log----------");// 核心操作还是核心类去做userService.register(user);}@Overridepublic boolean login(String name, String password) {System.out.println("---------log----------");return userService.login(name, password);}
}

调用测试

public class Test {public static void main(String[] args) {// 这里不能用原始类调,因为客户要的是也能看到额外功能,不然你弄额外干锤子UserServiceProxy userServiceProxy = new UserServiceProxy();userServiceProxy.login("诸葛亮","123456");userServiceProxy.register(new User("曹操","123456"));}
}输出结果为:
---------log----------
登录用户诸葛亮
---------log----------
注册这个用户com.yx.staticProxy.User@60e53b93

我们看到核心的登录是做了,增强的日志是代理类里面加的,这就是我们在没有修改核心类的基础上在代理里面对核心业务做了增强。

5、总结一下

我们至此就得到了这个代理的一个模式,
需要一个核心类,可以称之为目标类,需要被增强。
需要一个核心类里面的核心业务方法,我们需要对这个方法做增强。需要核心类去执行这个方法。
需要代理类,代理类和核心类实现一样的接口,对外暴露,因为你们的功能是要一致的。

6、静态代理存在的问题

1、静态代理类文件数量过多,不利于项目管理。每一个原始类起码一个代理类,大项目里几千个类能累死。
2、额外功能维护性差。每一个代理类中都有一个输出日志,要是有一天想改下输出方式,那一个个改,那可盖了帽了,当然了我们可以把日志输出抽成一个方法,各处调用即可.但是要是有一天不输出日志了,你还的各处去删除哪个调用。总之就是维护十分麻烦.项目大了或者涉及的面广了基本可以原地去世了。
基于这种弊端,于是动态代理模式随之而来。

三、动态代理模式

动态代理创建类的模式在java这块一般是有两种,一种是jdk的动态代理,一种是cglib的动态代理模式。

1、jdk的动态代理模式

在这里插入图片描述

我来具体解读一下上面的图:首先我们先明确一个概念:就是代理创建的三要素,静态代理和动态代理同样适用。
1、原始对象
2、额外功能
3、代理对象和原始对象实现相同的接口,是为了迷惑调用者,让调用者看到的是一样的接口,不然人家传参你不一样,那就接不到,你说锤子。然后我们用jdk来创建代理类,用的是java.lang.reflect.Proxy这个类,创建方法用的是newProxyInstance,就是下面这句代码,我们来分析一下,这句代码是怎么体现这三点要素的,因为没这三要素无法创建代理对象,我们就看看这句话干了什么来体现这三要素。
# Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);我们点进源码发现其实InvocationHandler就是处理了原始对象和额外功能的要素。是一个接口,里面有实现方法invoke。如下,
InvocationHandler invocationHandler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("****************before log******************");//额外功能Object result = method.invoke(userService.getClass(), args);return result;}
};
InvocationHandler的作用及时用于书写额外功能的代码,让额外功能运行在原始方法 前 后 环绕 以及抛出异常的时候
其中的返回值Object就是:原始方法的返回值。这个和那个前面的spring的动态代理一个模样。
参数解析:
# Proxy:先忽略掉,这个代表的就是最后创建的代理对象,我们目前还没到那里,先不谈,我们还没创建出来了,你说锤子。# Method:额外功能所增加给的那个原始方法,jdk把你调用的那个原始方法传了进来,因为你是在代码中先调用方法,然后spring会把代理对象创建出来,然后其实调用这个方法的是代理对象,但是创建代理对象是需要这个方法的,才能把额外方法执行在这个原始方法中,不传进来怎么在前后写额外方法。相当于代理拿到你得原始方法,然后替你调用,此时就能给你加东西了,这就是代理的意思,就是替换了你在人家这里执行,就能前后给你增强的东西了。# Object[]:原始方法的参数,这个其实很自然,你要调用这个原始方法,自然需要把参数也带过来,不然你调锤子。因为JDK不知道你们会传啥参数,各有各的,所以就用OBJECT的数组去接,数组都接过来。对应以前拦截器那会的执行原始方法现在是这句话:method.invoke(userService.getClass(), args);我们分析一下,这句话是执行原始方法,你怎么才能执行一个方法呢,第一就是执行方法的对象,第二就是参数,还有就是方法名,这三个构成执行一个方法,所以invoke是方法,还要参数就是userService的对象类型,你把你要创建的那个类的接口对象传进去,这里只能传对象,不然会报错,我之前传了一个.class进去。
args就是执行方法的参数。就像userService.login("lwq","654321");只不过上面是底层的反射实现,更加灵活,可以执行login还可以是别的,你在客户端调啥这里就是啥。所以你看到InvocationHandler这个参数其实就解决了原始对象和额外功能的两个要素。# 接下来解决第三个,就是代理类要和原始类实现一样的接口,不然外面调你代理类,你都和人家不一样,你还代理尼玛呢。
这个部分实现靠的是,第二个参数Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)就是Class<?>[] interfaces,这个就是你得把这个你要实现的代理的类传进来,因为你得告诉它你的接口是啥,他就会按照这个接口去实现,进而实现最后他们实现同一个接口的一个事情。那么怎么传接口呢,你把类.getclass.getInterface就能拿到它实现的接口。

#到此时我们已经解决了代理的三个要素,我们基本提供了所有的三要素的参数,但是还有最后一个问题就是,Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)其中的第一个参数ClassLoader这个参数还没有解决。我们来按照下图的知识来解释一下。

在这里插入图片描述

我们写了一个类.java文件,后面你编译成.class字节码文件,然后你运行它实际是jvm的classloader把你这个字节码文件加载到jvm中,然后你才能通过classloader new去创建对象。那么问题来了classloader(cl)是怎么来的呢,这个其实就是jvm自动为你创建的,只要你有一个字节码.class文件,jvm就会自动为你创建一个cl。话已至此,下一个问题就出来了,我们前面说,这个动态代理是个动态字节码技术,它其实没有.java 文件(我们前面写的时候至始至终没见过这个代理类的源文件),自然也就没有.class文件,是jvm直接就把那个字节码文件加载进去虚拟机的,从始至终没有字节码文件,(我理解的是你把文件加载进jvm需要cl,但是现在你不是加载的那个流程,所以没创建出对应的cl,你是直接进去的,走后门了没有加载过程)所以jvm也就不会为你创建所谓的cl,这就很伤,你没有拿传什么进去,但是这个东西其实就是传进去实现动态代理了,其实这个没特殊,没有说非得一对一,其实这个东西可以借用一个,既然代理的没有,那找个有的不就行了,本例中我们的UserService肯定是有的,那就用它的。
Proxy.newProxyInstance这就是动态字节码技术的实现。
问题总结就是,这个参数的作用是什么呢,我们说了cl可以用加载进去的字节码文件去创建出类的CLASS对象,就是那个模板,进而new创建对象,所以这个东西传进去的作用其实就是把动态的字节码文件创建成代理对象,这个东西是创建代理对象用的,可见其重要性。而且有趣的是,因为我一开始写错了,最后代理对象没创建出来,但是调用的时候额外方法输出了,原始方法没有,可见这二者真的就是组装起来的,不是一个整体。

2、编码实现

package com.yx.drmanicProxy;import com.yx.staticProxy.User;
import com.yx.staticProxy.UserService;
import com.yx.staticProxy.UserServiceImpl;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author: levi* @description: 我们来通过jdk方式创建UserService的代理对象,然后实现增强以及核心业务的调用* @date: 2022-10-3 10:06* @version: 1.0*/
public class JdkProxy {public static void main(String[] args) {// 创建原始对象UserServiceImpl userService = new UserServiceImpl();// 动态代理的InvocationHandler接口实现InvocationHandler invocationHandler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("****************before log******************");Object result = method.invoke(userService, args);return result;}};// getClassLoader这里可以借用,我随便借一个就行,只要是app的类加载器就行UserService proxyInstance = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);// 调用proxyInstance.login("张飞","654321");proxyInstance.register(new User("关羽","123456"));}
}
运行结果是:
****************before log******************
登录用户张飞
****************before log******************
注册这个用户com.yx.staticProxy.User@d716361
我们看到是可以实现增强的效果的。

3、CGLIB的动态代理模式

这是spring借助第三方库CGLIB的创建。
CGlib创建动态代理的原理:父子集成关系创建代理对象,原始类作为父类,代理类作为子类,这样就可能保证2者方法一致,同时在代理类中提供新的实现(额外功能 + 原始方法)。
对于上面的总结,我这里解释一下,因为我们说代理实现有三要素,1、原始类 2、额外方法 3、代理类要和原始类实现一样的接口
其实这个实现一样的接口就是保证你们有一样的方法,以此来迷惑调用者,调用者只管传参就行,其实底下已经是代理在做了,那么对于那些没有实现接口的人家就该不活了,不能创建代理不成,所以cglib登场,是为了那些没接口的出气,其实你就是为了方法一样,不一定得实现接口,继承也可以,继承就能复写,就能在复写中增加新得功能,这不就得了。

3.1、代码实现

原始类

/*** @author: levi* @description: 原始目标类* @date: 2022-10-3 10:35* @version: 1.0*/
public class UserService {public void login(String name,String password){System.out.println("----------- cglib login---------------");}public void register(User user){System.out.println("----------- cglib register---------------");}
}

cglib代理实现

package com.yx.drmanicProxy.cglib;import com.yx.staticProxy.User;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author: levi* @description: cglib创建代理对象* @date: 2022-10-3 10:35* @version: 1.0*/
public class CglibProxy {public static void main(String[] args) {// 原始对象UserService userService = new UserService();/*通过cglib创建动态代理对象之前jdk是Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);现在cglib其实高度一致Enhancer enhancer = new Enhancer();enhancer.setClassLoader(CglibProxy.class.getClassLoader());enhancer.setSuperclass(userService.getClass());enhancer.setCallback(methodInterceptor);*/// cglib得创建代理得类Enhancer enhancer = new Enhancer();// 设置cl,可以借一个enhancer.setClassLoader(CglibProxy.class.getClassLoader());// jdk是取得接口去创建一样得方法,这里是取得父类,那这个userService原始类得父类其实就是自己enhancer.setSuperclass(userService.getClass());// 设置额外方法得书写,其使用和传参和之前jdk得分析高度一致// MethodInterceptor这个之前是说过,但是此处注意,我们用的是cglib得包里类MethodInterceptor methodInterceptor = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("----------------cglib proxy log-----------------");// 调用需要指定调用谁得方法,和参数,前面jdk没说,这个methodJ就是你在客户端调得方法,所以这个method就是指定得方法名Object result = method.invoke(userService, args);return result;}};// 设置参数enhancer.setCallback(methodInterceptor);// 创建代理类UserService userServiceProxy = (UserService)enhancer.create();userServiceProxy.login("刘备","123456");userServiceProxy.register(new User("孙权","123456"));}
}
运行结果:
----------------cglib proxy log-----------------
----------- cglib login---------------
----------------cglib proxy log-----------------
----------- cglib register---------------
我们看到完全没问题的。

四、总结

1、JDK动态代理:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);通过接口创建代理的实现了类。
2、CGlib动态代理:Enhancer 通过继承父类创建代理类。
其实这两种就是spring底层创建代理,aop的实现方式,有接口用jdk,没有接口用cglib。

而且我们看到了代理模式,只要你提供了三要素,不管哪种实现方式,其实都是基于这三要素的一个封装处理实现。而且动态代理我们看到不需要程序员自己创建一个个的代理类了,都交给了底层去处理,可以规避类爆炸的问题。

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

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

相关文章

Lesson 8 The best and the worst 最好的和最差的

1.原文 2. 参考译文 3. New words and expressions ★competition n. 比赛&#xff0c;竞赛(暗地里的竞争) race n. 比赛&#xff0c;竞赛 car racematch n. 比赛 football matchcontest n. 比赛(更广泛)baby contest 宝宝大赛&#xff1b;beauty contest 选美game : 游戏, 运…

Spring自学日志01-IOC(控制翻转)

目录一、IOC的基本概念和底层原理1.1、什么是IOC?1.1.1、Spring IOC容器1.2、IOC底层原理1.2.1、IOC容器1.2.2、IOC容器装配Bean的方式1.2.3、IOC容器装配Bean的操作1.2.3.1、基于XML1.2.3.2、基于注解1.2.4、IOC容器装配Bean的作用域 一、IOC的基本概念和底层原理 1.1、什么是…

MySQL:索引特性

索引 0. 预备知识 索引是一个“物美价廉”的特性&#xff0c;用来提高数据库的性能。不需要改程序、调SQL、只需要正确的创建索引&#xff0c;查询速度就能提高成百上千倍&#xff0c;但查询速度的提升也带来了插入、更新、删除速度的下降。 0.1 认识磁盘 MySQL对数据进行增…

大数据讲课笔记2.1 初探大数据

文章目录零、学习目标一、导入新课二、新课讲解&#xff08;一&#xff09;什么是大数据&#xff08;二&#xff09;大数据的特征1、数据体量大2、数据类型多3、处理速度快4、价值密度低&#xff08;三&#xff09;研究大数据的意义&#xff08;四&#xff09;拥抱大数据时代1、…

【数据结构初阶】第四话 —— 动态栈的基本操作

文章目录什么是栈栈的结构1. 初始化栈2. 入栈3. 出栈4. 获取栈顶元素5. 获取栈中有效元素个数6. 检测栈是否为空7. 销毁栈8. 总结接口函数贴图什么是栈 假如有⼀个⼜细⼜⻓的圆筒&#xff0c;圆筒⼀端封闭&#xff0c;另⼀端开⼝。往圆筒⾥放⼊乒乓球&#xff0c;先放⼊的靠近…

U盘插入自动读写/U盘插入自动复制/pythhttps://www.cnblogs.com/wawawa888/p/16749476.htmlon检测U盘的插入,以及进行自动复制文件并写入文件

U盘自动读写的小玩意 共有四种方法(我知道的方法,全是转载。转载也很不易,可望给个硬币) 方法一(vbs方法 全自动,转载自bilibili 点我跳转)文件下载链接(点我下载) 方法二(cmd方法 需手动,转载自bilibili 点我跳转)文件下载链接(点我下载) 方法三(python方法 全…

在DataFrame中根据索引值进行排序:sort_index()函数

【小白从小学Python、C、Java】 【Python-计算机等级考试二级】 【Python-数据分析】 在DataFrame中根据索引值进行排序&#xff1a; sort_index()函数 [太阳]选择题 对以下python代码表述有误的选项是&#xff1f; import numpy as np import pandas as pd data np.random.…

ElasticSearch_03_批量处理命令mget和bulk的使用

系列文章目录 文章目录系列文章目录前言一、批量处理命令mget方案1&#xff1a;body请求体中指定index和type方案2&#xff1a;url中指定index和type&#xff0c;body中仅指定ids方案2扩展&#xff1a;url中指定index和type&#xff0c;body中仅指定id数组二、基于bulk的增删改…

C++开发坦克大战--补充(加入传送门)--附完整代码

目录 素材整理 穿越草地 坦克穿越草地 子弹穿越草地 传送门 判定形式 生成传送门 传送坦克 关卡模式 效果展示 ​总结 完整代码 上一篇坦克大战居然意外获得了一些关注&#xff0c;正好最近也完善了一些功能&#xff0c;同时也加入了一些自己想到的新元素&#xff0c;主要是…

python requests cookie的获取和使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、cookie是什么&#xff1f;二、使用步骤开始代码实现会话是什么然后写入我们的账号信息使用session访问登陆账号的url获取账号的书架上的数据完整的代码补充比…

基于javaweb在线投票管理系统ssm

基于SSM的在线投票系统以XXX学院为背景&#xff0c;运用在校所学习的软件开发原理&#xff0c;采用SpringSpringMVCMyBatis技术和MySQL数据库构建一个基于B/S模式的在线投票系统。 传统的投票模式都是通过人工手动填写问卷的方式来进行&#xff0c;这在很大程度上会造成人力和…

1.1 Ryu 的安装部署

What is Ryu Ryu是轻量级的、开源的SDN控制器Ryu是由日本NTT公司在2012年推出其名字在日文中的意思是“Flow”和“Dragon”的意思 Ryu架构 Ryu安装 在Ubuntu上装Ryu和Mininet&#xff0c;CSDN上搜教程&#xff0c;这一部分正确做法是对着视频敲代码如果有问题去CSDN上找解决办…

滤波器基础01——滤波器的种类与特性

滤波器是一种选频装置&#xff0c;它能够保留某一频段的信号&#xff0c;将此频段之外的信号消除。以下介绍不同分类依据下滤波器的特点。 一. 模拟滤波器与数字滤波器 根据滤波器的作用对象是模拟信号还是数字信号可将滤波器分为模拟滤波器和数字滤波器。 模拟滤波器处理模…

创建并运行一个 Spring Boot 项目

创建并运行一个 Spring Boot 项目引言第一个 Spring Boot 项目1. 创建一个 spring boot 项目第一步第二步第三步第四步2. 验证第一步第二步3. 写一个 hello world第一步解析代码第二步注意事项网页创建一个 Spring Boot 项目Spring Boot 的优点引言 Spring Boot 是 Spring 框架…

升级迭代:让我的颜色控制打印工具mypycolor更聪明,参数可以任意接收颜色控制码、颜色描述英文单词的任意组合。

【点击此处跳转笔记正文】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… My CSDN主页、My HOT博、My Python 学习个人备忘录好文力荐、 老齐教室 自学并不是什么神秘的…

YOLOV+pytorch+win10+CPU环境配置

Step 1&#xff1a;下载github YOLOV3源码 链接&#xff1a;https://github.com/ultralytics/yolov3 Step 2&#xff1a;配置CPUpytorch版本环境 WinR启动cmd&#xff0c;在命令提示符内输入以下命令&#xff0c;创建一个新环境&#xff1a; conda create –n yolov-pytorc…

记录自学的学习路线(详细)

目录 HTML css javaScript javaScript高级 jQuery(快速过一遍) bootstrap 移动端适配 ajax ES6 Vue2vue3全家桶&#xff08;vue3暂时不学&#xff0c;后面会解释原因&#xff09; axios promise vue2结束后 Vue3 Ts 依我而言 曾经我也迷茫过&#xff0c;如何学习…

JWT 和 JJWT 还傻傻的分不清吗

JWTs是JSON对象的编码表示。JSON对象由零或多个名称/值对组成,其中名称为字符串,值为任意JSON值。 JWT有助于在clear(例如在URL中)发送这样的信息,可以被信任为不可读(即加密的)、不可修改的(即签名)和URL - safe(即Base64编码的)。 JSON Web Token (JWT) 作为一个开放的标准…

CPU--指令系统

1.机器的指令的一般格式:操作码字段,地址码字段; 2.数据在存储器中的存放方式:a,从任意位置开始--不浪费空间,读写控制比较复杂; :b, 从一个存储字的起始位置开始存储--读写控制简单,浪费空间;  :c,边界对准方式,按地址数字节的整数倍位置存储--结合前两者;3.寻址…

日本抢滩Web3:“樱花”如何在加密彼岸绽放

失去互联网之后&#xff0c;这个第三大经济体决定在Web3奋起直追。 9月22日&#xff0c;Astar 创始人渡边宗太在自己的博客宣布&#xff0c;Astar 的原生代币通过了金融厅和 JVCEA&#xff08;日本加密资产交易协会&#xff09;的严格审核&#xff0c;并将在日本本土交易所 Bit…