【Spring】一文带你搞懂Spring容器配置

news2024/11/14 20:24:17

前言

在这里插入图片描述

本文为大家介绍的是Spring容器配置相关知识,包含@Bean@Configuration的使用,使用 AnnotationConfigApplicationContext实例化Spring容器,@Bean注解的使用,@Configuration的使用,@Import 注解的使用,结合Java和XML配置等~

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)

在这里插入图片描述

目录

文章标题

  • 前言
  • 目录
  • 1️⃣@Bean和@Configuration
  • 2️⃣使用 `AnnotationConfigApplicationContext`实例化Spring容器
  • 3️⃣ @Bean注解
  • 4️⃣`@Configuration`
  • 5️⃣ 使用 `@Import `注解
  • 6️⃣结合Java和XML配置
  • 后记


在这里插入图片描述


1️⃣@Bean和@Configuration

Spring新的java配置支持的中心组件是带注解的【@Configuration】类和带注解的【@Bean】方法。

@Bean注解用于指示一个方法,该方法负责【实例化、配置和初始化】一个由Spring IoC容器管理的新对象。 对于那些熟悉Spring <beans/>XML配置的人来说,@Bean注解扮演着与<bean/> 元素相同的角色。 你可以在任何Spring @Component中使用@Bean注解方法。 但是,它们最常与@Configuration一起使用。

@Configuration注解的一个类表明它的主要目的是作为beanDifination的源,我们通常称之为【配置类】。 此外,【@Configuration】类允许通过调用同一类中的其他【@Bean 】方法来【定义bean间的依赖关系】。 最简单的【@Configuration】类如下所示:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

前面的’ AppConfig '类等价于下面的Spring <beans/>XML:

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

2️⃣使用 AnnotationConfigApplicationContext实例化Spring容器

下面的章节记录了Spring 3.0中引入的【AnnotationConfigApplicationContext】。 这个通用的【ApplicationContext】实现不仅能够接受【@Configuration】类作为输入,还能够接受普通的【@Component】类和用JSR-330元数据注解的类。

当提供【@Configuration】类作为输入时,【@Configuration】类本身被注册为一个beanDifination,并且类中所有声明的【@Bean】方法也被注册为beanDifination。

​ 当提供【@Component 】和JSR-330相关的注解类时,它们被注册为beanDifination。

a、结构简洁

就像Spring XML文件在实例化【ClassPathXmlApplicationContext】时被用作输入一样,当实例化【AnnotationConfigApplicationContext】时,你可以使用【@Configuration】类作为输入。 这允许Spring容器完全不使用xml,如下例所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

正如前面提到的,【AnnotationConfigApplicationContext】并不局限于只与【@Configuration】类一起工作。 任何【@Component】或JSR-330注解类都可以作为输入提供给构造函数,如下面的例子所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.classDependency1.classDependency2.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

前面的例子假设【MyServiceImpl】、【Dependency1】和【Dependency2】使用Spring依赖注入注解,比如【@Autowired】。

b、通过使用’ register(Class<?>…)'以编程方式构建容器

你可以使用一个【没有参数的构造函数】来实例化一个【AnnotationConfigApplicationContext】,然后使用【register()】方法来配置它。 当以编程方式构建一个“AnnotationConfigApplicationContext”时,这种方法特别有用。 下面的例子展示了如何做到这一点:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.classOtherConfig.class);
    ctx.register(AdditionalConfig.class);
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

c、使用 scan(String…)启用组件扫描

要启用组件扫描,你可以像下面这样注解你的 @Configuration 类:

@Configuration
@ComponentScan(basePackages = "com.acme") 
public class AppConfig  {
    // ...
}
<beans> 
	<context:component-scan base-package="com.ydlclass" / > 
</beans>

同时,AnnotationConfigApplicationContext也暴露了【 scan(String…)】方法来允许相同的组件扫描功能,如下例所示:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
}

请记住,【@Configuration】类是带有【@Component】元注解的一个注解,因此它们是组件扫描的候选对象。 在前面的例子中,假设【AppConfig】在"com.acme"中声明。 在’ refresh() ‘之后,它的所有’ @Bean '方法都被处理并注册为容器中的beanDifination。

3️⃣ @Bean注解

@Bean】是一个方法级注解,与XML<bean/> 元素具有相同的能力。 注解支持<bean/>提供的一些属性,例如:

  • init-method
  • destroy-method
  • autowiring
  • name

你可以在带有【@Configuration】注解的类或带有【@Component】注解的类中使用【@Bean】注解。

a、声明一个 Bean

使用【@Bean】对方法进行注解可以帮助我们申明一个bean。 您可以使用此方法在【ApplicationContext】中注册一个beanDifination,该bean的类型会被指定为【方法的返回值类型】,而具体的返回值则是交由spring管理的bean实例。 默认情况下,bean名与方法名相同。 下面的例子显示了一个【 @Bean 】方法声明:

@Configuration
public class AppConfig {

    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

上面的配置与下面的Spring XML完全相同:

<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

注意: 你也可以使用接口(或基类)作为返回类型来声明你的@Bean方法,如下面的例子所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

b、Bean的依赖关系

带注解的【@Bean】方法可以有任意数量的参数,这些参数描述构建该bean所需的依赖关系。 例如,如果我们的【TransferService】需要一个【AccountRepository】,我们可以用一个方法参数来实现这个依赖,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

c、接受生命周期回调

  • 任何用【@Bean】注解定义的类都支持常规的生命周期回调,并且可以使用JSR-250的’ @PostConstruct ‘和’ @PreDestroy '注解。
  • 也完全支持常规的Spring lifecycle回调。 如果一个bean实现了’ InitializingBean ‘、’ DisposableBean ‘或’ Lifecycle ',则容器会调用它们各自的方法。
  • 标准的【Aware 】接口也完全支持。

@Bean注解】支持指定任意的初始化和销毁回调方法,就像Spring XML在’ bean ‘元素上的’ init-method ‘和’ destroy-method '属性一样,如下面的示例所示:

public class BeanOne {

    public void init() {
        // initialization logic
    }
}

public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }

    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

小知识: 对于上面例子中的’ BeanOne ‘,在构造过程中直接调用’ init() '方法同样有效,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        BeanOne beanOne = new BeanOne();
        beanOne.init();
        return beanOne;
    }

    // ...
}

当您直接在代码中进行配置时,您可以对您的对象做任何您想做的事情,而不总是需要依赖于容器生命周期。

d、指定Bean范围

Spring包含了【@Scope】注解,以便您可以指定bean的范围。
默认的作用域是’ singleton ‘,但是你可以用’ @Scope '注解来覆盖它,如下面的例子所示:

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
}

e、定制Bean命名

默认情况下,配置类使用【@Bean】方法的名称作为结果bean的名称。 但是,可以使用’ name '属性覆盖该功能,如下例所示:

@Configuration
public class AppConfig {

    @Bean("myThing")
    public Thing thing() {
        return new Thing();
    }
}

有时需要为单个bean提供多个名称,或者称为bean别名。【@Bean】注解的’ name '属性为此接受String数组。 下面的例子展示了如何为一个bean设置多个别名:

@Configuration
public class AppConfig {

    @Bean({"dataSource""subsystemA-dataSource""subsystemB-dataSource"})
    public DataSource dataSource() {
        // instantiate, configure and return DataSource bean...
    }
}

f、Bean 描述

有时,提供bean的更详细的文本描述是很有帮助的。 当bean被公开(可能通过JMX)用于监视目的时,这可能特别有用。

要向【@Bean】添加描述,可以使用【@Description】注解,如下面的示例所示:

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }
}

4️⃣@Configuration

@Configuration】是一个类级注解,指示一个对象是beanDifination的源。【@Configuration】类通过【@Bean】带注解的方法声明bean。 【在“@Configuration”类上调用“@Bean”方法也可以用来定义bean间的依赖关系】。

注入bean之间的依赖

@Bean方法在没有标注@Configuration的类中声明时,它们被认为是在【lite】模式下处理的。 在【@Component】中声明的Bean方法甚至在一个普通的类中声明的Bean方法都被认为是【lite】。在这样的场景中,【@Bean】方法是一种通用工厂方法机制。

​ 与@Configuration 不同,【lite】模式下 【@Bean】方法不能【声明bean】间的【依赖关系】。 因此,这样的【@Bean】方法不应该调用其他【@Bean】下的方法。 每个这样的方法实际上只是特定bean引用的工厂方法,没有任何特殊的运行时语义。

​ 在一般情况下,@Bean方法要在【@Configuration】类中声明,这种功能情况下,会使用【full】模式,因此交叉方法引用会被重定向到容器的生命周期管理。 这可以防止通过常规Java调用意外调用相同的Bean,这有助于减少在【lite】模式下操作时难以跟踪的微妙错误。

@Bean@Configuration注解将在下面几节中深入讨论。 不过,我们首先介绍通过使用基于java的配置创建spring容器的各种方法。

当bean相互依赖时,表示这种依赖就像让一个bean方法调用另一个bean方法一样简单,如下面的示例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        // full模式可以直接调用方法,这个调用过程由容器管理,lite模式这就是普通方法调用,多次调用会产生多个实例。
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

在前面的例子中,【beanOne】通过构造函数注入接收对【beanTwo】的引用。

考虑下面的例子,它显示了一个带注解的@Bean方法被调用两次:

@Configuration
public class AppConfig {

    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }
}

clientDao() 在【clientService1()】和【clientService2()】中分别被调用一次。 由于该方法创建了一个新的【ClientDaoImpl】实例并返回它,所以通常期望有两个实例(每个服务一个)。 这肯定会有问题。在Spring中,实例化的bean默认有一个【单例】作用域,在调用父方法并创建新实例之前,首先检查容器中是否有缓存的(有作用域的)bean。

我们目前学习的描述候选组件的注解很多,但是仔细意思考,其实很简单:

我们自己的写代码通常使用以下注解来标识一个组件:

  • @Component 组件的通用注解
  • @Repository,持久层
  • @Service,业务层
  • @Controller,控制层
  • @Configuration + @Bean

配置类通常是我们不能修改源代码,但是需要注入别人写的类。例如向容器注入一个德鲁伊数据源的bean,我们是绝对不能给这个类加个【@Component 】注解的。

5️⃣ 使用 @Import 注解

就像在Spring XML文件中使用<import/> 元素来实现模块化配置一样,@Import注解允许从另一个配置类加载【@Bean】定义,如下面的示例所示:

@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}

现在,在实例化上下文时不需要同时指定ConfigA.class ConfigB.class,只需要显式地提供【ConfigB】,如下面的示例所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

    // now both beans A and B will be available...
    A a = ctx.getBean(A.class);
    B b = ctx.getBean(B.class);
}

这种方法简化了容器实例化,因为只需要处理一个类,而不是要求您在构造过程中记住潜在的大量【@Configuration】类。

【小知识】: 我们一样可以给该注解传入一个实现了ImportSelector接口的类,返回的字符串数组的Bean都会被加载到容器当中:

public class ConfigSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.ydlclass.A""com.ydlclass.B"};
    }
}

6️⃣结合Java和XML配置

Spring的【@Configuration】类支持的目标并不是100%完全替代Spring XML,有些场景xml仍然是配置容器的理想方式。

我们有如下选择:

  • (1)容器实例化在一个“以XML为中心”的方式使用,例如“ClassPathXmlApplicationContext”。
  • (2)"以java编程的方式为中心”的方式,实例化它通过使用【@ImportResource】注解导入XML。

以xml为中心使用“@Configuration”类

最好从XML引导Spring容器,并以一种特别的方式包含【@Configuration 】类。将【@Configuration 】类声明为普通的Spring <bean/> 元素。记住,【@Configuration】类最终是容器中的beanDifination。

下面的例子展示了Java中一个普通的配置类:

@Configuration
public class AppConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }

    @Bean
    public TransferService transferService() {
        return new TransferService(accountRepository());
    }
}

下面的例子显示了一个’ system-test-config.xml '文件的一部分:

<beans>
    <!-- enable processing of annotations such as @Autowired and @Configuration -->
    <context:annotation-config/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="com.acme.AppConfig"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

下面的示例显示了一个可能的’ jdbc '。 属性的文件:

user=root
password=root
url=jdbc:mysql://127.0.0.1:3306/ydlclass?characterEncoding=utf8&serverTimezone=Asia/Shanghai
driverName=com.mysql.cj.jdbc.Driver
public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

因为【@Configuration】是用【@Component】注解的,所以被【@Configuration】注解的类会自动被组件扫描。 使用与前面示例中描述的相同的场景,我们可以重新定义system-test-config.xml来利用组件扫描。

下面的示例显示了修改后的system-test-config.xml文件:

<beans>
    <!-- picks up and registers AppConfig as a bean definition -->
    <context:component-scan base-package="com.acme"/>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

使用@ImportResource以类为中心使用XML

在【@Configuration】类是配置容器的主要机制的应用程序中,可能仍然需要使用至少一些XML。 在这些场景中,您可以使用【@ImportResource】注解,并只定义所需的XML。 这样做可以实现一种“以java为中心”的方法来配置容器,并将XML最小化。

下面的例子说明了这一点:

@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(url, username, password);
    }
}

properties-config.xml:

<beans>
    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>

jdbc.properties::

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=

启动容器:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

后记

在这里插入图片描述

👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

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

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

相关文章

C++中STL-set详解

目录 set/ multiset容器 1. set基本概念 2.set构造和赋值 3.set大小和交换 4.set插入和删除 5.set容器-查找和统计 6.set和multiset的区别 7.pair对组创建 8.set容器排序 9.set存放自定义数据类型 set/ multiset容器 1. set基本概念 简介: 所有元素都会在插入时自动…

使用Apisix打造家庭NAS网关,免公网IP访问

使用Apisix打造家庭NAS网关 本文使用apisix打造家庭NAS网关&#xff0c;并通过cloudflare进行穿透&#xff0c;可免公网IP访问。首先你的NAS支持Docker&#xff0c;没有NAS也没有关系&#xff0c;只要你的电脑支持Docker同样可以参照该教程。 1 依赖资源准备 准备域名: 免费…

HTML+CSS+JS做一个好看的个人网页—web网页设计作业

个人网页设计个人网页&#xff08;htmlcssjs&#xff09;——网页设计作业带背景音乐&#xff08;The way I still Love you&#xff09;、樱花飘落效果、粒子飘落效果页面美观&#xff0c;样式精美涉及&#xff08;htmlcssjs&#xff09;&#xff0c;下载后可以根据自己需求进…

8086,8088CPU管脚,奇偶地址体, 时钟信号发生器8284 ,ready信号,reset复位信号。规则字和非规则字

8086/8088均为40条引线&#xff0c;双列直插式封装&#xff0c;某些引线有多重功能&#xff0c;其功能转换有两种情况&#xff1a;一种是分时复用&#xff0c;一种是按组态定义。 用8088微处理器构成系统时&#xff0c;有两种不同的组态&#xff1a; 最小组态&#xff1a;808…

模型效果不好?推荐你8种机器学习调参技巧

大家好&#xff0c;今天给大家一篇关于机器学习调参技巧的文章 超参数调优是机器学习例程中的基本步骤之一。该方法也称为超参数优化&#xff0c;需要搜索超参数的最佳配置以实现最佳性能。 机器学习算法需要用户定义的输入来实现准确性和通用性之间的平衡。这个过程称为超参…

嵌入式开发学习之--RCC(上)

提示&#xff1a;本篇主要介绍一下不同时钟的特性和作用&#xff0c;了解为主。 文章目录前言一、RCC简介二、系统时钟简介2.1HSE 高速外部时钟信号2.2锁相环 PLL2.3系统时钟 SYSCLK2.4AHB 总线时钟 HCLK2.5 APB2 总线时钟 HCLK22.6 APB1 总线时钟 HCLK1三、其他时钟3.1RTC 时钟…

HTTP 请求是什么?

文章目录HTTP请求一&#xff0c;请求行二&#xff0c;请求头三&#xff0c;空行四&#xff0c;请求体五&#xff0c;HTTP请求示例HTTP请求 请求是由客户端向服务器发送的&#xff0c;一般可以分为请求行、请求头、空行和请求体四个部分&#xff0c;如下图所示&#xff1a; 一…

【数据集NO.2】工业检测数据集汇总(缺陷、纹理等检测)

文章目录前言一、东北大学钢材表面缺陷数据集二、天池铝型材表面缺陷数据集三、Severstal 带钢缺陷数据集四、UCI 带钢缺陷数据集五、磁瓦缺陷数据集六、RSDDs铁轨表面缺陷数据集七、印刷电路板&#xff08;PCB&#xff09;瑕疵数据集八、坑洼检测数据集九、Kylberg纹理检测十、…

C语言:文件操作(1)

1、什么是文件&#xff1f; 磁盘上的文件是文件。 但是在程序设计中&#xff0c;我们一般谈的文件有两种: 程序文件、数据文件 程序文件&#xff1a; 包括源程序文件(后缀为.c)&#xff0c;目标文件(windows环境后缀为.obj)&#xff0c;可执行程序(wndows环境后缀为.exe) 数…

初级测试到中级测试就差这几个找bug小技巧

前言 测试的过程就是一个寻找影响产品功能和用户体验bug的过程&#xff0c;测试人员发现的bug类型五花八门。 当你在上班期间&#xff0c;听到不远处传来这样的声音“你会不会提BUG&#xff0c;责任人都指派错了&#xff0c;还能好好提吗&#xff1f;” 如果哪天开发对着你说…

Babel自动生成Attribute文档实现详解

这篇文章主要为大家介绍了Babel自动生成Attribute文档实现示例详解&#xff0c;有需要的朋友可以借鉴参考下&#xff0c;希望能够有所帮助&#xff01; 1. 前言 利用Babel自动解析源码属性上的注释生成对应Markdown文档&#xff0c;这个场景的应用主要包括在组件库文档对组件…

SpringBoot单元测试

文章目录1、什么是单元测试2、单元测试有哪些好处&#xff1f;3、SpringBoot 单元测试使用3.1 生成单元测试的类3.2 配置单元测试的类并添加SpringBootTest注解3.3 添加单元测试的业务代码3.4 进行测试并查看结果3.5 使用断言3.6 在不修改数据库的前提下&#xff0c;执行单元测…

室内温度控制仿真模型(Simulink+PLC)

本篇博客将会和大家一起一步步解读Simulink自带的仿真模型(Thermal Model of a House),之后再讨论PLC控制系统控制环境温度的一些经验方法。温度控制的大部分控制方法都是采用PID控制,有关PLC的PID控制相关内容可以参看专栏的其它文章,链接如下: 博途PLC 1200/1500PID P…

【LeetCode每日一题:1774. 最接近目标价格的甜点成本~~~递归+深度优先遍历】

题目描述 你打算做甜点&#xff0c;现在需要购买配料。目前共有 n 种冰激凌基料和 m 种配料可供选购。而制作甜点需要遵循以下几条规则&#xff1a; 必须选择 一种 冰激凌基料。 可以添加 一种或多种 配料&#xff0c;也可以不添加任何配料。 每种类型的配料 最多两份 。 给你…

java计算机毕业设计ssm人事考勤管理系统1u133(附源码、数据库)

java计算机毕业设计ssm人事考勤管理系统1u133&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

Spread 16.X FOR WPF 中文版 我就喜欢 Spread.NET

Spread 16.X FOR WPF 中文版您可以将 Microsoft Excel 的强大功能嵌入到 WPF 和 Silverlight 应用中&#xff0c;使用丰富的内嵌数据可视化功能展现核心数据和分析结果&#xff0c;按需自定制富有创意的表格模版以及发挥更多便捷高效的功能。Spread WPF-Silverlight 源自备受好…

RIoTBoard开发板系列笔记(十三)—— yocto SDK安装与使用

yocto是一个很强大的嵌入式image 构建工具&#xff0c;借助yocto可以轻松的构建出一个开发板镜像。如果我们想借助yocto开发一些应用层的程序&#xff0c;有以下两种方法可供选择&#xff1a; &#xff08;1&#xff09;按照yocto的构建规则添加自己的程序和编译脚步&#xff0…

通话蓝牙耳机什么牌子好?通话工作蓝牙耳机推荐

在一般人的印象中&#xff0c;蓝牙耳机主要是用于听听歌、打打游戏还有煲剧&#xff0c;&#xff0c;而对经常经常外出的商务差旅人士和音乐发烧友来说&#xff0c;蓝牙耳机的通话和续航也是重点关注的&#xff0c;因此&#xff0c;笔者专门整理了一些通话效果好的蓝牙耳机&…

微服务框架 SpringCloud微服务架构 9 初识 Docker 9.3 Docker 架构

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构9 初识 Docker9.3 Docker 架构9.3.1 镜像和容器9.3.2 Docker 和DockerHub9…

【C/C++】C语言runtime调用技术

概述 C语言编译后&#xff0c;在可执行文件中会有 函数名信息。如果想要动态调用一个C函数&#xff0c;首先需要 根据函数名找到这个函数地址 &#xff0c;然后根据函数地址进行调用。 动态链接器已经提供一个 API&#xff1a;dlsym()&#xff0c;可以通过函数名字拿到函数地…