Spring 学习源码的基础 核心原理与核心概念

文章目录

  • 核心原理
    • AnnotationConfigApplicationContext
    • IoC 容器加载流程
    • Spring 中如何创建一个对象
    • Bean 的创建过程 (生命周期)
    • 单例 原型
    • 推断构造方法
    • 依赖注入
    • AOP 动态代理
    • 判断是否需要 AOP 的大致流程
    • CGLib 做 AOP 的大致流程
    • 事务
    • 事务代理对象执行方法的流程
    • 事务注解排至失效的原因
    • 为何下方加了 @Configuration 事务才能生效
  • 核心概念
    • BeanDefinition
    • BeanDefinitionReader
      • AnnotatedBeanDefinitionReader
      • XmlBeanDefinitionReader
      • ClassPathBeanDefinitionScanner
    • BeanFactory
      • DefaultListableBeanFactory
      • ApplicationContext
        • AnnotationConfigApplicationContext
        • ClassPathXmlApplicationContext
        • 国际化 MessageSource


核心原理

AnnotationConfigApplicationContext

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

我们很少按照上面的方式使用 Spring, 而是使用 Spring MVC, 或者 Spring Boot, 但是它们本质上都是基于这种方式的, 都需要在内部去创建一个 ApplicationContext

  • SpringBoot 创建的是 AnnotationConfigApplicationContext
  • SpringMVC 创建的是 XmlWebApplicationContext, 和 ClassPathXmlApplicationContext 类似都是基于 xml 的

AnnotationConfigApplicationContext 是研究学习的主类

IoC 容器加载流程

IoC容器加载流程可以分成两个步骤

  • 准备, 注册一些底层基础架构工具类, 在容器初始化流程中使用, 然后注册配置类, 然后刷新容器
  • 扫描, 将配置的各种 Bean 解析成为 BeanDefinition, 存入 BeanDefinitionMap
  • 遍历 BeanDefinitionMap, 生产单例, 并缓存到单例池 singletonObjects

Spring 中如何创建一个对象

new AnnotationConfigApplicationContext(Config.class) 的过程就是 IoC 容器的加载流程, 扫描生成 BeanDefinition, 遍历生成单例 Bean. 最后人为调用 getBean(beanName) 去缓存中拿到对应的 Bean

Bean 的创建过程 (生命周期)

class -> 反射newInstance -> 原始对象 -> 依赖注入(属性赋值) -> 一堆Aware -> 初始化前(@PostConstruct) -> 初始化(InitailizedBean) -> 初始化后(AOP) -> 代理对象(代理对象.target=原始对象) -> Bean

  • 实例化, 通过反射调用类的某个构造方法创建对象, 如果有多个构造方法, 会进行选择, 叫做推断构造方法
  • 依赖注入(属性赋值), 遍历对象内的字段, 有 @Autowired 的自动赋值
  • Aware 织入, 判断对象是否是(即类是否实现了) BeanNameAware, ApplicationContextAware 等各种 Aware, 是的话就强转调用结构定义的 set 方法
  • @PostConstruct 处理, 判断是否有方法有该注解, 有的话则执行该方法
  • InitializingBean 处理, 判断对象是否是该接口的实例, 是的话则执行接口定义的 afterPropertiesSet 方法
  • 自定义的 init-method 方法
  • 判断是否需要 AOP, 不需要时返回当前对象, 需要时则生成代理对象, 并返回
  • 如果是单例 Bean 则存入单例池

单例 原型

Bean 的作用域分为单例和原型两种

  • 单例: 每次 getBean 拿到的都是同一个对象, 首次创建后就会缓存到单例池
  • 原型: 每次 getBean 都会重新创建一次, 不会放到单例池

懒加载的 Bean 在 IoC 容器加载时不会被创建和缓存, 在使用时才会创建和缓存

推断构造方法

实例化时默认使用无参构造器(写了有参默认就没有无参了, 除非显式定义)

有无参构造器就使用无参构造器, 没无参构造器则判断有几个有参构造器, 只有一个的话就使用这一个有参构造器, 有多个的话因为不能确认使用哪个, 所以报错找不到默认无参构造器

有多个有参构造器的话, 也可以加 @Autowired 来指定使用哪个有参构造器

有参构造器的参数对象哪里来?

  • 先根据类型到容器中找, 如果只有一个则直接使用, 如果有多个则根据名称来过滤, 如果又匹配名称的则直接使用, 如果没有匹配的, 则报错

依赖注入

先按类型到容器中过滤, 匹配的如果只有一个则直接使用, 多个则再按名称匹配, 有匹配到的直接使用, 没有则报错

AOP 动态代理

在创建 Bean 的最后一步, 会判断是否需要做 AOP, 需要则做动态代理

判断是否需要 AOP 的大致流程

  • 找出所有切面 Bean
  • 遍历其中每个方法, 判断是否写了 @Before, @After 等注解
  • 如果写了, 则判断其所对应的 PointCut 和当前创建的 Bean 是否匹配
  • 如果匹配, 则说明当前 Bean 需要做 AOP

CGLib 做 AOP 的大致流程

  • 生成继承原类的代理类, 代理类持有原类对象 target. 注意, 原类对象是经过 Bean 创建流程的, 包括依赖注入, 初始化等流程
  • 代理类中覆盖原类中的方法, 最终会调用到 target 的对应方法, 但是会在前后把切面逻辑都加上, 大致如下
  • 最后创建 Bean 返回的是持有原始对象的代理对象
public class UserService {
	@Autowired
	private OrderService orderService;
	public void test() {
		sout;
	}
}
class UserServiceProxy extend UserService {
	UserService target;
	public void test() {
		// @Before 的逻辑
		target.test();
		// @After 的逻辑
	}
}

代理类继承自原始类, 所以原始类的字段在代理类中也有, 但是 Spring 并不会为代理类做依赖注入, 因为没有必要

代理对象仅仅用于强化原始对象的某方法, 如果在切面逻辑中需要用到原始对象的依赖注入的字段, 也可以通过 JoinPoint.getTarget() 拿到原始对象来操作, 而原始对象中各字段已经做过依赖注入了

事务

某方法添加了 @Transactional 注解后, 会在 AOP 阶段给本类生成代理类和代理对象

事务代理对象执行方法的流程

  • 判断当前方法上有没有 @Transactional 注解
  • 有的话由事务管理器创建一个数据库连接 (此连接不是来自连接池?)
  • 设置连接的 autoCommit 为 false (无事务注解时, 连接是从连接池获取, 每执行一条 SQL 自动提交一次)
  • 执行方法, 执行方法中的 SQL
  • 调用连接的提交或回滚方法

事务注解排至失效的原因

事务是否会失效, 就看执行 @Transactional 注解方法的是哪个对象

  • 代理对象: 不会失效
  • 原始对象: 失效, 因为执行的就是普通方法, 没有代理对象做的强化了

最常见的例子, 类中有两个事务方法 a 和 b, 而 a 中会调用 b, 单独执行 a 和 b 事务都不会失效, 但是在 a 中执行 b 时, b 的事务注解上的配置会失效

因为执行 a 的流程是这样的, 拿到类的代理对象, 执行其 a, 先走切面逻辑, 创建连接, 设置不自动提交, 然后才执行 target.a 即原始对象的 a 方法, 此时的主体是原始对象而非代理对象. 执行到 b 方法时, 本质是 this.b, 主体还是原始对象, 并没有切面逻辑, 所以在 a 里面的 b 方法的事务注解配置都会失效

当然还有很多其他原因, 需要具体分析

其他的 AOP 失效很多也是一样的原因, 都是自调用导致的

有解决办法, 就是自引用, 类中依赖注入自身 self, 此时的 self 是代理对象, 在 a 中调用 b 的时候, 用 self.b, 这样主体是代理对象, 有切面强化逻辑, b 的事务配置就会生效了

为何下方加了 @Configuration 事务才能生效

@Configuration
public class Config {
	@Bean
	public TransactionManager transationManager() {
		return new DataSourceTransactionManager(dataSource());
	}
	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dataSource())
	}
	@Bean
	public DataSource dataSource() {
		return new DataSource();
	}
}
  • 不加时, 调用两次 dataSource() 生成两个不同的数据源, 最终事务管理器和模板使用了不同的数据源
  • 加时, 会有特殊的处理, dataSource() 会被认为是一个 Bean, 传入两者的是同一个对象

在 JdbcTemplate 中获取连接时, 会检查当前是否为事务环境, 是的话会从 TransactionSynchronizationManager.getResource(dataSource); 中获取线程绑定的连接, 即事务管理器创建的那个连接, 需要使用同一个数据源对象才能拿到同一个连接, 这样事务管理器的提交和回滚操作才会对 JdbcTemplate 生效

核心概念

Spring 源码里有很多抽象和工具, 需要提前有一定了解, 读源码时能轻松一些

BeanDefinition

BeanDefinition 用来记录 Bean 配置的各种信息

  • class,表示Bean类型
  • scope,表示Bean作用域,单例或原型等
  • lazyInit:表示Bean是否是懒加载
  • initMethodName:表示Bean初始化时要执行的方法
  • destroyMethodName:表示Bean销毁时要执行的方法
  • 还有很多…

定义 Bean 的方式有申明式和编程式两种, 通过各种方式定义的 Bean 最终都会被解析为 BeanDefinition 并缓存起来

  • 申明式:
    • < bean/>
    • @Bean
    • @Component(@Service,@Controller)
  • 编程式
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
    // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.setBeanClass(User.class);
    context.registerBeanDefinition("user", beanDefinition);
    
    System.out.println(context.getBean("user"));
    

BeanDefinitionReader

用于根据某些规则将资源解析成为 BeanDefinition

AnnotatedBeanDefinitionReader

可以将某个类解析成为 BeanDefinition, 包括类上的注解(@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description)

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
reader.register(User.class);

System.out.println(context.getBean("user"));

XmlBeanDefinitionReader

可以解析 < bean/> 标签配置的 Bean

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
int i = reader.loadBeanDefinitions("spring.xml");

System.out.println(context.getBean("user"));

ClassPathBeanDefinitionScanner

扫描器, 但是它的作用和 BeanDefinitionReader 类似, 它可以进行扫描, 扫描某个包路径, 对扫描到的类进行解析

如果扫描到的类上存在 @Component 注解, 那么就会把这个类解析为一个 BeanDefinition

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.coder");

System.out.println(context.getBean("userService"));

BeanFactory

Spring 容器的根接口, Bean 工厂, 负责创建 Bean 和获取 Bean, 提供各种 getBean() 方法的定义

DefaultListableBeanFactory

BeanFactory 有一个最核心的实现类 DefaultListableBeanFactory, 可以直接当作 BeanFactory 来使用, 可以替代 ApplicationContext 来使用, 就是功能会少一点而已

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);

beanFactory.registerBeanDefinition("user", beanDefinition);

System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory

DefaultListableBeanFactory 的架构体系如上, 有很多接口(能力)和类

  • AliasRegistry: 支持别名功能, 定义了 alias 的注册/获取/判断/移除等功能, 在这里支持一个 BeanDefinition / Bean 有多个名称的功能
  • SimpleAliasRegistry, 维护着 Map<String, String> aliasMap, 在这里是 alias 与 beanName 的多对一关系, 便于从别名找到原名(别名也能起别名), 当然也可以从原名找到所有别名
  • BeanDefinitionRegistry: 定义了 BeanDefinition 的注册/获取/存在/移除等功能
  • SingletonBeanRegistry: 定义了单例 Bean 的注册/存在/获取/获取数量/获取名称等功能
  • BeanFactory: 定义了 Bean 的获取/存在/获取别名/判断作用域等功能
  • ListableBeanFactory: 扩展了 BeanFactory, 提供了方法用于枚举和检索容器中的 bean 实例, 可以方便地获取所有 bean 的名称、按类型获取 bean、按条件检索 bean 等操作
  • HierarchicalBeanFactory: 扩展了 BeanFactory, 提供了层次化的容器结构和继承机制, 每个子容器可以独立管理自己的 bean 定义和实例。子容器可以继承父容器中定义的 bean,并可以在子容器中覆盖或扩展父容器中的 bean 定义。可以实现更好的模块化和组织化,并灵活管理和定制 bean 的定义和作用域
  • AutowireCapableBeanFactory: 扩展了 BeanFactory, 提供了自动装配 bean 的能力, 可以实现依赖注入、自动装配和解耦等功能
  • ConfigurableBeanFactory, 除了 BeanFactory Bean 之外,还提供用于配置 BeanFactory 的工具. 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  • ConfigurableListableBeanFactory: 除了 ConfigurableBeanFactory 之外, 它还提供了分析和修改 Bean 定义以及预实例化单例的工具
  • DefaultSingletonBeanRegistry: 主要用于管理和维护单例 bean 的注册和获取, singletonObjects 在这里
  • FactoryBeanRegistrySupport: 主要用于支持 FactoryBean 的注册和获取, factoryBeanObjectCache 在这里
  • AbstractBeanFactory: 功能已经很全面了, 但是不能自动装配和获取 beanNames, beanPostProcessors 在这里
  • AbstractAutowireCapableBeanFactory: 拥有了自动装配的功能
  • DefaultListableBeanFactory: 是 Spring 容器的一个关键组件,负责管理 BeanDefinition 的注册、合并和查找,以及 Bean 的创建、装配和销毁。它提供了丰富的功能和灵活的配置选项,是 Spring 应用程序中常用的 BeanFactory 实现之一, beanDefinitionMap 在这里

ApplicationContext

BeanFactory 有一个最核心的子接口 ApplicationContext, 其定义如下

public interface ApplicationContext 
extends EnvironmentCapable, 
ListableBeanFactory, 
HierarchicalBeanFactory, 
MessageSource, 
ApplicationEventPublisher, 
ResourcePatternResolver

在这里插入图片描述

  • HierarchicalBeanFactory:拥有获取父BeanFactory的功能
  • ListableBeanFactory:拥有获取beanNames的功能
  • ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
  • EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
  • ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
  • MessageSource:拥有国际化功能

ApplicationContext 的定位是 Spring 的应用上下文, 负责管理和组织应用程序的各个部分. 从代码层面来说, ApplicationContext 是一个 BeanFactory, 从架构层面来说, ApplicationContext 是比 BeanFactory 更加高级的存在, 它统御 BeanFactory, EnvironmentCapable, MessageSource 等这些组件完成相应的功能, BeanFactory 只是它的一个零件而已

照着这个思路来看, GenericApplicationContext 不继承 DefaultListableBeanFactory 而是将之作为一个属性, 从 BeanFactory 继承来的功能全部委托其持有的 DefaultListableBeanFactory 来执行, 就是非常合理的事情了

ApplicationContext 接口继承了 ListableBeanFactory 和 HierarchicalBeanFactory, 但它的定位是一个高位 BeanFactory, 只是聚焦于 BeanFactory 一定程度的基础功能即可, 并不需要中低层更强大的更加细节的全部功能

ApplicationContext 有两个重要的实现类

  • AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext

AnnotationConfigApplicationContext

在这里插入图片描述

  • Lifecycle: 定义启动/停止生命周期控制方法的通用接口
  • ConfigurableApplicationContext: 增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
  • AbstractApplicationContext: 实现通用上下文功能, 大名鼎鼎的 refresh 方法就在这里了
  • GenericApplicationContext: 通用的应用上下文具体实现类
  • AnnotationConfigRegistry: 用于注释配置应用程序上下文, 可以单独注册某个类为 BeanDefinition(可以处理该类上的 @Configuration @Bean 注解)
  • AnnotationConfigApplicationContext: 是一种方便且强大的应用上下文实现,适用于注解驱动的开发方式。它通过扫描和处理注解,实现了自动化的 Bean 注册和装配,减少了繁琐的 XML 配置

ClassPathXmlApplicationContext

在这里插入图片描述
同样继承了 AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext 而言,功能没有AnnotationConfigApplicationContext 强大,比如不能注册 BeanDefinition

国际化 MessageSource

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

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

相关文章

使用yapi生成漂亮接口文档

YApi-教程 1. 进入yapi 的菜单 2. 从微服务中导出swagger的json 从浏览器页面访问http://localhost:端口/服务/swagger-ui.html&#xff0c;然后打开浏览器的控制台&#xff0c;查看network&#xff0c;刷新下页面&#xff0c;找到XHR中的api-docs&#xff0c;然后查看res…

基于Java+SpringBoot+Vue前后端分离公交线路查询系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

stm32读写片内flash项目总结(多字节读写tongxindu)

1.flash操作驱动程序 a头文件 #ifndef FLASH_H #define FLASH_H #include “stm32f4xx.h” #define BOARD_NUM_ADDR 0x0800C000 #define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址 #define FLASH_WAITETIME 50000 //FLASH等待超时时间 //FLASH 扇区的起始地址…

openGauss学习笔记-51 openGauss 高级特性-列存储

文章目录 openGauss学习笔记-51 openGauss 高级特性-列存储51.1 语法格式51.2 参数说明51.3 示例 openGauss学习笔记-51 openGauss 高级特性-列存储 openGauss支持行列混合存储。行存储是指将表按行存储到硬盘分区上&#xff0c;列存储是指将表按列存储到硬盘分区上。 行、列…

el-backtop返回顶部的使用

2023.8.26今天我学习了如何使用el-backtop组件进行返回页面顶部的效果&#xff0c;效果如&#xff1a; <el-backtop class"el-backtop"style"right: 20px; bottom: 150px;"><i class"el-icon-caret-top"></i></el-backtop&…

Markdown初级使用指南

前言 大家好&#xff0c;我是艾老虎尤&#xff0c;我在一篇官方的文章中&#xff0c;我了解到了markdown&#xff0c;原本我写博客一直是使用的富文本编译器&#xff0c;之前我也有同学叫我使用MD&#xff0c;但是我嫌它复杂&#xff0c;就比如说一个标题&#xff0c;我在富文…

STM32 Cubemx配置串口收发

文章目录 前言注意事项Cubemx配置printf重定向修改工程属性修改源码 测试函数 前言 最近学到了串口收发&#xff0c;简单记录一下注意事项。 注意事项 Cubemx配置 以使用USART1为例。 USART1需配置成异步工作模式Asynchronous。 并且需要使能NVIC。 printf重定向 我偏向…

AURIX TriCore内核架构学习笔记

名词缩写 ISA - Instruction Set Architecture&#xff0c;指令集架构PC - Program Counter, holds the address of the instruction that is currently runningGPRs - 32 General Purpose RegistersPSW - Program Status WordPCXI - Previous Context InformationCSA - Conte…

改进YOLO系列:10.添加NAMAttention注意力机制

添加NAMAttention注意力机制 1. NAMAttention注意力机制论文2. NAMAttention注意力机制原理3. NAMAttention注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. NAMAttention注意力机制论文 论文题目:NAM: Normalization-based Attention Module 论文…

Python——列表(list)推导式

本文基于python3。 目录 1、Python推导式2、列表(list)推导式2.1、定义2.2、实际操作2.2.1、一个表达式&#xff0c;后面为一个 for 子句2.2.2、一个表达式&#xff0c;后面为一个 for 子句&#xff0c;然后&#xff0c;跟着if 子句。2.2.3、一个表达式&#xff0c;后面为一个…

matlab使用教程(21)—求函数最值

1. 求函数最优值 1.1求一元函数的最小值 如果给定了一个一元数学函数&#xff0c;可以使用 fminbnd 函数求该函数在给定区间中的局部最小值。例如&#xff0c;请考虑 MATLAB 提供的 humps.m 函数。下图显示了 humps 的图。 x -1:.01:2; y humps(x); plot(x,y) xlabel(x)…

[管理与领导-50]:IT基层管理者 - 8项核心技能 - 5 - 沟通是润滑剂

目录 前言&#xff1a; 一、什么是沟通 1.1 定义 1.2 沟通模型 1.3 沟通的六层次模型 1.4 为什么需要沟通 二、沟通的五维度 三、沟通的原则 3.1 以终为始 3.2 双赢思维&#xff1a;人们只会做对自己有利的事 3.3 牵善的思维 四、沟通的过程 五、沟通技巧 六、深…

移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】

目录 组件库 移动端 vue vant PC端 react antd vue element 调试&#xff1a;vconsole vs dev tools中的控制台&#xff08;Console&#xff09; ​​​​​​​vconsole&#xff1a;在真机上调试 构建工具 webpack 原理 Babel&#xff1a;JS编译器&#xff08;…

sql server 快速安装

目录标题 一、下载二、直接选择基本安装二、下载ssms&#xff08;数据库图形化操作页面&#xff09;三、开启sa账号认证&#xff08;一&#xff09;第一步&#xff1a;更改身份验证模式&#xff08;二&#xff09;第二步&#xff1a;启用 sa 登录四、开启tcp/ip 一、下载 下载…

Visual Studio 2022 右键单击项目没有出现View | View Class Diagram(Visual Studio 无法使用类设计器)

文章目录 问题描述原因.NET Core项目.NET Framework项目 其他VS2022相关文章 问题描述 当我们在Solution Explorer窗口右键单击项目时&#xff0c;快捷菜单中没有出现“查看”&#xff0c;或者出现了“查看”&#xff0c;但是“查看”里没有View Class Diagram。 原因 首先…

大彩串口屏使用记录

写在最前面 屏幕型号 DC10600M070 IDE VisualTFT&#xff08;官方&#xff09; VSCode&#xff08;lua编程&#xff09; 用之前看一下官方那个1小时的视频教程就大概懂控件怎么用了&#xff0c;用官方的软件VisualTFT很简单 本文只是简单记录遇到的一些坑 lua编辑器 VisualTF…

设计模式之抽象工厂

文章目录 一、介绍二、基本组件三、演示案例1. 定义抽象工厂2. 定义抽象产品3. 定义具体工厂4. 定义具体产品5. 代码演示6. 代码改造 四、总结 一、介绍 抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。 复杂到哪里了…

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比)

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09; 目录 时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09;预测效果基本介绍模型介绍程序设计参…

【javaweb】学习日记Day3 - Ajax 前后端分离开发 入门

目录 一、Ajax 1、简介 2、Axios &#xff08;没懂 暂留&#xff09; &#xff08;1&#xff09;请求方式别名 &#xff08;2&#xff09;发送get请求 &#xff08;3&#xff09;发送post请求 &#xff08;4&#xff09;案例 二、前端工程化 1、Vue项目-目录结构 2、…

java 里面 long 转换int内存分析

了解补码知识点 要将补码转换为十进制&#xff0c;需要确定补码的符号位。如果补码的符号位为1&#xff0c;则表示为负数&#xff0c;否则表示为正数。 假设我们有一个补码为1 0110 1011 1100 1101 1000 0011 1101 1100 0010 1101 1111 1101 1100 0001 1100 0011 0100 首先&a…