SpringBoot自动配置

项目内部配置第三方bean

  1. 第三方的bean通过配置类的@bean注入,项目内部引用使用@Import配置类的class

  2. 解耦引入的第三方配置类, 新建一个缓冲类加载需要引入的配置类

  3. 将需要引入第三方配置类加入Mate-inf中的factories中

  4. 加载返回可以引入第三方的bean

  5. 本项目bean和第三方bean冲突,以本项目为准(import先解析被覆盖,默认不可以覆盖)

    1. DeferredImportSelector推迟导入,先解析本项目的

    2. @ConditionalOnMissingBean本项目没有,则加载第三方的

package com.butch.a41;

import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public class A41_1 {

    @SuppressWarnings("all")
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.getDefaultListableBeanFactory().setAllowBeanDefinitionOverriding(false);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(context.getBean(Bean1.class));
    }

    @Configuration // 本项目的配置类
    @Import(MyImportSelector.class)
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1("本项目");
        }
    }

    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                //EnableAutoConfiguration为key的类名
//            for (String name : SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, null)) {
//                System.out.println(name);
//            }
//            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            //获取配置文件中值 也会扫描第三方jar包的factories
            List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);

            return names.toArray(new String[0]);
        }
    }

    @Configuration // 第三方的配置类
    static class AutoConfiguration1 {
        @Bean
        @ConditionalOnMissingBean
        public Bean1 bean1() {
            return new Bean1("第三方");
        }
    }

    static class Bean1 {
        private String name;

        public Bean1() {
        }

        public Bean1(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Bean1{" +
                   "name='" + name + '\'' +
                   '}';
        }
    }

    @Configuration // 第三方的配置类
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean2 {

    }
}

自动配置实现类

AopAutoConfiguration(AOP)
  • AOP 自动配置类为 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

  • 可以通过 spring.aop.auto=false 禁用 aop 自动配置

  • AOP 自动配置的本质是通过 @EnableAspectJAutoProxy 来开启了自动代理,如果在引导类上自己添加了 @EnableAspectJAutoProxy 那么以自己添加的为准

  • @EnableAspectJAutoProxy 的本质是向容器中添加了 AnnotationAwareAspectJAutoProxyCreator 这个 bean 后处理器,它能够找到容器中所有切面,并为匹配切点的目标类创建代理,创建代理的工作一般是在 bean 的初始化阶段完成的

多层嵌套的静态内部类,最后一层EnableAspectJAutoProxy 导入代理创建器

  1. spring.aop.auto!= false才加载

  2. @ConditionalOnClass(Advice.class)存在Advice

  3. @ConditionalOnMissingClass("org.aspectj.weaver.Advice") 缺失条件

  4. 最终@EnableAspectJAutoProxy 本质是import,proxyTargetClass创建代理的模式,为false会看看有没有实现接口有接口jdk代理

  5. 最终注册AnnotationAwareAspectJAutoProxyCreator的bean后处理器,高层转底层创建jdk或者cglib代理

package com.butch.a41;

import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.type.AnnotationMetadata;

public class TestAopAuto {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        StandardEnvironment env = new StandardEnvironment();
        env.getPropertySources().addLast(new SimpleCommandLinePropertySource("--spring.aop.auto=true"));
        context.setEnvironment(env);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.registerBean(Config.class);
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        //org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration
        //org.springframework.aop.config.internalAutoProxyCreator
        //org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration
        //org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
        System.out.println(">>>>>>>>>>>>>>>");
        //查看代理实现类型
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(
                "org.springframework.aop.config.internalAutoProxyCreator", AnnotationAwareAspectJAutoProxyCreator.class);
        System.out.println(creator.isProxyTargetClass());

    }

    @Configuration
    @Import(MyImportSelector.class)
    static class Config {

    }

    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{AopAutoConfiguration.class.getName()};
        }
    }
}
Datasource
  • 对应的自动配置类为:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

  • 它内部采用了条件装配,通过检查容器的 bean,以及类路径下的 class,来决定该 @Bean 是否生效

简单说明一下,Spring Boot 支持两大类数据源:

  • EmbeddedDatabase - 内嵌数据库连接池

  • PooledDataSource - 非内嵌数据库连接池

PooledDataSource 又支持如下数据源

  • hikari 提供的 HikariDataSource

  • tomcat-jdbc 提供的 DataSource

  • dbcp2 提供的 BasicDataSource

  • oracle 提供的 PoolDataSourceImpl

如果知道数据源的实现类类型,即指定了 spring.datasource.type,理论上可以支持所有数据源,但这样做的一个最大问题是无法订制每种数据源的详细配置(如最大、最小连接数等)

dataSource

  1. @Conditional(PooledDataSourceCondition.class)进入带有连接池的数据源

  2. 集成mybaits依赖jdbc进入@ConditionalOnClass(HikariDataSource.class)

  3. @EnableConfigurationProperties(DataSourceProperties.class)封装绑定键值信息,spring.datasourcexxxxx

    1. 创建datasource绑定键值信息

mybits
  • MyBatis 自动配置类为 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

  • 它主要配置了两个 bean

    • SqlSessionFactory - MyBatis 核心对象,用来创建 SqlSession

    • SqlSessionTemplate - SqlSession 的实现,此实现会与当前线程绑定

    • 用 ImportBeanDefinitionRegistrar 的方式扫描所有标注了 @Mapper 注解的接口

    • 用 AutoConfigurationPackages 来确定扫描的包

  • 还有一个相关的 bean:MybatisProperties,它会读取配置文件中带 mybatis. 前缀的配置项进行定制配置

@MapperScan 注解的作用与 MybatisAutoConfiguration 类似,会注册 MapperScannerConfigurer 有如下区别

  • @MapperScan 扫描具体包(当然也可以配置关注哪个注解)

  • @MapperScan 如果不指定扫描具体包,则会把引导类范围内,所有接口当做 Mapper 接口

  • MybatisAutoConfiguration 关注的是所有标注 @Mapper 注解的接口,会忽略掉非 @Mapper 标注的接口

  • 其实并非将接口交给 Spring 管理,而是每个接口会对应一个 MapperFactoryBean,是后者被 Spring 所管理,接口只是作为 MapperFactoryBean 的一个属性来配置

package com.butch.a41;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.type.AnnotationMetadata;

public class TestDataSourceAuto {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        StandardEnvironment env = new StandardEnvironment();
        //添加配置源
        env.getPropertySources().addLast(new SimpleCommandLinePropertySource(
                "--spring.datasource.url=jdbc:mysql://localhost:3306/test",
                "--spring.datasource.username=root",
                "--spring.datasource.password=123456"
        ));
        context.setEnvironment(env);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.registerBean(Config.class);

        String packageName = TestDataSourceAuto.class.getPackage().getName();
        System.out.println("当前包名:" + packageName);
        AutoConfigurationPackages.register(context.getDefaultListableBeanFactory(),
                packageName);

        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            String resourceDescription = context.getBeanDefinition(name).getResourceDescription();
            if (resourceDescription != null)
                System.out.println(name + " 来源:" + resourceDescription);
            //dataSource 来源:class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]
            //hikariPoolDataSourceMetadataProvider 来源:class path resource [org/springframework/boot/autoconfigure/jdbc/metadata/DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration.class]
            //sqlSessionFactory 来源:class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
            //sqlSessionTemplate 来源:class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
            //transactionManager 来源:class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfiguration$DataSourceTransactionManagerConfiguration.class]
            //org.springframework.transaction.config.internalTransactionAdvisor 来源:class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]
            //transactionAttributeSource 来源:class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]
            //transactionInterceptor 来源:class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]
            //org.springframework.transaction.config.internalTransactionalEventListenerFactory 来源:class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]
            //transactionTemplate 来源:class path resource [org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration$TransactionTemplateConfiguration.class]
            //platformTransactionManagerCustomizers 来源:class path resource [org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.class]

        }
    }

    @Configuration
    @Import(MyImportSelector.class)
    static class Config {

    }

    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{
                    //配置数据源 必选
                    DataSourceAutoConfiguration.class.getName(),
                    //mybit的sqlsession工程mapper扫描
                    MybatisAutoConfiguration.class.getName(),
                    //事务管理
                    DataSourceTransactionManagerAutoConfiguration.class.getName(),
                    //声明式事务管理
                    TransactionAutoConfiguration.class.getName()
            };
        }
    }
}

 

TransactionAutoConfiguration
  • 事务自动配置类有两个:

    • org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration

    • org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

  • 前者配置了 DataSourceTransactionManager 用来执行事务的提交、回滚操作

  • 后者功能上对标 @EnableTransactionManagement,包含以下三个 bean

    • BeanFactoryTransactionAttributeSourceAdvisor 事务切面类,包含通知和切点

    • TransactionInterceptor 事务通知类,由它在目标方法调用前后加入事务操作

    • AnnotationTransactionAttributeSource 会解析 @Transactional 及事务属性,也包含了切点功能

  • 如果自己配置了 DataSourceTransactionManager 或是在引导类加了 @EnableTransactionManagement,则以自己配置的为准

WebMvcAutoConfiguration
  • 配置 DispatcherServlet 的各项组件,提供的 bean 见过的有

    • 多项 HandlerMapping

    • 多项 HandlerAdapter

    • HandlerExceptionResolver

自定义自动配置类

  1. 自动配置类本质上就是一个配置类而已,只是用 META-INF/spring.factories 管理,与应用配置类解耦

  2. @Enable 打头的注解本质是利用了 @Import

  3. @Import 配合 DeferredImportSelector 即可实现导入,selectImports 方法的返回值即为要导入的配置类名

  4. DeferredImportSelector 的导入会在最后执行,为的是让其它配置优先解析

package com.butch.a41;

import org.springframework.boot.autoconfigure.AutoConfigurationImportSelector;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.io.IOException;
import java.util.List;

public class A41_2 {

    @SuppressWarnings("all")
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        StandardEnvironment env = new StandardEnvironment();
        env.getPropertySources().addLast(new SimpleCommandLinePropertySource(
                "--spring.datasource.url=jdbc:mysql://localhost:3306/test",
                "--spring.datasource.username=root",
                "--spring.datasource.password=root"
        ));
        context.setEnvironment(env);        
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(context.getBean(Bean1.class));
    }

    //spring识别的import
//    @Import(AutoConfigurationImportSelector.class)
//    @Import(MyImportSelector.class)
    @EnableAutoConfiguration
    @Configuration // 本项目的配置类
    static class Config {

    }

    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            //EnableAutoConfiguration为key的类名
//            for (String name : SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, null)) {
//                System.out.println(name);
//            }
//            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            //获取配置文件中值
            List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);

            return names.toArray(new String[0]);
        }
    }

    @Configuration // 第三方的配置类
    static class AutoConfiguration1 {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    }



    @Configuration // 第三方的配置类
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean2 {

    }

    static class Bean1 {

    }
}

条件装配底层

当引入第三方的bean ,增加条件装配

底层使用conditional 配合实现了condition的接口进行检查

本质上是if-else语句

package com.butch.a42;


import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;

public class A42_2 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

    }
    @Configuration // 本项目的配置类
    @Import(MyImportSelector.class)
    static class Config {
    }
    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{AutoConfiguration1.class.getName(), AutoConfiguration2.class.getName()};
        }
    }

    static class Mycondition1 implements Condition{
        //检测德鲁伊存在
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            System.out.println("ClassUtils.isPresent(\"DruidDataSource\", null)" + ClassUtils.isPresent("DruidDataSource", null));
            return ClassUtils.isPresent("com.alibaba.druid.pool.DruidDataSource" +
                    "", null);
        }
    }
    static class Mycondition2 implements Condition{
        //检测德鲁伊不存在
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

            return !ClassUtils.isPresent("com.alibaba.druid.pool.DruidDataSource", null);
        }
    }


//    @ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = false) //有德鲁伊bean1 无德鲁伊bean2
    @Configuration // 第三方的配置类
    @Conditional(Mycondition1.class)
    static class AutoConfiguration1 {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    }

    @Configuration // 第三方的配置类
//    @ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = true)
    @Conditional(Mycondition2.class)
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {

    }

    static class Bean2 {

    }
}

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

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

相关文章

leetcode每日一练:链表OJ题

链表经典算法OJ题 1.1 移除链表元素 题目要求&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&a…

Kotlin扩展函数(also apply run let)和with函数

also apply run let with的使用例子 private fun testOperator() {/*** also*/val person Person("ZhangSan", 18)person.also {// 通常仅仅打印使用, 也可以通过it修改it.name "ZhangSan1"println("also inner name: " it.name)}println(&qu…

如何理解MySql的MVCC机制

MVCC是什么 MySQL的MVCC机制&#xff0c;全称为多版本并发控制&#xff08;Multi-VersionConcurrency Control&#xff09;&#xff0c;是一种提高数据库并发性能的技术。MVCC的主要目的是在保证数据一致性的同时&#xff0c;提高数据库的并发性能。 它通过为每个读操作创建数…

lower()方法——大写字母转换为小写字母

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 lower()方法用于将字符串中的大写字母转换为小写字母。如果字符串中没有需要被转换的字符&#xff0c;则将原字符串返回&#xff1b;否则将…

Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件

章节内容 上一节完成&#xff1a; HDFS的简介内容HDFS基础原理HDFS读文件流程HDFS写文件流程 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0c;但是没留下…

RK3568平台(USB篇)USB HID设备

一.USB HID设备简介 USB HID设备主要用于和计算机进行交互通信&#xff0c;典型的USB HID类设备包括USB键盘、USB鼠标、USB游戏手柄等等&#xff0c;这些都是日常生活中常见的设备。以USB接口的鼠标为例&#xff0c;打开计算机的“设备管理器”&#xff0c;可以在“鼠标和其他…

Milvus【部署 01】向量数据库Milvus在Linux环境下的在线+离线安装

向量数据库Milvus在Linux环境下的在线离线安装 1.千问简介2.在线安装2.离线安装 1.千问简介 Milvus 是一款专为处理高维向量数据设计的开源云原生数据库&#xff0c;旨在满足海量向量数据的实时召回需求。它由 Zilliz 公司开发并维护&#xff0c;基于Apache许可证2.0版本发布。…

Microsoft SQL Server 2019安装和设置用户密码

1、免费下载两个安装包 SQL2019-SSEI-Dev 地址:https://www.microsoft.com/en-us/sql-server/sql-server-downloads SSMS-Setup-CHS 地址:https://aka.ms/ssmsfullsetup 安装具体不在阐述了&#xff0c;可以参考我这篇文章&#xff1a;SQL Server 2019安装详细教程 2、以W…

llm-universe | 五. 系统评估与优化

系统评估与优化 一.LLM应用评估思路1.人工评估准则一 量化评估准则二 多维评估 2.自动评估方法一. 构造客观题方法二. 计算答案相似度 3.使用大模型评估4.混合评估 二.评估并优化生成部分1. 提升直观回答质量2.标明知识来源&#xff0c;提高可信度3. 构造思维链4.增加一个指令解…

springboot学习,如何用redission实现分布式锁

目录 一、springboot框架介绍二、redission是什么三、什么是分布式锁四、如何用redission实现分布式锁 一、springboot框架介绍 Spring Boot是一个开源的Java框架&#xff0c;由Pivotal团队&#xff08;现为VMware的一部分&#xff09;于2013年推出。它旨在简化Spring应用程序…

详解C语言分支与循环语句

分支语句 if elseswitch 循环语句 whilefordo while goto语句 文章目录 1.什么是语句2.分支语句&#xff08;选择结构&#xff09;2.1 if语句2.1.1 悬空else2.1.3 练习 2.2 switch语句2.2.1 在switch语句中的break2.2.2 default子句 3.循环语句3.1 while循环3.1.1 while语句中…

2024广州智能音箱展|广州蓝牙耳机展

2024广州智能音箱展|广州蓝牙耳机展 时间&#xff1a;2024年11月29日-12月1日 地点&#xff1a;广州琶洲保利世贸博览馆 【展会简介】 中国是全球最大的音频产品制造基地和消费市场&#xff0c;随着国内外互联网巨头纷纷瞄准音频行业并投入巨资布局AI产品矩阵&#xff0c;音…

Static Timing Analysis(STA)概述

文章目录 Preface一、Design Objects二、Timing Paths三、Delay Calculation1. cell delay2. net delay 四、Constraint Checks五、Timing Exceptions1. Setting false paths2. Setting Maximum and Minimum Path Delays3. Setting Multicycle Paths Summary Preface Static t…

Yolov8可视化界面使用说明,含代码

⭐⭐ YOLOv8改进专栏|包含主干、模块、注意力机制、检测头等前沿创新 ​ ⭐⭐ YOLOv8可视化界面如下 使用需要安装opencv-python、torch、numpy及PySide6(python版本>3.9) pip install PySide6 pip install numpy pip install opencv-python 使用说明 运行下方代码&#xf…

C - Popcorn(abs358)

题意&#xff1a;有n个摊子&#xff0c;m个爆米花&#xff0c;想花费最少去的店铺买到所有的口味的爆米花&#xff0c;找到每一列都为‘o’的最少行数。 分析&#xff1a;用dfs寻找最少路径 #include<bits/stdc.h> using namespace std; typedef long long ll; char x;…

那些好用的 Vue3 的工具搭子!!【送源码】

2020 年 9 月 18 日 Vue3 的正式发布已经过去了大约 3 年 9 个月左右&#xff01;&#xff01;&#xff01; 随着 Vue3 版本的逐渐成熟&#xff0c;我们的前端世界也迎来了一系列令人振奋的更新和工具。Vue 生态圈的持续扩大&#xff0c;无疑为前端开发人员带来了前所未有的便…

【自用】CentOS7.6 安装 node-RED 4.0.2 教程(各种坑都摆脱的版本)

步骤总览 1.下载安装 nodejs 2.安装并配置 node-RED 3.重启服务器&#xff0c;验证 node-RED 是否安装 and 配置成功 一、下载安装 nodejs 1.下载 nodejs 18 为什么要下载 nodejs 18 呢&#xff1f; 因为 node-RED 4.0.1 支持的最低 nodejs 版本就是 nodejs 18。 当然了&a…

javaEE——Servlet

1.web开发概述 所谓web开发,指的是从网页中向后端程序发送请求,与后端程序进行交互 2.java后端开发环境搭建 web后端(javaEE)程序需要运行在服务器中的&#xff0c;这样前端才可以访问得到 3.服务器是什么&#xff1f; ①服务器就是一款软件&#xff0c;可以向其发送请求&#…

基于Canvas的Html5多时区动态时钟实战

目录 前言 一、关于Canvas技术 1、Canvas是什么 2、Canvas的属性及渲染特性 二、Canvas动态多时区展示 1、新建html页面 2、创建Canvas对象 3、绘制所有的时钟 总结 前言 出差旅行相信大家一定会住酒店&#xff0c;大家在酒店的前台进行预订的时候&#xff0c;是不是都…

【开发篇】明明配置跨域声明,为什么却仍可以发送HTTP请求

一、问题 在SpringBoot项目中&#xff0c;明确指定仅允许指定网站跨域访问&#xff1a; 为什么开发人员却仍旧可以通过HTTP工具调用接口&#xff1f; 二、为什么 在回答这个问题之前&#xff0c;我们首先要了解一下什么是CORS&#xff01; 1、什么是CORS CORS的全称为跨域资源…