Java技术整理(5)—— Spring篇
Spring是一个全面的全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。
1、Spring的核心组件
(1)数据层: JDBC、ORM、OXM、JMS、Transations
(2)Web层: Web、Servlet、Portlet、Struts
(3)中间层: AOP、Aspects、Instrumentation
(4)核心容器: Beans、Core、Context、Expression Language
(5)测试层: Test
2、Spring IOC 原理
(1)概念: Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语言的反射功能实例化 Bean并建立Bean之间的依赖关系。Spring的IOC容器在完成这些底层工作的基础上,还提供 了 Bean实例缓存、生命周期管理、Bean实例代理、事件发布、资源装载等高级服务。
(2)Spring容器高层视图
- Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表
- 根据这张注册表实例化Bean,并将Bean实例存入Bean缓存池
- 应用程序读取Bean缓存池中的Bean实例
(3)IOC容器实现
IOC容器依赖于BeanFactory,是Spring框架的基础程序,所以开发者操作的是ApplicationContext而非底层的BeanFactory。
Bean注册表
首先,Spring配置文件中的每一个节点元素在Spring容器中都通过一个 BeanDefinition 对象表示,它表述了 Bean 的配置信息,而BeanDefinitionRegistry 接口提供了向容器手动注册 BeanDefinition 对象的方法。
获取Bean实例对象
BeanFactory 提供的最主要方法就是getBean(String beanName)方法,调用该方法能从容器中返回一个特定名称的Bean。
访问容器中关于Bean的基本信息——ListableBeanFactory
BeanFactory 的子类 ListableBeanFactory,提供了访问容器内关于Bean 的基本信息,如Bean的个数,获取某一类型Bean的配置名、查看容器中是否包含某一Bean等方法。
父子级容器——HierarchicalBeanFactory
父子级联IOC容器实现的接口是HierarchicalBeanFactory,子容器可以通过接口方法访问父容器,由此建立的IOC级联容器体系中,子容器可以访问父容器,而父容器无法访问子容器。
Spring利用父子级联容器实现了很多功能,例如 SpringMVC中,View层的Bean位于一个子容器中,而Service层和Dao层的Bean位于父容器中,这样View层的Bean就可以引用Service层和Dao层的Bean了
拓展接口 —— ConfigurableBeanFactory
这是一个BeanFactory子类系列十分重要的接口,它增强了IOC的可定制性,它定义了设置类加载器、属性编辑器、容器初始化后置处理器等方法
自动装配——AutowireCapableBeanFactory
这个接口定义了容器中的Bean按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。
注册单例Bean——SingletonBeanRegistry
这个接口定义了允许在运行期间向容器注册单例Bean的方法。
对于单例Bean对象来说,BeanFactory会缓存Bean实例,所以第二次调用getBean()获取Bean对象时会直接从IOC容器的缓存中获取Bean实例。
Spring 在 DefaultSingletenBeanFactory 类中提供了用于缓存单例Bean 缓存器,这个缓存器使用HashMap实现,单例Bena以beanName作为key进行存储。
BeanFactory依赖日志框架
在初始化 BeanFactory 时,必须提供一种日志框架,例如使用Log4j,这样启动Spring容器时才不会报错。
BeanFactory提供给开发者的操作类——ApplicationContext
ApplicationContext 继承于 HierarchicalBeanFactory 和 ListableBeanFactory 接口,并由此拓展出其它功能接口:
- ClassPathXmlApplicationContext: 默认从类路径加载配置文件
- FileSystemXmlApplicationContext: 默认从文件系统中装载配置文件
- ApplicationEventPublisher: 让容器拥有发布应用上下文事件的功能,包括启动容器事件、关闭容器事件等
- MessageSource: 为应用提供 il8n 国际化消息访问的功能
- ResourcePatternResolver: 通过带前缀的Ant风格的资源文件路径装载Spring配置条件
- LifeCycle: 这个接口是Spring 2.0 时加入的,提供了start 和 stop 方法,主要用来控制异步处理过程,在具体使用中,该接口会被ApplicaitonContext和Bean实例同时实现,ApplicationContext 会将 start 和 stop 状态发布给所有实现了接口的Bean,以达到管理和控制JMX、任务调度的目的
- ConfigurableApplicationContext: 扩展了ApplicationContext,主要是新增了两个方法:refresh() 和 close(),让ApplicationContext拥有了启动、刷新、关闭应用上下文的功能。
WebApplicationContext
WebApplicationContext是专门为Web应用准备的,它允许从相对于Web根目录的路径中装载配置文件完成初始化工作,从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性放置到ServletContext 中,以便Web应用环境可以访问Spring应用上下文。
(4)Spring Bean的作用域
Spring 3.0 定义了五种Bean的作用域:单例、原型、请求、会话、全局会话
- singleton(单例模式,多线程不安全): Spring IOC容器只存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一个对象,但这种模式在多线程环境下是不安全的。
- prototype(原型模式): Spring 每一次尝试获取原型模式的Bean对象时,容器都将创建一个新的Bean提供给Spring。
- request(请求模式): 一次HTTP请求,Spring创建一次新的Bean提供使用,其生命周期随请求状态的销毁而销毁。
- session(会话模式): 一次Http Session 中,容器返回的是同一个实例,当重新开启一次Http Session,容器会重新创建一个Bean实例提供使用,请求结束,实例销毁。
- global session(全局会话模式): 在一个全局Http Session中,容器返回同一个Bean实例,仅在protlet context时使用。
(5)Spring Bean的生命周期
SpringBean的生命周期:实例化 —— 属性赋值 —— 初始化 —— 销毁
实例化: 实例化一个Bean,也就是我们常说的new
属性赋值
- IOC 依赖注入: 按照Spring Context对Bean实例进行配置
- setBeanName的实现: 若Bean实现了
BeanNameAware接口,调用setBeanName(String beanId)方法 - setBeanFactory的实现: 若Bean实现了
BeanFactoryAware接口,调用setBeanFactory(BeanFacrtory beanFactory)方法 - setApplicationContext的实现: 若Bean实现了
ApplicationContextAware接口,调用setApplicationContext(ApplicationContext applicationContext)方法,可以实现设置BeanFactory方法,并比BeanFactoryAware更加优秀 - postProcessBeforelnitialization的实现: 若Bean实现了
BeanPostProcessor接口,将调用postProcessBeforelnitialization(Object obj, String s)方法,BeanPostProcessor经常用于Bean内容的修改,并且Bean初始化结束后也会调用这个方法,也可以应用于内存或缓存技术。
初始化
- init-method: 若Bean在配置文件中定义了初始化方法,则在初始化阶段会自动调用配置的初始化方法。
- postProcessAfterInitialization的实现: 若Bean实现了
BeanPostProcessor接口,调用postProcessAfterInitialization(Object obj, String s)方法。
销毁
- destroy 过期自动清理阶段: 当Bean不再需要时,会经历清理阶段,若 Bean 实现了 DisposableBean 接口,则调用
destroy()方法进行销毁。 - destroy-method 自配置清理: 若Bean的配置文件中设置了destroy方法时,则自动调用自定义的destroy方法
(6)Spring 依赖注入的方式
Spring 提供的依赖注入的方式:构造器注入、set方法注入、静态工厂注入、实例工厂注入
构造器注入案例
public CatDaoImpl(String message){this.message = message;
}<bean id="CatDaoImpl" class="class.CatDaoImpl"><constructor-arg value="message"></constructor-arg>
</bean>
setter方法注入
public class Id{private int id;public int getId(){return id;}public void setId(int id){this.id = id;}
}<bean id="id" class="com.Id"><property name="id" value="123"></property>
</bean>
静态工厂注入
// 对外提供的静态工厂
public class DaoFactory{public static final FactoryDao getStaticFactoryDaoImpl(){return new StaticFactoryDaoImpl;}
}//使用静态工厂的类
public class SpringAction{//注入对象private DaoFactory staticFactoryDao;//注入对象的set方法public void setStaticFactoryDao(FactoryDao staticFactoryDao){this.staticFactoryDao = staticFactoryDao;}
}//给调用类注入静态工厂
<bean name="springAction" class="com.SpringAction"><property name="staticFactoryDao" ref="staticFatoryDao"></property>
</bean>//给静态工厂中的成员注入
<bean name="staticFatoryDao" class="com.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
实例工厂注入
//创建一个实例工厂
public class DaoFactory{public DaoFactory getFactoryDaoImpl(){return new FactoryDaoImpl(); }
}//调用类使用实例工厂
public class SpringAction{private DaoFactory daoFactory;public void setDaoFactory(DaoFactory daoFactory){this.daoFactory = daoFactory;}
}//为调用类注入实例工厂Bean对象
<bean name="springAction" class="SpringAction"><property name="daoFactory" ref="daoFactory"></property>
</bean>//管理实例工厂,先声明注入的类,再配置实例工厂的成员
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
(7)自动装配的实现方式
Spring装配包括手动装配和自动装配,手动装配是基于 xml 装配、构造方法、setter方法等。
自动装配一共有5种实现方式:
- no: 默认不自动装配,通过显式的 ref 属性进行装配
- byName: 通过参数名自动装配,Spring在配置文件中检测到Autowired属性被设置为byName,容器自动按照beanName进行注入
- byType: 通过参数类型自动装配,Spring在配置文件中检测到Autowired属性被设置为byType,容器自动按照type进行注入,若有多个匹配对象,则抛出错误
- constructor: 类似于byType,但必须提供构造器参数,若没有确定参数的构造器参数类型,则抛出异常
- autodetect: 首先尝试使用 构造器参数 装配,若无法工作则使用byType方式
3、Spring AOP 的原理
(1)概念: AOP是一种“横切”技术,将多个类的公共模块抽取到一个模块中,并将其命名为**“Aspect”**,即切面。
(2)AOP的两个部分: 核心关注点、横切关注点
- 核心关注点: 业务处理的主要流程
- 横切关注点: 一切与业务代码无相关的代码
(3)AOP的应用场景:
- Authentication: 权限
- Caching: 缓存
- Context passing: 内容传递
- Error handling: 错误处理
- Lazy loading: 懒加载
- Debugging: 调试
- logging, tracing, profiling and monitoring: 记录跟踪 优化 校准
- Performance optimization: 性能优化
- Persistence: 持久化
- Resource pooling: 资源池
- Synchronization: 同步
- Transactions: 事务
(4)AOP的核心概念:
- 切面(Aspect): 类是对物体特征的抽象,切面是对横切关注点的抽象
- 横切关注点: 对哪些对象进行拦截、如何处理,这些关注点都是横切关注点
- 连接点(JoinPoint): 被拦截到的点,因为Spirng只支持方法类型的连接点,所以Spirng中连接点就是被拦截方法,实际上连接点还可以是字段、构造方法
- 切入点(PointCut): 对连接点进行拦截的定义
- 通知(Advice): 所谓的通知就是拦截到连接点后要执行的代码,分为前置、后置、异常、最终、环绕通知等类型
- 目标对象: 代理的目标对象
- 织入(weave): 将切面应用到目标对象并导致代理对象创建的过程
- 引入(introduction): 不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
(5)AOP的代理方式
Spring 提供了两种AOP的代理方式:JDK接口动态代理、CGLib动态代理
JDK接口动态代理:
- 被代理类实现
InvocationHandler,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起 - 代理类通过
InvocationHandler接口动态创建一个实例,生成目标类的代理对象
GCLib动态代理:
GCLib的全称是Code Generation Library,是一个高性能、高质量的代码生成类库,可以在运行期间动态扩展Java类和实现Java接口,CGLib封装了ASM,可以在运行期间生成新的class,对比JDK动态代理,CGLib可以动态代理未实现接口的类。
(6)AOP的实现原理
@Aspect
public class TransactionDemo {@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))") public void point(){}@Before(value="point()")public void before(){System.out.println("transaction begin");}@AfterReturning(value = "point()")public void after(){System.out.println("transaction commit");}@Around("point()")public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("transaction begin");joinPoint.proceed();System.out.println("transaction commit");}
}
4、Spring MVC 的原理
MVC指的是Modal(模型),View(视图),Controller(控制器),Spring MVC框架是围绕 DispatcherServlet 而设计的,这个Servlet会将请求分发到各个控制器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。
(1)浏览器请求的全过程:
- 浏览器发送HTTP请求,DispatcherServlet接收
- DispatcherServlet轮询处理器,通过HandlerMapping进行查找适用的Controller
- 当HandlerMapping查找到处理器后,DispatcherServlet调用处理器,将请求发送给Controller
- Controller调用Service层业务逻辑,获取返回值后分发到ModalAndView对象
- DispatcherServlet监听ModalAndView响应结果
- DispatcherServlet得到结果后分发给Model对象,并轮询视图映射ViewResolver,查找到指定的视图
- Modal将结果反应到视图,View向浏览器发送响应体
(2)MVC常用注解
组件注解: @Controller、@RestController、@Component、@Repository、@Service
请求注解: @RequestMapping、@Autowired、@PathVariable、@RequestParam、@RequestHeader
5、MyBatis缓存
MyBatis拥有两级缓存,默认情况下开启一级缓存,二级缓存由开发者手动开启。
一级缓存是会话级别的缓存,当同一会话调用同一个SQL时,优先从缓存中读取数据。
二级缓存是映射级别的缓存,不同的SQL会话可以共享该缓存
(1)一级缓存的原理
当用户线程第一次发出查询sql,sql的查询结果会写入到sqlSession的一级缓存中,缓存使用的是Map结构,其中key = mapperID + offset + limit + SQL + 所有入参,value = 用户信息,当同一个sqlSession再次发出同一个sql请求,就从缓存中取出数据,若两次查询中间发生更新操作,则本sqlSession中的一级缓存区域全部清空,所以第二次请求会从数据库中查询,并写入到新的缓存中去。
(2)二级缓存的原理
二级缓存的范围是mapper同命名空间的mapper,mapper以命名空间为单位创建缓存数据结构,结构是 map,通过 CacheExecutor 实现的。
CacheExecutor是Executor的代理对象,所有的查询操作,在CacheExecutor都会先查询缓存,再查询数据库。
(3)如何配置二级缓存
- MyBatis 全局配置中启用二级缓存配置
- 对应的mapper配置cache节点
- 对应的select查询节点添加useCache=true
相关文章:
Java技术整理(5)—— Spring篇
Spring是一个全面的全面的、企业应用开发一站式的解决方案,贯穿表现层、业务层、持久层。但是 Spring 仍然可以和其他的框架无缝整合。 1、Spring的核心组件 (1)数据层: JDBC、ORM、OXM、JMS、Transations (2&#x…...
07-MySQL-基础篇-函数
函数之字符串函数 前言函数字符串函数数值函数日期函数流程函数 前言 本篇来学习下MySQL中的函数–字符串函数。 函数 函数:是指一段可以直接被另一段程序调用的程序或代码MySQL中的函数主要分为以下四类: 字符串函数、数值函数、日期函数、流程函数。…...
不同路径 II——力扣63
class Solution {public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int n=...
NLP文本分类
NLP文本分类 落地实战五大利器!_kaiyuan_sjtu的博客-CSDN博客https://zhuanlan.zhihu.com/p/432619164 https://github.com/alibaba/EasyNLP/blob/master/README.cn.md...
进程和线程的联系与区别
文章目录 一、进程和线程的联系二、进程和线程的区别 一、进程和线程的联系 操作系统中可以有很多进程,每个进程都有自己独立的资源;一个进程中可以有很多线程,系统中的每个线程都能独立调度,同一个进程中的各个线程共享内存/硬盘…...
分支和循环语句(2)(C语言)
目录 do...while()循环 do语句的语法 do语句的特点 do while循环中的break和continue 练习 goto语句 do...while()循环 do语句的语法 do 循环语句; while(表达式); do语句的特点 循环至少执行一次,使用的场景有限,所以不是经常使用。 #inc…...
Flutter: A RenderFlex overflowed by 42 pixels on the bottom.
Flutter:渲染活动底部上方溢出了42个像素 Flutter 控件超出异常:A RenderFlex overflowed by 42 pixels on the bottom. 解决方案 1.Scaffold内添加 resizeToAvoidBottomInset 属性,缺点是软键盘下面的控件被挡住 Scaffold( resizeToAvoidBot…...
第三章,矩阵,07-用初等变换求逆矩阵、矩阵的LU分解
第三章,矩阵,07-用初等变换求逆矩阵、矩阵的LU分解 一个基本的方法求 A − 1 B A^{-1}B A−1BLU分解例1,求矩阵A的LU分解:例12,LU分解解线性方程组: 玩转线性代数(19)初等矩阵与初等变换的相关应用的笔记&a…...
STM32F429IGT6使用CubeMX配置SPI通信(W25Q256芯片)
1、硬件电路 需要系统性的看一下W25Q256芯片手册 2、设置RCC,选择高速外部时钟HSE,时钟设置为180MHz 3、配置SPI 4、生成工程配置 5、相关代码 #define sFLASH_ID 0XEF4019 // W25Q256#define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256#def…...
C++11异步与通信之 packaged_task
概念简介 packaged_task 用于包装可调用目标(Callable)为一个对象,如lambda,普通函数,小括号重载等,用于异步调用。 其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中,和promise类似。 将函数的调用与函数返…...
磁盘的管理
一、磁盘的分区 查看磁盘 lsblk fdisk -l 2、分区 没有e扩展,则都是主分区,已经有三个主分区了,剩下的全设置为扩展 查看分区结果: 二、格式化 三、挂载...
数据结构:完全二叉树的性质
完全二叉树的性质: 具有 n n n个结点的完全二叉树的深度为 [ l o g 2 n ] 1 ( [ x ] 表示不大于 x 的最大整数 ) [log_2n]1([x]表示不大于x的最大整数) [log2n]1([x]表示不大于x的最大整数) 对于任意一个结点 ( 1 < i < n ) &…...
【数据结构】‘双向链表’冲冲冲
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
Linux 编译CEF源码详细记录
Linux CEF(Chromium Embedded Framework)源码下载编译 背景 由于CEF默认的二进制分发包不支持音视频播放,需要自行编译源码,将ffmpeg开关打开才能支持。这里介绍的是Linux平台下的CEF源码下载编译过程。 Windows平台参考&#…...
LeetCode 2810. Faulty Keyboard【模拟,双端队列,字符串】简单
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
两个数组的交集-C语言/Java
描述 给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序。(1 < nums1.length, nums2.length < 1000,0 < nums1[i], nums2[i] < 1000) 示例1 输入…...
Arduino+esp32学习笔记
学习目标: 使用Arduino配置好蓝牙或者wifi模块 学习使用python配置好蓝牙或者wifi模块 学习内容(笔记): 一、 Arduino语法基础 Arduino语法是基于C的语法,C又是c基础上增加了面向对象思想等进阶语言。那就只记录没见过的。 单多…...
计算机网络-专业术语
计算机网络-专业术语 实体 实体:任何可发送或接收信息的硬件或软件进程 对等实体:收发双方相同层次中的实体 协议 控制两个对等实体进行逻辑通信的规则的集合 协议三要素 语法 定义所交换的信息的格式 是用户数据与控制信息的结构和格式 语义 定义收发双方所需要完成的操作…...
E. Maximum Monogonosity
You are given an array aa of length nn and an array bb of length nn. The cost of a segment [l,r][l,r], 1≤l≤r≤n1≤l≤r≤n, is defined as |bl−ar||br−al||bl−ar||br−al|. Recall that two segments [l1,r1][l1,r1], 1≤l1≤r1≤n1≤l1≤r1≤n, and [l2,r2][l2,…...
已解决Excel file format cannot be determined, you must specify an engine manually
问题 我使用以下语句时出现错误 data pd.read_excel(temp_inputc.csv, headerNone)出现错误: Excel file format cannot be determined, you must specify an engine manually有很多人说添加engine,但接下来会出现这个错误: File is not…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
基于小程序老人监护管理系统源码数据库文档
摘 要 近年来,随着我国人口老龄化问题日益严重,独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长,随之而来的是日益突出的老年人问题,尤其是老年人的健康问题,尤其是老年人产生健康问题后&…...
