『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段
『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段
- 基于 2.2.9.RELEASE
- 问题:当方法进行了注释标记之后,springboot 又是怎么注入到容器中并创建类呢?
- 首先创建测试主程序
package com.lagou;@SpringBootApplication//标注在类上说明这个类是`SpringBoot`的主配置类
public class SpringBootMytestApplication{public static void main(String[] args) {SpringApplication.run(SpringBootMytestApplication.class, args);}
}
- 创建测试 Controller
package com.lagou.controller;@RestController
public class TestController {@RequestMapping("/test")public String test(){System.out.println("源码环境构建成功...");return "源码环境构建成功";}
}
准备阶段
- 当准备完成应用上下文环境,以及应用上下文以后,需要为应用上下文做个准备阶段,简单来说其实就是要配置应用上下文,把需要的类装配上
public class SpringApplication {...public ConfigurableApplicationContext run(String... args) {...try {// 将运行时参数封装ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 构造应用上下文环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 处理需要忽略的 BeanconfigureIgnoreBeanInfo(environment);// 打印 bannerBanner printedBanner = printBanner(environment);// 刷新应用上下文前的准备阶段context = createApplicationContext();// 实例化 SpringBootExceptionReporter.class,用来支持报告关于启动的错误exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// 1. 刷新应用上下文前的准备阶段prepareContext(context, environment, listeners, applicationArguments, printedBanner);...}catch (Throwable ex) {...}...}
}
- 在对应用上下文进行处理时,主要执行了下面几步的装配
- 把上下文环境设置到应用上下文中
- 执行容器后置处理
- 把应用上下文交给 SpringApplication 初始化收集的 org.springframework.context.ApplicationContextInitializer 所有实现类进行初始化工作
- 利用 org.springframework.boot.context.event.EventPublishingRunListener 向 org.springframework.context.ApplicationListener 发布容器准备好事件
public class SpringApplication {...// 完成属性设置 bean对象创建private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 1. 设置容器环境context.setEnvironment(environment);// 2. 执行容器后置处理postProcessApplicationContext(context);// 3. 执行一些初始化器applyInitializers(context); // 4. 向各个监听器发送容器已经准备好的事件listeners.contextPrepared(context);...}
}
- 执行容器后置处理:其实只是往 BeanFactory 添加了基础的转换器
public class SpringApplication {private BeanNameGenerator beanNameGenerator;private ResourceLoader resourceLoader;private boolean addConversionService = true;...protected void postProcessApplicationContext(ConfigurableApplicationContext context) {if (this.beanNameGenerator != null) {context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);}if (this.resourceLoader != null) {if (context instanceof GenericApplicationContext) {((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);}if (context instanceof DefaultResourceLoader) {((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());}}if (this.addConversionService) { // 1. 设置了转换器,例如平时能把整数字符串转换为整形,设置转换器context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());}}
}
- 执行一些初始化器:就是遍历 org.springframework.context.ApplicationContextInitializer 执行 initialize() 方法
public class SpringApplication {...protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);}}
}
- 向各个监听器发送容器已经准备好的事件:就是 org.springframework.boot.context.event.EventPublishingRunListener 向 org.springframework.context.ApplicationListener 发布容器准备好事件
public class SpringApplication {...// 1. 当 ApplicationContext 构建完成时,该方法被调用void contextPrepared(ConfigurableApplicationContext context) {for (SpringApplicationRunListener listener : this.listeners) {listener.contextPrepared(context);}}
}
- 发布完监听之后,从上下文中获取 IOC 工厂,并设置允许 bean 定义被覆盖参数
public class SpringApplication {...// 完成属性设置 bean 对象创建private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 设置容器环境context.setEnvironment(environment);// 执行容器后置处理postProcessApplicationContext(context);// 执行一些初始化器applyInitializers(context); // 向各个监听器发送容器已经准备好的事件listeners.contextPrepared(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 1. 获取 IOC 容器ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 将 main() 函数中的 args 参数封装成单例 Bean,注册进容器beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {// 将 printedBanner 也封装成单例,注册进容器beanFactory.registerSingleton("springBootBanner", printedBanner);}// 2. 设置允许 bean 定义被覆盖参数if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}...}
}
- 然后加载启动类,并将启动类注入到容器当中,然后发布容器已加载事件
public class SpringApplication {...// 完成属性设置 bean 对象创建private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 设置容器环境context.setEnvironment(environment);// 执行容器后置处理postProcessApplicationContext(context);// 执行一些初始化器applyInitializers(context); // 向各个监听器发送容器已经准备好的事件listeners.contextPrepared(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 获取 IOC 容器ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 将 main() 函数中的 args 参数封装成单例 Bean,注册进容器beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {// 将 printedBanner 也封装成单例,注册进容器beanFactory.registerSingleton("springBootBanner", printedBanner);}// 设置允许 bean 定义被覆盖参数if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) { // 是否需要进行懒加载,这里不是context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 1. 加载源,这里拿到的是主类,com.lagou.SpringBootMytestApplicationSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");// 2. 加载我们的启动类,将启动类注入容器 重点关注load(context, sources.toArray(new Object[0]));// 取出第一个元素,就是主类,要先实例化主类,灌入容器中// 3. 发布容器已加载事件listeners.contextLoaded(context);}
}
- 其中将启动类注入到容器当中是比较关键的一步,首先先把 ApplicationContext 转换成 BeanDefinitionRegistry,然后创建 bean 定义加载器
public class SpringApplication {...protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}// 2. 创建 BeanDefinitionLoaderBeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);...}private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {// 1. 将 ApplicationContext 转换成 BeanDefinitionRegistryif (context instanceof BeanDefinitionRegistry) {return (BeanDefinitionRegistry) context;}if (context instanceof AbstractApplicationContext) {return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();}throw new IllegalStateException("Could not locate BeanDefinitionRegistry");}
}
- 创建 BeanDefinitionLoader 主要是把 BeanDefinitionRegistry 以及主类的 sources 进行赋值初始化
public class SpringApplication {private final Object[] sources;private final AnnotatedBeanDefinitionReader annotatedReader;private final XmlBeanDefinitionReader xmlReader;private BeanDefinitionReader groovyReader;private final ClassPathBeanDefinitionScanner scanner;private ResourceLoader resourceLoader;...protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {// 1. 创建 bean 定义加载器return new BeanDefinitionLoader(registry, sources);}BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {// 其中,sources 就是主类 com.lagou.SpringBootMytestApplicationAssert.notNull(registry, "Registry must not be null");Assert.notEmpty(sources, "Sources must not be empty");this.sources = sources;// 2. 注解形式的 Bean 定义读取器 比如:@Configuration @Bean @Component @Controller @Service等等this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);// 3. XML 形式的 Bean 定义读取器this.xmlReader = new XmlBeanDefinitionReader(registry);if (isGroovyPresent()) {this.groovyReader = new GroovyBeanDefinitionReader(registry);}// 4. 类路径扫描器this.scanner = new ClassPathBeanDefinitionScanner(registry);// 5. 扫描器添加排除过滤器this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));}
}
- 创建 BeanDefinitionLoader 成功后,就可以开始执行 load(),这里主要是先把主类注册到 IOC 容器中去
public class SpringApplication {private BeanNameGenerator beanNameGenerator;...protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}// 创建 BeanDefinitionLoaderBeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);if (this.beanNameGenerator != null) {loader.setBeanNameGenerator(this.beanNameGenerator);}if (this.resourceLoader != null) {loader.setResourceLoader(this.resourceLoader);}if (this.environment != null) {loader.setEnvironment(this.environment);}// 1. 执行 load()loader.load();}
}
- 其中 load() 通过 AnnotatedBeanDefinitionReader 将主类 source 注册进 beanDefinitionMap 中
class BeanDefinitionLoader {private final AnnotatedBeanDefinitionReader annotatedReader;...int load() {int count = 0;for (Object source : this.sources) {count += load(source);}return count;}// 根据加载不同类型调用不同的方法private int load(Object source) {Assert.notNull(source, "Source must not be null");// 1. 从 Class 加载if (source instanceof Class<?>) {return load((Class<?>) source);}...}private int load(Class<?> source) {// source 就是 class com.lagou.SpringBootMytestApplicationif (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {// Any GroovyLoaders added in beans{} DSL can contribute beans hereGroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);load(loader);}if (isComponent(source)) { // 判断方法有没有标记 Component 注解// 1. 将启动类的 BeanDefinition 注册进 beanDefinitionMapthis.annotatedReader.register(source);return 1;}return 0;}
}
- 调用 register() 方法时,真正会传到 doRegisterBean() 进行执行。首先会把主类转换成 AnnotatedGenericBeanDefinition,然后获取主类的名称,把名称和 AnnotatedGenericBeanDefinition 封装成 BeanDefinitionHolder 后,注册到上下文中
public class AnnotatedBeanDefinitionReader {...public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}}public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);}private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {// 1. 把主类转换成 AnnotatedGenericBeanDefinition,其中 beanClass 为 com.lagou.SpringBootMytestApplicationAnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(supplier);ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());// 2. 获取类名 springBootMytestApplicationString beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}if (customizers != null) {for (BeanDefinitionCustomizer customizer : customizers) {customizer.customize(abd);}}// 3. 封装成 BeanDefinitionHolder BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);// 4. 注册到容器中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}
}
- 注册到容器中,简单而言就是调用 BeanDefinitionRegistry 把 BeanDefinitionHolder 的 name 和 AnnotatedGenericBeanDefinition 装配进去
public abstract class BeanDefinitionReaderUtils {...public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {// 1. 获取名称 springBootMytestApplicationString beanName = definitionHolder.getBeanName();// 2. 注册到 IOC 容器中registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());String[] aliases = definitionHolder.getAliases();if (aliases != null) {String[] var4 = aliases;int var5 = aliases.length;for(int var6 = 0; var6 < var5; ++var6) {String alias = var4[var6];registry.registerAlias(beanName, alias);}}}
}
- 最后会把 name 和 AnnotatedGenericBeanDefinition 存入到 beanDefinitionMap 中
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {...public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");// 1. 先校验 beanDefinition 是否合法if (beanDefinition instanceof AbstractBeanDefinition) {try {((AbstractBeanDefinition)beanDefinition).validate();} catch (BeanDefinitionValidationException var8) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);}}BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {if (!this.isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}if (existingDefinition.getRole() < beanDefinition.getRole()) {if (this.logger.isInfoEnabled()) {this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");}} else if (!beanDefinition.equals(existingDefinition)) {if (this.logger.isDebugEnabled()) {this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");}} else if (this.logger.isTraceEnabled()) {this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");}this.beanDefinitionMap.put(beanName, beanDefinition);} else {if (this.hasBeanCreationStarted()) {synchronized(this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;this.removeManualSingletonName(beanName);}} else {// 2. 再把 beanDefinition 放到 beanDefinitionMap 中this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}if (existingDefinition == null && !this.containsSingleton(beanName)) {if (this.isConfigurationFrozen()) {this.clearByTypeCache();}} else {this.resetBeanDefinition(beanName);}}
}
- 总结

相关文章:
『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段
『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段 基于 2.2.9.RELEASE问题:当方法进行了注释标记之后,springboot 又是怎么注入到容器中并创建类呢? 首先创建测试主程序 package …...
WordPress Page Builder KingComposer 2.9.6 Open Redirection
WordPress Page Builder KingComposer 2.9.6 Open Redirection WordPress 插件 KingComposer 版本2.9.6 以及以前版本受到开放重定向漏洞的影响。该漏洞在packetstorm网站披露于2023年7月24日,除了该漏洞,该版本的插件还存在XSS攻击的漏洞风险 图1.来自…...
第五章:中国革命新道路
革命道路的艰难探索 1.国民党在全国统治的建立 南京国民政府的成立国民党政权的性质 2.土地革命战争的兴起 1. 大革命失败后的艰难环境 2. 开启武装反抗国民党统治的斗争: 南昌起义:共产党独立领导的革命战争,创建人民军队和武装夺取政权…...
PMP-沟通管理的重要性
一、什么是项目沟通管理 项目沟通管理包括通过开发工件,以及执行用于有效交换信息的各种活动,来确保项目及其相关方的信息需求得以满足的各个过程。项目沟通管理由两个部分组成:第一部分是制定策略,确保沟通对相关方行之有效&…...
【Sentinel】降级源码:插槽DegradeSlot与断路器的实现
文章目录 1、实现原理2、DegradeSlot类3、CircuitBreaker4、触发断路器 1、实现原理 Sentinel的降级是基于状态机来实现的: 2、DegradeSlot类 熔断降级的逻辑在DegradeSlot类中实现,核心API: Override public void entry(Context context,…...
【Apollo】开启Apollo之旅:让自动驾驶如此简单
前言 Apollo 是百度公司推出的自动驾驶平台。它是一个综合性的自动驾驶解决方案,提供了包括感知、决策、规划和控制等核心功能,以及地图、定位、仿真、数据管理等配套工具。 文章目录 前言Apollo 的发展历程Apollo 8.0新特性软件包管理感知框架工具链小…...
maven搭建spring项目
前提 安装jdk 安装maven 安装eclipse 创建maven项目 搭建spring项目 pom.xml <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.4.RELEASE</version> </dependency&…...
Java“牵手”阿里巴巴商品详情数据,阿里巴巴商品详情API接口,阿里巴巴国际站API接口申请指南
阿里巴巴平台商品详情接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取阿里巴巴商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口…...
MYSQL调优之思路----sql语句和索引调优
MySQL数据库性能优化包括综合多方面因素,应根据实际的业务情况制定科学、合理的调优方案进行测试调优 文章目录 MySQL性能优化1 优化介绍1.2 优化要考虑的问题2.1 优化可能带来的问题2.2 优化的需求2.3 优化由谁参与2.4 优化的方向2.5 优化的维度 1.2数据库使用优化…...
论文阅读_变分自编码器_VAE
英文名称: Auto-Encoding Variational Bayes 中文名称: 自编码变分贝叶斯 论文地址: http://arxiv.org/abs/1312.6114 时间: 2013 作者: Diederik P. Kingma, 阿姆斯特丹大学 引用量: 24840 1 读后感 VAE 变分自编码(Variational Autoencoder)是一种生…...
springboot整合elasticsearch使用案例
引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency> 添加注入 import org.apache.http.HttpHost; import org.elasticsearch.client.Res…...
Unity制作下雨中的地面效果
Unity引擎制作下雨效果 大家好,我是阿赵。 之前介绍了Unity引擎里面通过UV偏移做序列帧动画的做法,这里再介绍一个进阶的用法,模拟地面下雨的雨点效果。 一、原理 最基本的原理,还是基于这个序列帧动画的做法。不过这里做一点…...
windows从0搭建python3开发环境与开发工具
文章目录 一、python3下载安装1、下载2、安装3、测试 二、安装VS Code1、安装2、安装python插件3、测试 三、pip命令的使用1、基本命令2、修改pip下载源 一、python3下载安装 1、下载 打开 WEB 浏览器访问 https://www.python.org/downloads/windows/ ,一般就下载…...
centos中得一些命令 记录
redis命令 链接redis数据库的命令 redis-cli如果 Redis 服务器在不同的主机或端口上运行,你需要提供相应的主机和端口信息。例如: redis-cli -h <hostname> -p <port>连接成功后,你将看到一个类似于以下的提示符,表…...
Python实现Word、Excel、PPT批量转为PDF
今天看见了一个有意思的脚本Python批量实现Word、EXCLE、PPT转PDF文件。 因为我平时word用的比较的多,所以深有体会,具体怎么实现的我们就不讨论了,因为这个去学了也没什么提升,不然也不会当作脚本了。这里我将其放入了pyzjr库中…...
LLM大模型推理加速 vLLM
参考: https://github.com/vllm-project/vllm https://zhuanlan.zhihu.com/p/645732302 https://vllm.readthedocs.io/en/latest/getting_started/quickstart.html ##文档 加速原理: PagedAttention,主要是利用kv缓存 使用: #…...
Python|小游戏之猫捉老鼠!!!
最近闲(mang)来(dao)无(fei)事(qi),喜欢研究一些小游戏,本篇文章我主要介绍使用 turtle 写的一个很简单的猫捉老鼠的小游戏,主要是通过鼠标控制老鼠(Tom)的移动,躲避通过电脑控制的猫(Jerry)的追捕。 游戏主体思考逻辑࿱…...
万里路,咫尺间:汽车与芯片的智能之遇
目前阶段,汽车产业有两个最闪耀的关键词,就是智能与低碳。 在践行双碳目标与产业智能化的大背景下,汽车已经成为了能源技术、交通技术、先进制造以及通信、数字化、智能化技术的融合体。汽车的产品形态与产业生态都在发生着前所未有的巨大变革…...
Ubuntu22.04.1上 mosquitto安装及mosquitto-auth-plug 认证插件配置
Ubuntu22.04.1上 mosquitto安装及mosquitto-auth-plug 认证插件配置 1、先上效果,可以根据mysql中mosquitto数据库的不同users角色登陆mosquitto: SELECT * FROM mosquitto.users; id,username,pw,super 1,jjolie,PBKDF2$sha256$901$yZnELWKK4NnaNNJl…...
CCKS2023:基于企业数仓和大语言模型构建面向场景的智能应用
8月24日-27日,第十七届全国知识图谱与语义计算大会(CCKS 2023)在沈阳召开。大会以“知识图谱赋能通用AI”为主题,探讨知识图谱对通用AI技术的支撑能力,探索知识图谱在跨平台、跨领域等AI任务中的作用和应用途径。 作为…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
