一文学习开源框架LeakCanary
LeakCanary 简介
LeakCanary 是一个由 Square 开发的开源工具,主要用于检测和诊断 Android 应用中的内存泄漏问题。它通过自动化的方式帮助开发者捕捉和分析可能导致内存泄漏的对象,简化了内存问题的排查过程。
LeakCanary 的功能
- 自动检测内存泄漏: 在调试版本中,LeakCanary 会自动检测应用中未释放的内存。
- 生成堆快照和分析: 它会捕获堆转储文件,并通过分析生成易于理解的泄漏路径。
- 通知和报告: 检测到内存泄漏时,会通过系统通知展示详细的泄漏信息。
- 深度集成 Android: 专为 Android 优化,可与常见的生命周期管理器如
Activity
、Fragment
配合使用。
LeakCanary 的安装与使用
步骤 1: 添加依赖
在 build.gradle
文件中添加以下依赖:
dependencies {debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.x' // 使用调试模式releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.x' // 在发布版本中禁用
}
步骤 2: 初始化
LeakCanary 会在 Application
的启动过程中自动初始化,无需手动代码配置。
如果需要自定义配置,可以覆盖 Application
的 onCreate
方法:
class MyApplication : Application() {override fun onCreate() {super.onCreate()// 如果 LeakCanary 已经初始化,将其禁用if (LeakCanary.isInAnalyzerProcess(this)) {return}LeakCanary.config = LeakCanary.config.copy(dumpHeap = true) // 自定义配置}
}
步骤 3: 检测内存泄漏
LeakCanary 会自动检测内存泄漏,通常在以下场景下最为常见:
- Activity 或 Fragment 没有被正确销毁
- 未取消的监听器或回调
- 长生命周期对象(如单例)持有对短生命周期对象的引用
分析内存泄漏
当 LeakCanary 检测到泄漏时,会生成如下通知:
- 泄漏详情:展示泄漏路径。
- 相关类名:标记引发泄漏的关键对象。
- 快速跳转:支持跳转到代码位置。
示例:泄漏路径
┬───
│ GC Root: System class
│
├─ com.example.MyActivity instance
│ Leaking: YES (Activity被销毁但仍被引用)
│ Retaining: 10 KB
│
└─ Anonymous class implementationRetaining 10 KB in 1 object
LeakCanary 的优势
- 易于集成和使用:无需复杂的配置。
- 自动化:简化内存泄漏的检测过程。
- 可视化分析:详细的泄漏路径分析,帮助快速定位问题。
注意事项
- 生产环境禁用:LeakCanary 适用于开发和测试环境,发布版本中需要禁用。
- 泄漏分析耗时:捕获堆转储和分析会消耗资源,应避免频繁触发。
- 仅检测问题,不修复问题:LeakCanary 提供泄漏路径,但需要开发者手动修复问题。
LeakCanary 使用的设计模式分析
LeakCanary 是一个复杂的内存泄漏检测工具,其设计中应用了多种经典的设计模式,使其功能强大且易于维护。以下是 LeakCanary 中一些关键的设计模式及其作用:
1. 单例模式 (Singleton)
作用
LeakCanary 的核心组件(如监控器和配置管理)使用了单例模式,确保全局只有一个实例,避免多次初始化导致资源浪费。
应用示例
LeakCanary 的初始化使用了单例模式:
object LeakCanary {var config: Config = Config.defaultConfig
}
- 优点:确保全局状态一致性。简化全局访问,方便管理配置。
2. 观察者模式 (Observer)
作用
LeakCanary 需要监听特定事件(如 Activity
或 Fragment
的销毁),以便检测潜在的内存泄漏问题。观察者模式在此场景下非常适合。
应用示例
LeakCanary 通过监听 Lifecycle
组件监控 Activity 和 Fragment 的生命周期:
class ActivityWatcher : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)fun onActivityDestroyed(activity: Activity) {// 检测是否存在内存泄漏}
}
- 优点:解耦事件源和事件监听者。支持动态添加和移除观察者。
3. 工厂模式 (Factory Method)
作用
LeakCanary 提供了一些可扩展的组件,如堆分析器(Heap Analyzer)。通过工厂模式,可以动态创建不同的分析器以适应各种需求。
应用示例
object HeapAnalyzerFactory {fun createAnalyzer(): HeapAnalyzer {return DefaultHeapAnalyzer()}
}
- 优点:提高代码的灵活性和可扩展性。便于更换不同的实现。
4. 责任链模式 (Chain of Responsibility)
作用
LeakCanary 在分析内存泄漏时,可能需要执行多个步骤(如堆转储、路径分析、报告生成)。通过责任链模式,可以按顺序执行这些步骤,并灵活地增加或修改流程。
应用示例
堆分析过程中的责任链:
class LeakAnalysisPipeline {fun analyze(heapDump: HeapDump): AnalysisResult {val step1 = HeapDumpParser()val step2 = LeakReferenceFinder()val step3 = LeakPathFormatter()return step3.format(step2.find(step1.parse(heapDump)))}
}
- 优点:清晰地分离每个分析步骤。支持动态调整分析流程。
5. 策略模式 (Strategy)
作用
LeakCanary 支持多种策略来处理不同的内存泄漏场景(如如何捕获堆转储或如何生成报告)。通过策略模式,可以动态选择不同的处理逻辑。
应用示例
interface HeapDumpStrategy {fun dumpHeap(): HeapDump
}class DefaultHeapDumpStrategy : HeapDumpStrategy {override fun dumpHeap(): HeapDump {// 默认堆转储逻辑}
}
- 优点:代码更灵活,易于扩展。提高了具体策略的可替换性。
6. 建造者模式 (Builder)
作用
LeakCanary 的配置管理(如 Config
类)采用了建造者模式,便于链式调用构造复杂的配置对象。
应用示例
val config = LeakCanary.Config.Builder().dumpHeap(true).maxStoredHeapDumps(5).build()
- 优点:代码可读性更高。更易于扩展和维护。
总结
LeakCanary 结合了多种设计模式,设计精巧:
- 单例模式 用于管理全局组件。
- 观察者模式 用于监听生命周期事件。
- 工厂模式 提供灵活的组件创建。
- 责任链模式 实现堆分析流程。
- 策略模式 动态选择不同的分析逻辑。
- 建造者模式 便于配置复杂参数。
这些模式协同工作,使 LeakCanary 功能强大且易于扩展,是优秀设计的典范。
LeakCanary的原理
LeakCanary 是一个用于检测 Android 应用中内存泄漏的工具,它的核心原理基于以下关键流程:
- 监听对象的生命周期 LeakCanary 通过对 Activity、Fragment 等短生命周期对象进行监听,检查这些对象是否在销毁后仍被其他对象持有引用,导致无法被垃圾回收(GC)。
- *触发垃圾回收 (GC) *在检测到某个对象即将被销毁时,LeakCanary 会主动触发一次垃圾回收,确保可以正确判断该对象是否仍在内存中。
- 弱引用监控 使用
WeakReference
对目标对象进行引用。对象正常情况下在 GC 后会被回收,但如果未被回收,则可能存在内存泄漏。 - 生成堆转储 (Heap Dump) 如果检测到疑似内存泄漏,LeakCanary 会生成一个堆转储文件,用于后续分析。
- 分析堆转储使用内置的分析工具(如
Shark
)解析堆转储文件,寻找泄漏路径,并输出详细报告,帮助开发者定位泄漏原因。
LeakCanary 的工作流程
1. 初始化监听
LeakCanary 在 Application
启动时自动初始化,并通过 Android 的 Lifecycle
或 ActivityLifecycleCallbacks
监听 Activity 和 Fragment 的生命周期。
- 示例:监听 Activity 的 onDestroy 方法:
class ActivityWatcher : Application.ActivityLifecycleCallbacks {override fun onActivityDestroyed(activity: Activity) {LeakCanary.refWatcher.watch(activity)}
}
2. 检测对象泄漏
LeakCanary 通过 RefWatcher
对目标对象创建弱引用,并定期检查弱引用是否被清除。
- 示例:使用 WeakReference 检测内存泄漏:
fun watch(activity: Activity) {val weakRef = WeakReference(activity)System.gc() // 主动触发 GCif (weakRef.get() != null) {// 如果对象仍未被回收,可能存在泄漏reportLeak(activity)}
}
3. 触发堆转储
当检测到疑似泄漏时,LeakCanary 会生成堆转储文件。它使用 Android 提供的 Debug.dumpHprofData()
方法保存内存快照。
- 示例:堆转储生成:
Debug.dumpHprofData("/data/local/tmp/leak.hprof")
4. 分析堆转储
LeakCanary 使用 Square 开发的 Shark
库对堆转储文件进行解析。Shark
是一个轻量级的堆分析工具,能够快速定位保留目标对象的引用路径。
堆分析的关键点 找到未被回收的对象。分析该对象的引用链。生成泄漏路径报告。
5. 报告泄漏路径
LeakCanary 将泄漏信息以友好的方式呈现,包括泄漏的对象、保留它的引用链以及内存占用等信息。
- 示例报告:
┬───
│ GC Root: System class
│
├─ com.example.MyActivity instance
│ Leaking: YES
│ Retaining: 10 KB
│
└─ Anonymous class implementationRetaining 10 KB in 1 object
关键技术点
- 弱引用 (WeakReference)
- 使用弱引用检测对象是否被正确回收。
- 垃圾回收 (GC)
- 主动调用 System.gc(),确保检测时垃圾回收器已运行。
- 堆转储 (Heap Dump)
- 使用 Debug.dumpHprofData() 生成堆转储文件。
- 堆分析 (Heap Analysis)
- 解析堆转储文件,寻找对象的保留路径。
- 生命周期监听
- 借助 ActivityLifecycleCallbacks 或 AndroidX Lifecycle 监听生命周期变化。
原理图
Activity/Fragment 销毁↓触发 WeakReference↓调用 System.gc()↓对象仍未被回收?是 否↓ ↓Dump 堆 正常↓
分析引用链 (Shark)↓
报告泄漏路径
LeakCanary 的优势
- 自动化检测:自动监听对象生命周期,无需手动操作。
- 详细报告:清晰的泄漏路径,方便定位问题。
- 轻量级:堆分析优化性能,适合开发阶段使用。
- 深度集成 Android 生命周期:特别针对 Activity 和 Fragment 的内存泄漏。
通过上述流程和技术,LeakCanary 提供了一种高效的方法来检测和定位内存泄漏,为开发者节省了大量调试时间。
LeakCanary 的源码解析
LeakCanary 是一款开源的 Android 内存泄漏检测工具,源码结构清晰且使用了多个设计模式。以下从 核心模块 和 关键流程 两方面解析 LeakCanary 的源码实现。
1. 源码结构
LeakCanary 的源码主要分为以下几个模块:
- leakcanary-android:LeakCanary 的主模块,负责生命周期监听、弱引用检测和堆转储。
- leakcanary-shark:堆分析模块,解析堆转储文件。
- leakcanary-android-core:核心逻辑实现,包含内存泄漏检测、通知和报告功能。
- leakcanary-object-watcher:负责监听和管理弱引用对象。
- leakcanary-log:日志工具模块。
2. 核心类解析
2.1. RefWatcher
RefWatcher
是 LeakCanary 的核心类,负责检测对象是否发生内存泄漏。
- 主要职责:创建 WeakReference 对目标对象进行监控。定期检查弱引用是否被回收。在未被回收时触发堆转储。
- 源码分析:
class RefWatcher(private val objectWatcher: ObjectWatcher
) {fun watch(watchedObject: Any, description: String = "") {objectWatcher.watch(watchedObject, description)}
}
RefWatcher
实际将监控任务交给了 ObjectWatcher
,这是典型的 委托模式。
2.2. ObjectWatcher
ObjectWatcher
是用于检测对象是否被回收的核心工具类。
- 主要职责:为目标对象创建一个弱引用,并关联一个标记。在定期检查时,判断弱引用是否被回收。
- 源码分析:
class ObjectWatcher {private val retainedReferences = mutableMapOf()fun watch(watchedObject: Any, description: String) {val key = UUID.randomUUID().toString()val reference = KeyedWeakReference(watchedObject, key, description)retainedReferences[key] = reference}fun checkRetainedObjects() {retainedReferences.entries.removeIf { it.value.isCleared() }}
}
KeyedWeakReference:通过弱引用 (WeakReference) 包装目标对象,并附加唯一标识。定期调用 checkRetainedObjects() 清理已回收的对象。
2.3. HeapDumpTrigger
HeapDumpTrigger
是堆转储的触发器。
- 主要职责:当对象未被回收时,触发堆转储并记录泄漏信息。调用 Android 系统 API 生成堆转储文件。
- 源码分析:
class HeapDumpTrigger {fun dumpHeap(retainedObjects: List) {val file = createHeapDumpFile()Debug.dumpHprofData(file.absolutePath)analyzeHeap(file)}
}
Debug.dumpHprofData:Android 提供的堆转储工具。analyzeHeap:调用 Shark 分析堆文件。
2.4. Shark (堆分析模块)
Shark
是 LeakCanary 内部用于堆分析的库,支持解析和分析堆转储文件。
- 主要职责:解析堆文件中的对象引用链。找出未被回收的对象及其引用路径。
- 关键代码:
class HeapAnalyzer {fun analyze(heapDump: File): AnalysisResult {val parser = HprofParser(heapDump)val leakingObjects = parser.findLeakingObjects()return AnalysisResult(leakingObjects)}
}
HprofParser:负责解析堆文件,提取目标对象的引用链。findLeakingObjects:检测所有可能的泄漏对象。
3. 核心流程解析
3.1. 生命周期监听
LeakCanary 使用 ActivityLifecycleCallbacks
或 AndroidX 的 LifecycleObserver
监听 Activity 和 Fragment 的生命周期。
- 源码:
class ActivityWatcher(application: Application) : Application.ActivityLifecycleCallbacks {override fun onActivityDestroyed(activity: Activity) {LeakCanary.refWatcher.watch(activity)}
}
在 onDestroy 方法中调用 RefWatcher.watch(),启动泄漏检测。
3.2. 检测内存泄漏
当目标对象被监听后,LeakCanary 会执行以下步骤:
- 弱引用监控:
使用ObjectWatcher
创建目标对象的WeakReference
。
val weakReference = KeyedWeakReference(watchedObject, key, description)
retainedReferences[key] = weakReference
- 触发垃圾回收:
调用System.gc()
主动回收内存。 - 检查引用:
如果弱引用仍未被回收,认为对象可能泄漏。
3.3. 生成堆转储
如果对象未被回收,LeakCanary 使用 HeapDumpTrigger
触发堆转储。
- 代码:
if (!weakReference.isCleared()) {heapDumpTrigger.dumpHeap(retainedReferences.values.toList())
}
3.4. 堆分析
Shark
分析堆文件,定位泄漏路径。
- 分析逻辑:解析堆文件中所有对象。寻找目标对象的引用路径。输出报告。
4. 数据流总结
Activity/Fragment 销毁↓
RefWatcher.watch()↓
ObjectWatcher 添加弱引用↓
触发 GC 检查引用↓
未回收?(是)→ Dump 堆↓
解析引用链 (Shark)↓
输出泄漏报告
LeakCanary 的设计亮点
- 解耦逻辑:
- 使用多个独立的模块(如 RefWatcher、ObjectWatcher)分离职责。
- 设计模式:
- 单例模式:如 RefWatcher 的全局实例管理。
- 观察者模式:监听对象生命周期。
- 责任链模式:堆转储和堆分析分步执行。
- 高效的堆分析:
- 通过 Shark 优化堆文件解析,提升性能。
源码地址
LeakCanary GitHub 可以直接参考其开源代码来学习具体实现细节和架构设计。
相关文章:

一文学习开源框架LeakCanary
LeakCanary 简介 LeakCanary 是一个由 Square 开发的开源工具,主要用于检测和诊断 Android 应用中的内存泄漏问题。它通过自动化的方式帮助开发者捕捉和分析可能导致内存泄漏的对象,简化了内存问题的排查过程。 LeakCanary 的功能 自动检测内存泄漏&a…...

jetson orin系列开发版安装cuda的gpu版本的opencv
opencv安装包下载地址: https://github.com/opencv/opencv/扩展库下载地址: https://github.com/opencv/opencv_contrib1. 删除jetpack包中的opencv版本 原先的opencv库安装在目录/usr/lib/aarch64-linux-gnu/下(一般其他的第三方库也都安…...

数据结构-8.Java. 七大排序算法(中篇)
本篇博客给大家带来的是排序的知识点, 由于时间有限, 分两天来写, 中篇主要实现后三种排序算法: 冒泡排序,快速排序,下一篇讲 归并排序. 文章专栏: Java-数据结构 若有问题 评论区见 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作…...

数据结构C语言描述4(图文结合)--栈的实现,中序转后序表达式的实现
前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…...

python基本数据类型 -- 元组tuple
在 Python 中,元组(Tuple)是一种轻量级的、不可变的数据结构。与列表类似,元组用于存储有序的数据集合,但它一旦创建,其内容就无法更改。这种特性让元组在某些场景下更加安全和高效。本文将从定义、操作、应…...

tcpdump交叉编译
TCPDUMP在Libpcap上开发。 首先需要编译libcap。 网上那么多教程,下载地址都只给了一个英文的官网首页, 你尽可以试试,从里面找到下载地址都要费半天时间。 \color{red}网上那么多教程,下载地址都只给了一个英文的官网首页&#…...

Spring IOC注入方式、Bean作用域
Spring IOC注入 手动注入 set方法注入 需要提供set方法 public class UserService {private UserDao userDao; public void setUserDao(UserDao userDao) {this.userDao userDao;} } 设置属性字段的值 <bean id"userService" class"com.shsxt.servi…...

uniapp微信小程序转发跳转指定页面
onShareAppMessage 是微信小程序中的一个重要函数,用于自定义转发内容。当用户点击右上角的菜单按钮,并选择“转发”时,会触发这个函数。开发者可以在这个函数中返回一个对象,用于定义分享卡片的标题、图片、路径等信息。 使用场…...

利用uniapp开发鸿蒙:运行到鸿蒙模拟器—踩坑合集
从uniapp运行到鸿蒙模拟器上这一步,就有非常多的坑,一些常见的坑,官网都有介绍,就不再拿出来了,这里记录一下官网未记录的大坑 1.运行路径从hbuilderx启动鸿蒙模拟器 解决方法: Windows系统,官…...

【Vue】Vue3.0(二十五)Vue3.0中的具名插槽 的概念和使用场景
上篇文章 【Vue】Vue3.0(二十四)Vue3.0中 r e f s 、 refs 、 refs、parent 的概念和使用场景 🏡作者主页:点击! 🤖Vue专栏:点击! ⏰️创作时间:2024年11月20日16点30分 …...

【pytorch-02】:张量的索引、形状操作和常见运算函数
文章目录 1 张量索引1.1 简单行列索引和列表索引1.2 布尔索引和多维索引 2 张量的形状操作2.1 reshape函数2.2 transpose和permute函数的使用2.3 view和contiguous函数2.4 squeeze和unsqueeze函数用法2.5 张量更改形状小结 3 常见运算函数 1 张量索引 1.1 简单行列索引和列表索…...

C语言-指针作为函数返回值及二级指针
1、指针作为函数返回值 c语言允许函数的返回值是一个指针(地址)我们将这样的函数称为指针函数,下面的例子定义一了一个函数strlong(),用来返回两个字符串中较长的一个: 1. #include <stdio…...

css 使用图片作为元素边框
先看原始图片 再看效果 边框的四个角灭有拉伸变形,但是图片的中部是拉伸的 代码 border-style: solid;/* 设置边框图像的来源 */border-image-source: url(/static/images/mmwz/index/bk_hd3x.png);/* 设置如何切割图像 */border-image-slice: 66;/* 设置边框的宽度 */border…...

Linux无sudo权限将zsh作为默认shell
由于我只有用户权限,没有sudo权限,将zsh作为用户默认shell需要密码,所以没法在系统层面进行操作,下面另寻他法。 安装zsh 可以根据网上教程去安装zsh,一般电脑上会带有zsh,可以使用下述命令查看是否安装z…...

【React 进阶】掌握 React18 全部 Hooks
一、数据更新驱动 1. useState 1. 基础介绍 useState主要用于声明和操作状态变量,可以使函数组件像类组件一样拥有state const [state, setState] useState(initialState);state:状态,作为渲染视图的数据源 setState:改变st…...

【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter) 更新以gitee为准: 文章目录 数据预测概念和适用方式线性系统的适用性 数据预测算法和卡尔曼滤波公式推导状态空间方程和观测器先验估计后验估计…...

【SQL50】day 2
目录 1.每位经理的下属员工数量 2.员工的直属部门 3.判断三角形 4.上级经理已离职的公司员工 5.换座位 6.电影评分 7.修复表中的名字 8.患某种疾病的患者 9.删除重复的电子邮箱 1.每位经理的下属员工数量 # Write your MySQL query statement below #e1是经理,…...

【内存管理】理解 `WeakReference` 以更好地管理 Android 应用中的内存
在 Android 应用开发中,内存管理至关重要。糟糕的内存管理可能导致“内存泄漏”,即一些不再需要的对象仍然留在内存中,最终导致性能下降,甚至应用崩溃。WeakReference 就是帮助解决这个问题的一种工具。在本文中,我们将…...

解决IDEA中Maven管理界面不是层级结构的问题
文章目录 0. 前言1. 点击Maven管理界面右上角的三个点2. 勾选将模块分组3. 分组后的层级结构 更多 IDEA 的使用技巧可查看 IDEA 专栏中的文章:IDEA 0. 前言 在 IDEA 中,如果项目中有很多子模块,每个子模块中又有一个或多个子模块时…...

Linux运维篇-iscsi存储搭建
目录 概念实验介绍环境准备存储端软件安装使用targetcli来管理iSCSI共享存储 客户端软件安装连接存储 概念 iSCSI是一种在Internet协议上,特别是以太网上进行数据块传输的标准,它是一种基于IP Storage理论的存储技术,该技术是将存储行业广泛…...

深度学习基础练习:代码复现transformer重难点
2024/11/10-2024/11/18: 主要对transformer一些比较难理解的点做了一些整理,希望对读者有所帮助。 前置知识: 深度学习基础练习:从pytorch API出发复现LSTM与LSTMP-CSDN博客 【神经网络】学习笔记十四——Seq2Seq模型-CSDN博客 【官方双语】一…...

141. Sprite标签(Canvas作为贴图)
上节课案例创建标签的方式,是把一张图片作为Sprite精灵模型的颜色贴图,本节给大家演示把Canvas画布作为Sprite精灵模型的颜色贴图,实现一个标签。 注意:本节课主要是技术方案讲解,默认你有Canvas基础,如果没有Canvas基…...

【IDEA】解决总是自动导入全部类(.*)问题
文章目录 问题描述解决方法 我是一名立志把细节说清楚的博主,欢迎【关注】🎉 ~ 原创不易, 如果有帮助 ,记得【点赞】【收藏】 哦~ ❥(^_-)~ 如有错误、疑惑,欢迎【评论】指正探讨,我会尽可能第一时间回复…...

python中的OS模块的基本使用
🎉🎉🎉欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!🙏🙏🙏 文章目录…...

【Qt】QComboBox设置默认显示为空
需求 使用QComboBox,遇到一个小需求是,想要设置未点击出下拉列表时,内容显示为空。并且不想在下拉列表中添加一个空条目。 实现 使用setPlaceholderText()接口。我们先来看下帮助文档: 这里说的是,placeholderText是…...

LeetCode - #139 单词拆分
文章目录 前言摘要1. 描述2. 示例3. 答案题解动态规划的思路代码实现代码解析1. **将 wordDict 转换为 Set**2. **初始化 DP 数组**3. **状态转移方程**4. **返回结果** **测试用例**示例 1:示例 2:示例 3: 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗…...

服务器作业4
[rootlocalhost ~]# vim 11.sh #关闭防火墙 systemctl stop firewalld setenforce 0 #1.接收用户部署的服务名称 read -p "服务名称:(nginx)" server_name if [ $server_name ! nginx ];then echo "输入的不是nginx,脚本退出" exit 1 fi # 判断是…...

IOC控制反转---相关的介绍和6大注解解读(类注解+方法注解)
文章目录 1.传统方式造车2.传统方法的弊端3.IOC的引入3.IOC对于图书管理系统进行改进(初识)4.注解的使用说明4.1controller注解4.2service注解4.3component注解4.4关于spring命名的问题4.5component重命名4.6repository注解4.7configuration注解4.8注解之…...

SpringBoot(8)-任务
目录 一、异步任务 二、定时任务 三、邮件任务 一、异步任务 使用场景:后端发送邮件需要时间,前端若响应不动会导致体验感不佳,一般会采用多线程的方式去处理这些任务,但每次都需要自己去手动编写多线程来实现 1、编写servic…...

【机器学习】如何配置anaconda环境(无脑版)
马上就要上机器学习的实验,这里想写一下我配置机器学习的anaconda环境的二三事 一、首先,下载安装包: Download Now | Anaconda 二、打开安装包,一直点NEXT进行安装 这里要记住你要下载安装的路径在哪,后续配置环境…...