Bean注入到Spring方式

news2025/2/27 17:23:18

扒一扒Bean注入到Spring的那些姿势

配置文件的方式就是以外部化的配置方式来声明Spring Bean,在Spring容器启动时指定配置文件。配置文件方式现在用的不多了,但是为了文章的完整性和连续性,这里我还是列出来了,知道的小伙伴可以自行跳过这节。

配置文件的类型Spring主要支持xml和properties两种类型。

xml

在XmlBeanInjectionDemo.xml文件中声明一个class为类型为User的Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       ">

    <bean class="com.sanyou.spring.bean.injection.User"/>

</beans>

User

@Data
@ToString
public class User {

    private String username;

}

测试:

public class XmlBeanInjectionDemo {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:XmlBeanInjectionDemo.xml");
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

结果:

User(username=null)

可以看出成功将User注入到Spring中,由于没有设置username属性值,所以是null。

properties

除了xml,spring还支持properties配置文件声明Bean的方式。

如下,在PropertiesBeanInjectionDemo.properties文件中声明了class类型为User的Bean,并且设置User的username属性为sanyou。

user.(class) = com.sanyou.spring.bean.injection.User
user.username = sanyou

测试:

public class PropertiesBeanInjectionDemo {

    public static void main(String[] args) {
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        //创建一个PropertiesBeanDefinitionReader,可以从properties读取Bean的信息,将读到的Bean信息放到applicationContext中
        PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(applicationContext);
        //创建一个properties文件对应的Resource对象
        Resource classPathResource = new ClassPathResource("PropertiesBeanInjectionDemo.properties");
        //加载配置文件
        propReader.loadBeanDefinitions(classPathResource);
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

结果:

User(username=sanyou)

成功获取到User对象,并且username的属性为properties设置的sanyou。

除了可以配置属性之外还支持其它的配置,如何配置可以查看PropertiesBeanDefinitionReader类上的注释。

图片

注解声明

上一节介绍了通过配置文件的方式来声明Bean,但是配置文件这种方式最大的缺点就是不方便,因为随着项目的不断扩大,可能会产生大量的配置文件。为了解决这个问题,Spring在2.x的版本中开始支持注解的方式来声明Bean。

@Component + @ComponentScan

这种方式其实就不用多说,在项目中自定义的业务类就是通过@Component及其派生注解(@Service、@Controller等)来注入到Spring容器中的。

在SpringBoot环境底下,一般情况下不需要我们主动调用@ComponentScan注解,因为@SpringBootApplication会调用@ComponentScan注解,扫描启动引导类(加了@SpringBootApplication注解的类)所在的包及其子包下所有加了@Component注解及其派生注解的类,注入到Spring容器中。

图片

@Bean

虽然上面@Component + @ComponentScan的这种方式可以将Bean注入到Spring中,但是有个问题那就是对于第三方jar包来说,如果这个类没加@Component注解,那么@ComponentScan就扫不到,这样就无法注入到Spring容器中,所以Spring提供了一种@Bean的方式来声明Bean。

比如,在使用MybatisPlus的分页插件的时候,就可以按如下方式这么来声明。

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    return interceptor;
}

此时就能将MybatisPlusInterceptor这个Bean注入到Spring容器中。

@Import

@Import注解也可以用来将Bean注入到Spring容器中,@Import注解导入的类可以分为三种情况:

  • 普通类
  • 类实现了ImportSelector接口
  • 类实现了ImportBeanDefinitionRegistrar接口
普通类

普通类其实就很简单,就是将@Import导入的类注入到Spring容器中,这没什么好说的。

类实现了ImportSelector接口
public interface ImportSelector {

    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }

}

当@Import导入的类实现了ImportSelector接口的时候,Spring就会调用selectImports方法的实现,获取一批类的全限定名,最终这些类就会被注册到Spring容器中。

比如如下代码中,UserImportSelector实现了ImportSelector,selectImports方法返回User的全限定名

public class UserImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("调用 UserImportSelector 的 selectImports 方法获取一批类限定名");
        return new String[]{"com.sanyou.spring.bean.injection.User"};
    }

}

当使用@Import注解导入UserImportSelector这个类的时候,其实最终就会把User注入到Spring容器中,如下测试

@Import(UserImportSelector.class)
public class ImportSelectorDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将 ImportSelectorDemo 注册到容器中
        applicationContext.register(ImportSelectorDemo.class);
        applicationContext.refresh();

        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

运行结果

User(username=null)

对于类实现了ImportBeanDefinitionRegistrar接口的情况,这个后面说。

一般来说,@Import都是配合@EnableXX这类注解来使用的,比如常见的@EnableScheduling、@EnableAsync注解等,其实最终都是靠@Import来实现的。

图片@EnableScheduling

图片@EnableAsync

讲完通过注解的方式来声明Bean之后,可以来思考一个问题,那就是既然注解方式这么简单,为什么Spring还写一堆代码来支持配置文件这种声明的方式?

其实答案很简单,跟Spring的发展历程有关。Spring在创建之初Java还不支持注解,所以只能通过配置文件的方式来声明Bean,在Java1.5版本开始支持注解之后,Spring才开始支持通过注解的方式来声明Bean。

注册BeanDefinition

在说注册BeanDefinition之前,先来聊聊什么是BeanDefinition?

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

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    //设置Bean className
    void setBeanClassName(@Nullable String beanClassName);

    //获取Bean className
    @Nullable
    String getBeanClassName();
    
    //设置是否是懒加载
    void setLazyInit(boolean lazyInit);

    //判断是否是懒加载
    boolean isLazyInit();
    
    //判断是否是单例
    boolean isSingleton();

}

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

有了BeanDefinition这个概念之后,再来看一下配置文件和注解声明这些方式往Spring容器注入Bean的原理。

图片Bean注入到Spring原理

如图为Bean注入到Spring大致原理图,整个过程大致分为以下几个步骤

  • 通过BeanDefinitionReader组件读取配置文件或者注解的信息,为每一个Bean生成一个BeanDefinition
  • BeanDefinition生成之后,添加到BeanDefinitionRegistry中,BeanDefinitionRegistry就是用来保存BeanDefinition
  • 当需要创建Bean对象时,会从BeanDefinitionRegistry中拿出需要创建的Bean对应的BeanDefinition,根据BeanDefinition的信息来生成Bean
  • 当生成的Bean是单例的时候,Spring会将Bean保存到SingletonBeanRegistry中,也就是平时说的三级缓存中的第一级缓存中,以免重复创建,需要使用的时候直接从SingletonBeanRegistry中查找

好了,通过以上分析我们知道,配置文件和注解声明的方式其实都是声明Bean的一种方式,最终都会转换成BeanDefinition,Spring是基于BeanDefinition的信息来创建Bean。

既然Spring最终是基于BeanDefinition的信息来创建Bean,那么我们是不是可以跳过配置文件和注解声明的方式,直接通过手动创建和注册BeanDefinition的方式实现往Spring容器中注入呢?

答案是可以的。

前面说过,BeanDefinition最终会被注册到BeanDefinitionRegistry中,那么如何拿到BeanDefinitionRegistry呢?主要有以下两种方式:

  • ImportBeanDefinitionRegistrar
  • BeanDefinitionRegistryPostProcessor

ImportBeanDefinitionRegistrar

上面在说@Import的时候,关于导入的类实现了ImportBeanDefinitionRegistrar接口的情况没有说,主要是因为在这里说比较合适

public interface ImportBeanDefinitionRegistrar {

   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,BeanNameGenerator importBeanNameGenerator) {
       registerBeanDefinitions(importingClassMetadata, registry);
   }

   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   }

}

ImportBeanDefinitionRegistrar中有两个方法,方法的参数就是BeanDefinitionRegistry。当@Import导入的类实现了ImportBeanDefinitionRegistrar接口之后,Spring就会调用registerBeanDefinitions方法,传入BeanDefinitionRegistry。

来个Demo

UserImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar

public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //构建一个 BeanDefinition , Bean的类型为 User
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class)
                //设置User这个Bean的属性username的值为icon
                .addPropertyValue("username", "icon")
                .getBeanDefinition();
        //把User的BeanDefinition注入到BeanDefinitionRegistry中
        registry.registerBeanDefinition("user", beanDefinition);
    }

}

测试类

@Import(UserImportBeanDefinitionRegistrar.class)
public class UserImportBeanDefinitionRegistrarDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(UserImportBeanDefinitionRegistrarDemo.class);
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

结果

User(username=icon的java日记)

从结果可以看出,成功将User注入到了Spring容器中。

上面的例子中有行代码

applicationContext.register(UserImportBeanDefinitionRegistrarDemo.class);

这行代码的意思就是把UserImportBeanDefinitionRegistrarDemo这个Bean注册到Spring容器中,所以这里其实也算一种将Bean注入到Spring的方式,原理也跟上面一样,会为UserImportBeanDefinitionRegistrarDemo生成一个BeanDefinition注册到Spring容器中。

BeanDefinitionRegistryPostProcessor

除了ImportBeanDefinitionRegistrar可以拿到BeanDefinitionRegistry之外,还可以通过BeanDefinitionRegistryPostProcessor拿到BeanDefinitionRegistry

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4l2qVrk0-1676429621108)(data:image/svg+xml,%3C%3Fxml version=‘1.0’ encoding=‘UTF-8’%3F%3E%3Csvg width=‘1px’ height=‘1px’ viewBox=‘0 0 1 1’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg’ xmlns:xlink=‘http://www.w3.org/1999/xlink’%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=‘none’ stroke-width=‘1’ fill=‘none’ fill-rule=‘evenodd’ fill-opacity=‘0’%3E%3Cg transform=‘translate(-249.000000, -126.000000)]’ fill=‘%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)BeanDefinitionRegistryPostProcessor

这种方式就不演示了。

手动注册BeanDefinition这种方式还是比较常见的。就比如说OpenFeign在启用过程中,会为每个标注了@FeignClient注解的接口创建一个BeanDefinition,然后再往Spring中的注册的,如下是OpenFeign注册FeignClient的部分代码

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

    private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
        //构建BeanDefinition,class类型为FeignClientFactoryBean
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
        String alias = contextId + "FeignClient";
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias });
        //注册BeanDefinition
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }
}

注册创建完成的Bean

上一节说可以跳过配置文件或者是注解,直接通过注册BeanDefinition以达到将Bean注入到Spring中的目的。

既然已经可以跳过配置文件或者是注解,那么我们可不可以更激进一步,跳过注册BeanDefinition这一步,直接往Spring中注册一个已经创建好的Bean呢?

答案依然是可以的。

因为上面在提到当创建的Bean是单例的时候,会将这个创建完成的Bean保存到SingletonBeanRegistry中,需要用到直接从SingletonBeanRegistry中查找。既然最终是从SingletonBeanRegistry中查找的Bean,那么直接注入一个创建好的Bean有什么不可以呢?

既然可以,那么如何拿到SingletonBeanRegistry呢?

其实拿到SingletonBeanRegistry的方法其实很多,因为ConfigurableListableBeanFactory就继承了SingletonBeanRegistry接口,所以只要能拿到ConfigurableListableBeanFactory就相当于拿到了SingletonBeanRegistry。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJ2OlRaq-1676429621108)(C:\Users\Lenovo\AppData\Local\Temp\1676425958065.png)]

ConfigurableListableBeanFactory类图

而ConfigurableListableBeanFactory可以通过BeanFactoryPostProcessor来获取

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0XB3TJs2-1676429621109)(C:\Users\Lenovo\AppData\Local\Temp\1676425972214.png)]

BeanFactoryPostProcessor

来个Demo

RegisterUserBeanFactoryPostProcessor实现BeanFactoryPostProcessor, 往Spring容器中添加一个手动创建的User对象

public class RegisterUserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //创建一个User对象
        User user = new User();
        user.setUsername("icon的java日记");
        //将这个User对象注入到Spring容器中
        beanFactory.registerSingleton("user", user);
    }

}

测试

public class RegisterUserDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(RegisterUserBeanFactoryPostProcessor.class);
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

结果

User(username=icon的java日记)

从结果还是可以看出,成功从Spring容器中获取到了User对象。

这种直接将创建好的Bean注入到Spring容器中在Spring框架内部使用的还是比较多的,Spring的一些内建的Bean就是通过这个方式注入到Spring中的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2OXpA5cv-1676429621109)(C:\Users\Lenovo\AppData\Local\Temp\1676428995026.png)]

如上图,在SpringBoot项目启动的过程中会往Spring容器中添加两个创建好的Bean,如果你的程序需要使用到这些Bean,就可以通过依赖注入的方式获取到。

虽然基于这种方式可以将Bean注入到Spring容器,但是这种方式注入的Bean是不经过Bean的生命周期的,也就是说这个Bean中诸如@Autowired等注解和Bean生命周期相关的回调都不会生效的,注入到Spring时Bean是什么样就是什么样,Spring不做处理,仅仅只是做一个保存作用。

FactoryBean

FactoryBean是一种特殊的Bean的类型,通过FactoryBean也可以将Bean注入到Spring容器中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENlZ0ZLD-1676429621109)(C:\Users\Lenovo\AppData\Local\Temp\1676429052192.png)]

FactoryBean

当我们通过配置文件、注解声明或者是注册BeanDenifition的方式,往Spring容器中注入了一个class类型为FactoryBean类型的Bean时候,其实真正注入的Bean类型为getObjectType方法返回的类型,并且Bean的对象是通过getObject方法返回的。

来个Demo

UserFactoryBean实现了FactoryBean,getObjectType返回了User类型,所以这个UserFactoryBean会往Spring容器中注入User这个Bean,并且User对象是通过getObject()方法的实现返回的。

public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        User user = new User();
        user.setUsername("icon的java日记");
        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

测试

public class UserFactoryBeanDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //将UserFactoryBean注入到Spring容器中
        applicationContext.register(UserFactoryBean.class);
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }

}

结果

User(username=icon的java日记)

成功通过UserFactoryBean将User这个Bean注入到Spring容器中了。

FactoryBean这中注入的方式使用也是非常多的,就拿上面举例的OpenFeign来说,OpenFeign为每个FeignClient的接口创建的BeanDefinition的Bean的class类型FeignClientFactoryBean就是FactoryBean的实现。

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    
    // FeignClient接口类型
    private Class<?> type;
    
    @Override
    public Object getObject() throws Exception {
       return getTarget();
    }
    
    @Override
    public Class<?> getObjectType() {
       return type;
    }
}

getObject()方法就会返回接口的动态代理的对象,并且这个代理对象是由Feign创建的,这也就实现了Feign和Spring的整合。

总结

通过以上分析可以看出,将Bean注入到Spring容器中大致可以分为5类:

  • 配置文件
  • 注解声明
  • 注册BeanDefinition
  • 注册创建完成的Bean
  • FactoryBean

以上几种注入的方式,在日常业务开发中,基本上都是使用注解声明的方式注入Spring中的;在第三方框架在和Spring整合时,注册BeanDefinition和FactoryBean这些注入方式也会使用的比较多;至于配置文件和注册创建完成的Bean的方式,有但是不多。

bean注入到spring的方式小结:

在这里插入图片描述

·············· END ··············

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

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

相关文章

Jetson Xavier NX设备将opencv和tensorrt链接到conda环境

注意安装的时候先查看设备旧版本的opencv&#xff0c;卸载干净后再装。 Jetpack4.6 opencv4.1.1 conda安装 过程翻一下之前的博客把&#xff0c;下面是创建环境开始 conda create -n py36 python3.6.9 OPENCV_EXTRA_MODULES_PATH/home/ta/open/opencv_contrib-4.1.1/modul…

白银走势图如何做空?

做现货白银的好处是&#xff0c;我们可以在白银走势图上做空&#xff0c;不再像股票那样只能先卖后买&#xff0c;还能先卖后买&#xff0c;这样我们做投资就多了一份从容&#xff01;任何时候我们都能获得投资获利的机会&#xff0c;但是由于习惯了单向交易&#xff0c;我们要…

Sarsa算法讲解及实现

Sarsa算法讲解及实现 1. Q表格 我们使用表格来存储每一个状态 state, 和在这个 state 每个行为 action 所拥有的 Q 值。 Q即为Q&#xff08;s,a&#xff09;就是在某一时刻的 s 状态下(s∈S)&#xff0c;采取动作a (a∈A)动作能够获得收益的期望&#xff0c;环境会根据agent…

java嵌入式持久化消息队列SMQ,改造自FQueue

一、说明之前项目中一直使用ConcurrentLinkedQueue做为缓冲队列&#xff08;主要是单个项目内&#xff0c;单条改批量的场景&#xff0c;多个项目间使用的是rocketmq&#xff09;&#xff0c;虽然用着方便但是是纯内存的&#xff0c;如果项目发生异常崩溃内存队列中的数据就会全…

JavaSE学习day6 进制转换和idea的调试

1.进制 1.1 常见的进制分类(掌握) 学过计算机组成原理的同学可以跳过这里。 二进制 十进制 八进制 十六进制 1.2 二进制 计算机数据在底层存储和运算的时候&#xff0c;都是以二进制的形式操作的&#xff0c;了解不同的进制&#xff0c;便于我们对数据的运算过程理解的更…

个人博客推出了更多功能

背景 Web2.0的典型代表博客&#xff0c;吸引着粉丝们打造属于自己的个人博客&#xff0c;分享自己的学习经验&#xff0c;记录自己的日常生活。随着大厂的入局&#xff0c;我们可以很容易的申请自己的个人博客&#xff0c;但是弊端就是往往会被他们控制&#xff0c;甚至封号。…

汕头市农村生活污水治理“十四五”规划行动方案

汕头&#xff0c;简称“汕”&#xff0c;广东省辖地级市&#xff0c;北接潮州&#xff0c;西邻揭阳&#xff0c;南濒南海&#xff0c;东与台湾隔海相望&#xff0c;境内韩江、榕江、练江三江入海&#xff0c;是中国大陆唯一拥有内海湾的城市。今天就来为大家介绍&#xff0c;汕…

Windows系统实现命令行(CMD)关闭指定的IIS网站

一、需求说明我们部署在Windows服务器上的IIS网站&#xff0c;需要在特定的时间停止一会后在进行重新启动该网站。二、思路分析由于需要特定的时间停止后重启网站&#xff0c;则手动操作肯定是不行的&#xff0c;需要实现自动化操作&#xff1a;①特定时间操作可以使用Windows系…

聚观早报|王慧文要做「中国版 OpenAI」;Temu斥资近亿元赞助超级碗

点击蓝字 / 关注我们今日要闻&#xff1a;王慧文要做「中国版 OpenAI」&#xff1b;Temu斥资近亿元赞助超级碗&#xff1b;新东方在线股价收跌2.8%&#xff1b;ChatGPT带动的AIGC创业热潮要来了&#xff1b;传谷歌拆分其AR部门王慧文要做「中国版 OpenAI」 2 月 13 日&#xff…

CSS中的常见单位(px,%,em,rem,vw,vh,vmax,vmin,calc)

像素(px)&百分比(%) 像素(Pixel) 长度单位&#xff0c;相对于显示器屏幕分辨率而言&#xff0c;通常在不定义显示缩放比例的情况下&#xff0c;1px对应显示器屏幕上的一个像素点。早年的pc端展示的页面基本都用这个单位。 百分比(%) 相对长度单位&#xff0c;指占用的父…

电源模块 DC-DC直流升压正负高压输出12v24v转±110V±150V±220V±250V±300V±600V

特点效率高达80%以上1*2英寸标准封装电源正负双输出稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上应用HRA 1~40W系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、9~18V、及18~36VDC标准&…

对比Hashtable、HashMap、TreeMap有什么不同?

第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同&#xff1f; Map 是广义 Java 集合框架中的另外一部分&#xff0c;HashMap 作为框架中使用频率最高的类型之一&#xff0c;它本身以及相关类型自然也是面试考察的热点。 今天我要问你的问题是&#xff0c;对比 Hashtable、…

HTTP协议——详细讲解

目录 一、HTTP协议 1.http 2.url url的组成&#xff1a; url的保留字符&#xff1a; 3.http协议格式​编辑 ①http request ②http response 4.对request做出响应 5.GET与POST方法 ①GET ②POST 7.HTTP常见Header ①Content-Type:: 数据类型(text/html等)在上文…

JavaSE系列 打基础版

JavaSE 笔记记录P1 Java概述1.1 java编译1.2 认识JDK、JRE1.3 下载jdk和配置环境变量1.4 开发注意事项和开发细节1.5 学习java之我的需求1.6 转义字符1.7 注释1.8 代码规范1.9 dos命令 了解P2 变量数据类型变量基本使用数据类型转换P3运算符P4 控制结构P5 数组、排序和查找P6面…

突破压缩极限的AI语音编解码器

I. Speech Codecs语音编码的目的是在保持语音质量的前提下尽可能地减少传输所用的带宽&#xff0c;主要是利用人的发声过程中存在的冗余度和人的听觉特性达到压缩的目的。经过了多年的发展&#xff0c;目前语音编解码器大致可以分为以下几类&#xff1a;波形编码&#xff0c;将…

c++ 指针、引用和常量

指针、引用和常量的关系_夜悊的博客-CSDN博客 1. ① 指针是对象&#xff0c;引用不是对象&#xff08;在此可以理解为变量&#xff0c;一个变量是一个对象&#xff09; 指针不必须初始化引用只是为一个已经存在的对象所起的另一个名字&#xff08;别名&#xff09;&#xff…

亚马逊云科技汽车行业解决方案

当今&#xff0c;随着万物智联、云计算等领域的高速发展&#xff0c;创新智能网联汽车和车路协同技术正在成为车企加速发展的关键途径&#xff0c;推动着汽车产品从出行代步工具向着“超级智能移动终端”快速转变。 挑战无处不在&#xff0c;如何抢先预判&#xff1f; 随着近…

安装 GPU 版本的 tensorflow 完整版本

前言&#xff1a; 之前安装的 CPU 版本的 tensorflow 一直出问题&#xff0c;索性就直接安装 GPU 版本的 tensorflow 了&#xff08;有了GPU 就不能浪费&#xff09;。 安装过程&#xff1a; 1&#xff09;看自己有无 GPU&#xff0c;找到对应 GPU 的版本&#xff1a;任务管理…

C生万物 | 常量指针和指针常量的感性理解

文章目录&#x1f4da;引言✒常量指针&#x1f50d;介绍与分析&#x1f4f0;小结与记忆口诀✒指针常量&#x1f50d;介绍与分析&#x1f4f0;小结与记忆口诀&#x1f449;一份凉皮所引发的故事&#x1f448;总结与提炼&#x1f4da;引言 本文我们来说说大家很困惑的两个东西&am…

【蒸滴C】C语言指针入门很难?看这一篇就够了

目录 一、前言 二、指针是什么 小结&#xff1a; 三、指针变量是什么 小结&#xff1a; 四、指针在32位机器和64位机器中的差别 32位机器&#xff1a; 64位机器: 小结&#xff1a; 五、指针和指针类型 &#xff08;1&#xff09;指针的意义 &#xff08;2&#xff…