权威解析Spring框架九大核心功能(续篇):专业深度,不容错过

news/2024/5/18 16:55:13

作者介绍:✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。

 推荐订阅精彩专栏 👇🏻 避免错过下次更新

Springboot项目精选实战案例

更多项目:CSDN主页YAML墨韵

学如逆水行舟,不进则退。学习如赶路,不能慢一步。

接上一节Spring的9个核心功能(一):Spring框架九大核心功能全面揭秘(一)-CSDN博客

目录

数据绑定

1、PropertyValues

2、BeanWrapper

3、DataBinder

泛型处理

国际化

1、Java中的国际化

Locale

ResourceBundle

MessageFormat

2、Spring国际化

小结

BeanFactory

1、BeanFactory接口体系

2、BeanDefinition及其相关组件

BeanDefinition

读取BeanDefinition

3、BeanFactory核心实现

总结


数据绑定

上一节我们讲了类型转换,而既然提到了类型转换,那么就不得不提到数据绑定了,他们是密不可分的,因为在数据绑定时,往往都会伴随着类型转换,

数据绑定的意思就是将一些配置属性跟我们的Bean对象的属性进行绑定。

不知你是否记得,在远古的ssm时代,我们一般通过xml方式声明Bean的时候,可以通过<property/>来设置Bean的属性

<bean class="com.sanyou.spring.core.basic.User"><property name="username" value="java日记"/>
</bean>
@Data
public class User {private String username;}

然后Spring在创建User的过程中,就会给username属性设置为三友的java日记

这就是数据绑定,将三友的java日记绑定到username这个属性上。

数据绑定的核心api主要包括以下几个:

  • PropertyValues

  • BeanWrapper

  • DataBinder

1、PropertyValues

这里我们先来讲一下PropertyValue(注意没有s)

顾明思议,PropertyValue就是就是封装了属性名和对应的属性值,它就是数据绑定时属性值的来源。

以前面的提到的xml创建Bean为例,Spring在启动的时候会去解析xml中的<property/>标签,然后将namevalue封装成PropertyValue

当创建User这个Bean的时候,到了属性绑定的阶段的时候,就会取出PropertyValue,设置到User的username属性上。

而PropertyValues,比PropertyValue多了一个s,也就是复数的意思,所以其实PropertyValues本质上就是PropertyValue的一个集合

因为一个Bean可能有多个属性配置,所以就用PropertyValues来保存。

2、BeanWrapper

BeanWrapper其实就数据绑定的核心api了,因为在Spring中涉及到数据绑定都是通过BeanWrapper来完成的,比如前面提到的Bean的属性的绑定,就是通过BeanWrapper来的

BeanWrapper是一个接口,他有一个唯一的实现BeanWrapperImpl。

先来个demo

public class BeanWrapperDemo {public static void main(String[] args) {//创建user对象User user = new User();//创建BeanWrapper对象,把需要进行属性绑定的user对象放进去BeanWrapper beanWrapper = new BeanWrapperImpl(user);//进行数据绑定,将三友的java日记这个属性值赋值到username这个属性上beanWrapper.setPropertyValue(new PropertyValue("username", "三友的java日记"));System.out.println("username = " + user.getUsername());}}

结果

成功获取到,说明设置成功

BeanWrapperImpl也间接实现了TypeConverter接口

当然底层还是通过前面提到的ConversionService和PropertyEditor实现的

所以当配置的类型跟属性的类型不同时,就可以对配置的类型进行转换,然后再绑定到属性上

这里简单说一下数据绑定和@Value的异同,因为这两者看起来好像是一样的,但实际还是有点区别的

相同点:

  • 两者都会涉及到类型转换,@Value和数据绑定都会将值转换成目标属性对应的类型,并且都是通过TypeConverter来转换的

不同点:

  • 1、发生时机不同,@Value比数据绑定更早,当@Value都注入完成之后才会发生数据绑定(属性赋值)

  • 2、属性赋值方式不同,@Value是通过反射来的,而是数据绑定是通过setter方法来的,如果没有setter方法,属性是没办法绑定的

3、DataBinder

DataBinder也是用来进行数据绑定的,它的底层也是间接通过BeanWrapper来实现的数据绑定的

但是他相比于BeanWrapper多了一些功能,比如在数据绑定之后,可以对数据校验,比如可以校验字段的长度等等

说到数据校验,是不是想到了SpringMVC中的参数校验,通过@Valid配合一些诸如@NotBlank、@NotNull等注解,实现优雅的参数校验。

其实SpringMVC的参数校验就是通过DataBinder来的,所以DataBinder其实在SpringMVC中用的比较多,但是在Spring中确用的很少。

如果你有兴趣,可以翻一下SpringMVC中关于请求参数处理的HandlerMethodArgumentResolver的实现,里面有的实现会用到DataBinder(WebDataBinder)来进行数据请求参数跟实体类的数据绑定、类型转换、数据校验等等。

不知道你有没有注意过,平时写接口的时候,前端传来的参数String类型的时间字符串无法通过Spring框架本身转换成Date类型,有部分原因就是前面提到的Spring没有相关的Converter实现

总的来说,数据绑定在xml配置和SpringMVC中用的比较多的,并且数据绑定也是Spring Bean生命周期中一个很重要的环节。

泛型处理

Spring为了方便操作和处理泛型类型,提供了一个强大的工具类——ResolvableType。

泛型处理其实是一块相对独立的东西,因为它就只是一个工具类,只还不过这个工具类在Spring中却是无处不在!

ResolvableType提供了有一套灵活的API,可以在运行时获取和处理泛型类型等信息。

ResolvableType

接下来就通过一个案例,来看一看如何通过ResolvableType快速简单的获取到泛型的

首先我声明了一个MyMap类,继承HashMap,第一个泛型参数是Integer类型,第二个泛型参数是List类型,List的泛型参数又是String

public class MyMap extends HashMap<Integer, List<String>> {}

接下来就来演示一下如何获取到HashMap的泛型参数以及List的泛型参数

第一步先来通过ResolvableType#forClass方法创建一个MyMap类型对应的ResolvableType

//创建MyMap对应的ResolvableType
ResolvableType myMapType = ResolvableType.forClass(MyMap.class);

因为泛型参数是在父类HashMap中,所以我们得获取到父类HashMap对应的ResolvableType,通过ResolvableType#getSuperType()方法获取

//获取父类HashMap对应的ResolvableType
ResolvableType hashMapType = myMapType.getSuperType();

接下来需要获取HashMap的泛型参数对应的ResolvableType类型,可以通过ResolvableType#getGeneric(int... indexes)就可以获取指定位置的泛型参数ResolvableType,方法参数就是指第几个位置的泛型参数,从0开始

比如获取第一个位置的对应的ResolvableType类型

//获取第一个泛型参数对应的ResolvableType
ResolvableType firstGenericType = hashMapType.getGeneric(0);

现在有了第一个泛型参数的ResolvableType类型,只需要通过ResolvableType#resolve()方法就可以获取到ResolvableType类型对应的class类型,这样就可以获取到一个泛型参数的class类型

//获取第一个泛型参数对应的ResolvableType对应的class类型,也就是Integer的class类型
Class<?> firstGenericClass = firstGenericType.resolve();

如果你想获取到HashMap第二个泛型参数的泛型类型,也就是List泛型类型就可以这么写

//HashMap第二个泛型参数的对应的ResolvableType,也就是List<String>
ResolvableType secondGenericType = hashMapType.getGeneric(1);
//HashMap第二个泛型参数List<String>的第一个泛型类型String对应的ResolvableType
ResolvableType secondFirstGenericType = secondGenericType.getGeneric(0);
//这样就获取到了List<String>的泛型类型String
Class<?> secondFirstGenericClass = secondFirstGenericType.resolve();

从上面的演示下来可以发现,其实每变化一步,其实就是获取对应泛型或者是父类等等对应的ResolvableType,父类或者是泛型参数又可能有泛型之类的,只需要一步一步获取就可以了,当需要获取到具体的class类型的时候,通过ResolvableType#resolve()方法就行了。

除了上面提到的通过ResolvableType#forClass方法创建ResolvableType之外,还可以通过一下几个方法创建:

  • forField(Field field):获取字段类型对应的ResolvableType

  • forMethodReturnType(Method method):获取方法返回值类型对应的ResolvableType

  • forMethodParameter(Method method, int parameterIndex):获取方法某个位置方法参数对应的ResolvableType

  • forConstructorParameter(Constructor<?> constructor, int parameterIndex):获取构造方法某个构造参数对应的ResolvableType

通过上面解释可以看出,对于一个类方法参数,方法返回值,字段等等都可以获取到对应的ResolvableType

国际化

国际化(Internationalization,简称i18n)也是Spring提供的一个核心功能,它其实也是一块相对独立的功能。

所谓的国际化,其实理解简单点就是对于不同的地区国家,输出的文本内容语言不同。

Spring的国际化其实主要是依赖Java中的国际化和文本处理方式。

1、Java中的国际化

Locale

Locale是Java提供的一个类,它可以用来标识不同的语言和地区,如en_US表示美国英语,zh_CN表示中国大陆中文等。

目前Java已经穷举了很多国家的地区Locale。

我们可以使用Locale类获取系统默认的Locale,也可以手动设置Locale,以适应不同的语言环境。

ResourceBundle

ResourceBundle是一个加载本地资源的一个类,他可以根据传入的Locale不同,加载不同的资源。

来个demo

首先准备资源文件,资源文件通常是.properties文件,文件名命名规则如下:

basename_lang_country.properties

basename无所谓,叫什么都可以,而lang和country是从Locale中获取的。

举个例子,我们看看英语地区的Locale

从上图可以看出,英语Locale的lang为en,country为空字符串,那么此时英语地区对应资源文件就可以命名为:basename_en.properties,由于country为空字符串,可以省略

中国大陆Locale如下图

此时文件就可以命为:basename_zh_CN.properties

好了,现在既然知道了命名规则,我们就创建两个文件,basename就叫message,一个英语,一个中文,放在classpath路径下

中文资源文件:message_zh_CN.properties,内容为:

name=java日记

英文资源文件:message_en.properties,内容为:

name= java diary

有了文件之后,就可以通过ResourceBundle#getBundle(String baseName,Locale locale)方法来获取获取ResourceBundle

  • 第一个参数baseName就是我们的文件名中的basename,对于我们的demo来说,就是message

  • 第二个参数就是地区,根据地区的不同加载不同地区的文件

测试一下

public class ResourceBundleDemo {public static void main(String[] args) {//获取ResourceBundle,第一个参数baseName就是我们的文件名称,第二个参数就是地区ResourceBundle chineseResourceBundle = ResourceBundle.getBundle("message", Locale.SIMPLIFIED_CHINESE);//根据name键取值String chineseName = chineseResourceBundle.getString("name");System.out.println("chineseName = " + chineseName);ResourceBundle englishResourceBundle = ResourceBundle.getBundle("message", Locale.ENGLISH);String englishName = englishResourceBundle.getString("name");System.out.println("englishName = " + englishName);}}

运行结果

图片

其实运行结果可以看出,其实是成功获取了,只不过中文乱码了,这主要是因为ResourceBundle底层其实编码是ISO-8859-1,所以会导致乱码。

解决办法最简单就是把中文用Java Unicode序列来表示,之后就可以读出中文了了,比如java日记用Java Unicode序列表示为\java\u65e5\u8bb0

除了这种方式之外,其实还可以继承ResourceBundle内部一个Control类

重写newBundle方法

newBundle是创建ResourceBundle对应核心方法,重写的时候你就可以随心所欲让它支持其它编码方式。

有了新的Control之后,获取ResourceBundle时只需要通过ResourceBundle#getBundle(String baseName, Locale targetLocale,Control control)方法指定Control就可以了。

Spring实际上就是通过这种方式扩展,支持不同编码的,后面也有提到。

MessageFormat

MessageFormat顾明思议就是把消息格式化。它可以接收一条包含占位符的消息模板,并根据提供的参数替换占位符,生成最终的消息。

MessageFormat对于将动态值插入到消息中非常有用,如欢迎消息、错误消息等。

先来个Demo

public class MessageFormatDemo {public static void main(String[] args) {String message = MessageFormat.format("你好:{0}", "张三");System.out.println("message = " + message);}}

解释一下上面这段代码:

  • 你好:{0}其实就是前面提到的消息的模板,{0}就是占位符,中间的0代表消息格式化的时候将提供的参数第一个参数替换占位符的值

  • 张三就是提供的参数,你可以写很多个,但是我们的demo只会取第一个参数,因为是{0}

所以输出结果为:

message = 你好:张三

成功格式化消息。

2、Spring国际化

Spring提供了一个国际化接口MessageSource

MessageSource

他有一个基于ResourceBundle + MessageFormat的实现ResourceBundleMessageSource

他的本质可以在资源文件存储消息的模板,然后通过MessageFormat来替换占位符,MessageSource的getMessage方法就可以传递具体的参数

来个demo

现在模拟登录欢迎语句,对于不同的人肯定要有不同的名字,所以资源文件需要存模板,需要在不同的资源文件加不同的模板

中文资源文件:message_zh_CN.properties

中文资源文件:message_zh_CN.properties

welcome=您好:{0}

英文资源文件:message_en.properties

welcome=hello:{0}

占位符,就是不同人不同名字

测试代码

public class MessageSourceDemo {public static void main(String[] args) {ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();//Spring已经扩展了ResourceBundle的Control,支持资源文件的不同编码方式,但是需要设置一下messageSource.setDefaultEncoding("UTF-8");//添加 baseName,就是前面提到的文件中的basenamemessageSource.addBasenames("message");//中文,传个中文名字String chineseWelcome = messageSource.getMessage("welcome", new Object[]{"张三"}, Locale.SIMPLIFIED_CHINESE);System.out.println("chineseWelcome = " + chineseWelcome);//英文,英语国家肯定是英文名String englishWelcome = messageSource.getMessage("welcome", new Object[]{"Bob"}, Locale.ENGLISH);System.out.println("englishWelcome = " + englishWelcome);}}

运行结果

chineseWelcome = 您好:张三
englishWelcome = hello:Bob

成功根据完成不同国家资源的加载和模板消息的格式化。

小结

这里来简单总结一下这一小节说的内容

  • Locale:不同国家和地区的信息封装

  • ResourceBundle:根据不同国家的Locale,加载对应的资源文件,这个资源文件的命名需要遵守basename_lang_country.properties命名规范

  • MessageFormat:其实就是一个文本处理的方式,他可以解析模板,根据参数替换模板的占位符

  • MessageSource:Spring提供的国际化接口,其实他底层主要是依赖Java的ResourceBundle和MessageFormat,资源文件存储模板信息,MessageFormat根据MessageSource方法的传参替换模板中的占位符

BeanFactory

我们知道Spring的核心就是IOC和AOP,而BeanFactory就是大名鼎鼎的IOC容器,他可以帮我们生产对象。

1、BeanFactory接口体系

BeanFactory本身是一个接口

从上面的接口定义可以看出从可以从BeanFactory获取到Bean。

他也有很多子接口,不同的子接口有着不同的功能

  • ListableBeanFactory

  • HierarchicalBeanFactory

  • ConfigurableBeanFactory

  • AutowireCapableBeanFactory

ListableBeanFactory

从提供的方法可以看出,提供了一些获取集合的功能,比如有的接口可能有多个实现,通过这些方法就可以获取这些实现对象的集合。

HierarchicalBeanFactory

从接口定义可以看出,可以获取到父容器,说明BeanFactory有子父容器的概念。

ConfigurableBeanFactory

从命名可以看出,可配置BeanFactory,所以可以对BeanFactory进行配置,比如截图中的方法,可以设置我们前面提到的类型转换的东西,这样在生成Bean的时候就可以类型属性的类型转换了。

AutowireCapableBeanFactory

提供了自动装配Bean的实现、属性填充、初始化、处理获取依赖注入对象的功能。

比如@Autowired最终就会调用AutowireCapableBeanFactory#resolveDependency处理注入的依赖。

其实从这里也可以看出,Spring在BeanFactory的接口设计上面还是基于不同的职责进行接口的划分,其实不仅仅是在BeanFactory,前面提到的那些接口也基本符合这个原则。

2、BeanDefinition及其相关组件

BeanDefinition

BeanDefinition是Spring Bean创建环节中很重要的一个东西,它封装了Bean创建过程中所需要

的元信息。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {//设置Bean classNamevoid setBeanClassName(@Nullable String beanClassName);//获取Bean className@NullableString getBeanClassName();//设置是否是懒加载void setLazyInit(boolean lazyInit);//判断是否是懒加载boolean isLazyInit();//判断是否是单例boolean isSingleton();}

如上代码是BeanDefinition接口的部分方法,从这方法的定义名称可以看出,一个Bean所创建过程中所需要的一些信息都可以从BeanDefinition中获取,比如这个Bean的class类型,这个Bean是否是懒加载,这个Bean是否是单例的等等,因为有了这些信息,Spring才知道要创建一个什么样的Bean。

读取BeanDefinition

读取BeanDefinition大致分为以下几类

  • BeanDefinitionReader

  • ClassPathBeanDefinitionScanner

BeanDefinitionReader

BeanDefinitionReader可以通过loadBeanDefinitions(Resource resource)方法来加载BeanDefinition,方法参数就是我们前面说的资源,比如可以将Bean定义在xml文件中,这个xml文件就是一个资源

BeanDefinitionReader的相关实现:

  • XmlBeanDefinitionReader:读取xml配置的Bean

  • PropertiesBeanDefinitionReader:读取properties文件配置的Bean,是的,你没看错,Bean可以定义在properties文件配置中

  • AnnotatedBeanDefinitionReader:读取通过注解定义的Bean,比如@Lazy注解等等,AnnotatedBeanDefinitionReader不是BeanDefinitionReader的实现,但是作用是一样的

ClassPathBeanDefinitionScanner

这个作用就是扫描指定包下通过@Component及其派生注解(@Service等等)注解定义的Bean,其实就是@ComponentScan注解的底层实现

ClassPathBeanDefinitionScanner这个类其实在很多其它框架中都有使用到,因为这个类可以扫描指定包下,生成BeanDefinition,对于那些需要扫描包来生成BeanDefinition来说,用的很多

比如说常见的MyBatis框架,他的注解@MapperScan可以扫描指定包下的Mapper接口,其实他也是通过继承ClassPathBeanDefinitionScanner来扫描Mapper接口的

BeanDefinitionRegistry

这个从命名就可以看出,是BeanDefinition的注册中心,也就是用来保存BeanDefinition的。

提供了BeanDefinition的增删查的功能。

讲到这里,就可以用一张图来把前面提到东西关联起来

  • 通过BeanDefinitionReader或者是ClassPathBeanDefinitionScanner为每一个Bean生成一个BeanDefinition

  • BeanDefinition生成之后,添加到BeanDefinitionRegistry中

  • 当从BeanFactory中获取Bean时,会从BeanDefinitionRegistry中拿出需要创建的Bean对应的BeanDefinition,根据BeanDefinition的信息来生成Bean

  • 当生成的Bean是单例的时候,Spring会将Bean保存到SingletonBeanRegistry中,也就是平时说的三级缓存中的第一级缓存中,以免重复创建,需要使用的时候直接从SingletonBeanRegistry中查找

3、BeanFactory核心实现

前面提到的BeanFactory体系都是一个接口,那么BeanFactory的实现类是哪个类呢?

BeanFactory真正底层的实现类,其实就只有一个,那就是DefaultListableBeanFactory这个类,这个类以及父类真正实现了BeanFactory及其子接口的所有的功能。

并且接口的实现上可以看出,他也实现了BeanDefinitionRegistry,也就是说,在底层的实现上,其实BeanFactory跟BeanDefinitionRegistry的实现是同一个实现类。

上面说了这么多,来个demo

public class BeanFactoryDemo {public static void main(String[] args) {//创建一个BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//创建一个BeanDefinitionReader,构造参数是一个BeanDefinitionRegistry//因为DefaultListableBeanFactory实现了BeanDefinitionRegistry,所以直接把beanFactory当做构造参数传过去AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(beanFactory);//读取当前类 BeanFactoryDemo 为一个Bean,让Spring帮我们生成这个BeanbeanDefinitionReader.register(BeanFactoryDemo.class);//从容器中获取注册的BeanFactoryDemo的BeanBeanFactoryDemo beanFactoryDemo = beanFactory.getBean(BeanFactoryDemo.class);System.out.println("beanFactoryDemo = " + beanFactoryDemo);}}

简单说一下上面代码的意思

  • 创建一个BeanFactory,就是DefaultListableBeanFactory

  • 创建一个AnnotatedBeanDefinitionReader,构造参数是一个BeanDefinitionRegistry,因为BeanDefinitionReader需要把读出来的BeanDefinition存到BeanDefinitionRegistry中,同时因为DefaultListableBeanFactory实现了BeanDefinitionRegistry,所以直接把beanFactory当做构造参数传过去

  • 读取当前类 BeanFactoryDemo 为一个Bean,让Spring帮我们生成这个Bean

  • 后面就是获取打印

运行结果

成功获取到我们注册的Bean

总结

本节主要讲了实现IOC的几个核心的组件

BeanFactory及其接口体系:

  • ListableBeanFactory

  • HierarchicalBeanFactory

  • ConfigurableBeanFactory

  • AutowireCapableBeanFactory

BeanDefinition及其相关组件:

  • BeanDefinition

  • BeanDefinitionReader和ClassPathBeanDefinitionScanner:读取资源,生成BeanDefinition

  • BeanDefinitionRegistry:存储BeanDefinition

BeanFactory核心实现:

  • DefaultListableBeanFactory:IOC容器,同时实现了BeanDefinitionRegistry接口


http://www.mrgr.cn/p/42027644

相关文章

e语言 【超级列表框 某列 不显示 】 “假隐藏” 效果

demo本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18155589

xilinx cpri ip 开发记录

CPRI是无线通信里的一个标准协议&#xff0c;连接REC和RE的通信。 Xilinx有提供CPRI IP核。 区别于其它通信协议&#xff0c;如以太网等&#xff0c;CPRI是一个同步系统。 这就意味着两端的Master和Slave应当是同源时钟的&#xff0c;两边不存在频差&#xff0c;并且内部延时…

【性能监控】如何有效监测网页静态资源大小?

前言 作为前端人员肯定经常遇到这样的场景:需求刚上线,产品拿着手机来找你,为什么页面打开这么慢呀,心想自己开发的时候也有注意性能问题呀,不可能会这么夸张。那没办法只能排查下是哪一块影响了页面的整体性能,打开浏览器控制台一看,页面上的这些配图每张都非常大,心想…

HarmonyOS 实战开发-Worker子线程中解压文件

本示例介绍在Worker子线程使用@ohos.zlib提供的zlib.decompressfile接口对沙箱目录中的压缩文件进行解压操作,解压成功后将解压路径返回主线程,获取解压文件列表。介绍 本示例介绍在Worker子线程使用@ohos.zlib提供的zlib.decompressfile接口对沙箱目录中的压缩文件进行解压操…

3年经验来面试20K的测试岗,连基本功都不会,还不如去招应届生

为了新项目做准备,这段时间公司面了不少人,竟然没有一个满意的。一开始瞄准的就是中高级的水准,也没指望来技术大牛,提供的薪资在15-25K,面试的人很多,但结果让人失望。 从简历上来说都是3-4年工作经验,但面试中,不会工具方法和编程框架,基本功的技术很多也不熟练,多…

java-spring-mybatis -学习第一天-基础知识讲解

目录 前置条件(创建一个项目) Mybatis 定义 可能出现的问题 这边如果连接不上数据库 ​编辑 Dao接口设计 Mybatis流程 创建实体类 User 和其属性 创建Mapper的接口类 测试类测试 实例数据库数据的更新 实例数据库数值的删除 最重要的是有一个原始的数据库 -我这边…

C语言实现双人贪吃蛇项目(基于控制台界面)

一.贪吃蛇 贪吃蛇是一款简单而富有乐趣的游戏&#xff0c;它的规则易于理解&#xff0c;但挑战性也很高。它已经成为经典的游戏之一&#xff0c;并且在不同的平台上一直受到人们的喜爱和回忆。 二.贪吃蛇的功能 游戏控制&#xff1a;玩家可以使用键盘输入设备来控制蛇的移动方…

Pycharm远程连接服务器调试过程(个人记录)

Pycharm远程调试服务器,这里主要讲的是ssh方法(避免自己主机显存、内存不足的情况,ssh服务如何开启请自行查找)。 主要分为几个步骤: 1、服务器开启ssh服务,开放ssh端口号(一般为22) 2、打开pycharm,设置ssh远程python为解释器(如下,打开设置后点设置添加解释器,随…

ChatGPT在线网页版(与GPT Plus会员完全一致)

ChatGPT镜像 今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用ChatGPT吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像…

vis.js工具提示3d图形

代码案例<!DOCTYPE html> <html><head><title>Graph 3D demo</title><style>body {font: 10pt arial;}div#info {width: 600px;text-align: center;margin-top: 2em;font-size: 1.2em;}</style><scripttype="text/javascrip…

Linux下SPI设备驱动实验:测试读取ICM20608设备中数据是否正常

一. 简介 前面文章实现了 SPI设备的读写功能&#xff0c;也对ICM20608设备中&#xff08;即SPI设备&#xff09;寄存器里的数据进行了读取。文章如下&#xff1a; Linux下SPI设备驱动实验&#xff1a;读取ICM20608设备的数据-CSDN博客 本文对驱动功能进行测试&#xff0c;即…

static+单例模式+类的复合继承

汇编语言 汇编语言是最靠谱的验证“编程语言相关知识点”正确性的方式 汇编语言与机器语言一一对应&#xff0c;每一条机器语言都有与之对应的汇编指令 机器语言是计算机使用的语言&#xff0c;它是一串二进制数字 汇编语言可以通过汇编得到机器语言机器语言可以通过反汇编得到…

鸿蒙开发实战:【文件管理】

介绍 本示例主要展示了文件管理相关的功能,使用[@ohos.multimedia.medialibrary]、[@ohos.filemanagement.userFileManager] 、[@ohos.fileio] 、[@ohos.file.fs]、[@ohos.app.ability.contextConstant] 等接口,实现了增添文件、删除文件、查找指定类型文件文件、复制并移动文…

机器学习(四)之无监督学习

前言&#xff1a; 前面写了监督学习的几种算法&#xff0c;下面就开始无监督啦&#xff01; 如果文章有错误之处&#xff0c;小伙伴尽情在评论区指出来&#xff08;嘿嘿&#xff09;&#xff0c;看到就会回复的。 1.聚类&#xff08;Clustering&#xff09; 1.1 概述&#xff…

上位机图像处理和嵌入式模块部署(树莓派4b与视觉slam十四讲)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 实际使用中&#xff0c;树莓派4b是非常好的一个基础平台。本身板子价格也不是很贵&#xff0c;建议大家多多使用。之前关于vslam&#xff0c;也就是…

WAF攻防-漏洞发现协议代理池GobyAwvsXray

知识点 1、Http/s&Sock5协议 2、Awvs&Xray&Goby代理 3、Proxifier进程代理使用 4、Safedog&BT&Aliyun防护在漏洞发现中&#xff0c;WAF会对三个方向进行过滤拦截&#xff1a; 1、速度频率问题&#xff08;代理池解决&#xff09; 2、工具的指纹被识别&am…

XMU《计算机网络与通信》第三次实验报告

一、个人信息 学号:************** 姓名:### 二、实验目的理解TCP和UDP协议主要特点掌握socket的基本概念和工作原理,编程实现socket通信三、实验任务与结果 任务 1 前置任务开启两个终端窗口,分别编译、运行 server_example.c 和 client_example.c,观察它们实现的功能。可…

vis.js样式3d图形

代码案例<!DOCTYPE html> <html><head><title>Graph 3D demo</title><style>body {font: 10pt arial;}</style><scripttype="text/javascript"src="https://unpkg.com/vis-graph3d@latest/dist/vis-graph3d.min.j…

Redis系列之Cluster集群搭建

在上一篇博客&#xff0c;我们学习Redis哨兵Sentinel集群的搭建&#xff0c;redis的哨兵模式提供了比如监控、自动故障转移等高可用方案&#xff0c;但是这种方案&#xff0c;容量相对固定&#xff0c;要进行持续扩容或者数据分片就不适合&#xff0c;所以有另外一种更复杂的集…

使用 ECharts 绘制咖啡店各年订单的可视化分析

使用 ECharts 绘制咖啡店各年订单的可视化分析 在这篇博客中&#xff0c;我将分享一段使用 ECharts 库创建可视化图表的代码。通过这段代码&#xff0c;我们可以直观地分析咖啡店各年订单的情况。 饼图 这段代码包含了两个 ECharts 图表&#xff0c;一个是饼图&#xff0c;用…