.NET IoC 容器(三)Autofac
目录
- .NET IoC 容器(三)Autofac
- Autofac
- Nuget 安装
- 实现DI
- 定义接口
- 定义实现类
- 依赖注入
- 注入方式
- 构造函数注入 | 属性注入 | 方法注入
- 注入实现
- 接口注册
- 重复注册
- 指定参数注册
- 生命周期
- 默认生命周期
- 单例生命周期
- 每个周期范围一个生命周期
- 依赖配置
- Nuget
- 配置文件
- AOP
- Nuget安装
- 定义接口、实现类
- 定义切面
- 容器配置
- 参考资料
.NET IoC 容器(三)Autofac
Autofac
Autofac 是一个用于 .NET 应用程序的依赖注入 (Dependency Injection, DI) 容器。它帮助开发人员管理对象的创建和生命周期,使得依赖项的注入更加灵活和可维护。以下是 Autofac 的主要功能和特性概述:
依赖注入 (Dependency Injection)
Autofac 允许你通过构造函数、属性或方法注入依赖项。这样,你可以轻松地将对象的依赖关系传递给需要它们的类,从而提高代码的可测试性和可维护性。
模块化设计 (Modular Design)
Autofac 支持模块化设计,可以将相关的依赖项注册逻辑分组到模块中。这使得大型应用程序的配置更加简洁和易于管理。
生命周期管理 (Lifecycle Management)
Autofac 提供多种对象生命周期管理方式,例如单例 (Singleton)、每次请求 (Instance Per Dependency)、每个生命周期范围 (Instance Per Lifetime Scope) 等,允许你精确控制对象的创建和销毁时机。
注册与解析 (Registration and Resolution)
Autofac 通过流畅的 API 提供了多种注册组件的方式。你可以注册类型、实例、工厂方法,甚至通过扫描程序集自动注册组件。此外,Autofac 的解析功能支持构造函数参数注入、命名参数注入等高级特性。
支持 AOP (Aspect-Oriented Programming)
Autofac 与 AOP 框架(如 Castle Windsor)集成,支持横切关注点(如日志记录、事务管理)的处理,从而使业务逻辑代码更加简洁。
集成支持
Autofac 与许多流行的 .NET 库和框架集成良好,包括 ASP.NET Core、WCF、Web API、MVC 等。通过这些集成,Autofac 可以轻松地管理 web 应用程序中的依赖项。
扩展性
Autofac 具有很高的扩展性,可以通过自定义注册源、生命周期、解析器等方式扩展其功能,以满足特定应用的需求。
Nuget 安装
实现DI
定义接口
internal interface IComputer
{
}
internal interface IKeyboard
{
}
internal interface IMouse
{
}
internal interface IPerson
{IComputer Computer { get; set; }IKeyboard Keyboard { get; set; }IMouse Mouse { get; set; }void Work();
}
定义实现类
internal class ConstructBase
{public ConstructBase() {Console.WriteLine($"{this.GetType().Name} - 被构造了");}
}
internal class LenovoComputer : ConstructBase, IComputer
{public LenovoComputer() : base() { }
}
internal class TogarKeyboard : ConstructBase, IKeyboard
{public TogarKeyboard() : base() { }
}
internal class LogitechMouse : ConstructBase, IMouse
{public LogitechMouse() : base() { }
}
internal class Programmer : ConstructBase, IPerson
{public IComputer Computer { get; set; }public IKeyboard Keyboard { get; set; }public IMouse Mouse { get; set; }public Programmer(IComputer computer, IKeyboard keyboard, IMouse mouse) : base(){Computer = computer;Keyboard = keyboard;Mouse = mouse;}public void Work(){Console.WriteLine("Programmers are building software...");}
}
依赖注入
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Programmer>().As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...
注入方式
构造函数注入 | 属性注入 | 方法注入
定义特性用来筛选属性注入
public class InjectPropertyAttribute : Attribute
{}
定义实现类
public class Gamer : ConstructBase, IPerson
{public IComputer Computer { get; set; }[InjectProperty]public IKeyboard Keyboard { get; set; }public IMouse Mouse { get; set; }public Gamer(IComputer computer) : base(){Computer = computer;}public void Inject(IMouse mouse){Mouse = mouse;}public void Work(){Console.WriteLine("The player is playing...");}
}
注入实现
// 注入顺序(与编码顺序无关):构造函数注入 > 属性注入 > 方法注入
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()// 方法注入.OnActivating(e =>{IMouse mouse = e.Context.Resolve<IMouse>();e.Instance.Inject(mouse);})// 属性注入.PropertiesAutowired((g, o) => g.Name == "Keyboard")// 构造函数注入.UsingConstructor(typeof(IComputer)).As<IPerson>();
var container = builder.Build();
IPerson gamer = container.Resolve<IPerson>();
gamer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
The player is playing...
结果
注入顺序:构造函数注入 > 属性注入 > 方法注入
接口注册
重复注册
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Programmer>().As<IPerson>();
builder.RegisterType<Gamer>()// 方法注入.OnActivating(e =>{IMouse mouse = e.Context.Resolve<IMouse>();e.Instance.Inject(mouse);})// 属性注入.PropertiesAutowired((g, o) => g.Name == "Keyboard")// 构造函数注入.UsingConstructor(typeof(IComputer)).As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
The player is playing...
调换Gamer和Programmer的注册顺序:
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()// 方法注入.OnActivating(e =>{IMouse mouse = e.Context.Resolve<IMouse>();e.Instance.Inject(mouse);})// 属性注入.PropertiesAutowired((g, o) => g.Name == "Keyboard")// 构造函数注入.UsingConstructor(typeof(IComputer)).As<IPerson>();
builder.RegisterType<Programmer>().As<IPerson>();
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...
结论
同一接口多次注册时,后注册的会覆盖前面注册的,若需要实现多重注册,需要指定名称
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
builder.RegisterType<TogarKeyboard>().As<IKeyboard>();
builder.RegisterType<LogitechMouse>().As<IMouse>();
builder.RegisterType<Gamer>()// 方法注入.OnActivating(e =>{IMouse mouse = e.Context.Resolve<IMouse>();e.Instance.Inject(mouse);})// 属性注入.PropertiesAutowired((g, o) => g.Name == "Keyboard")// 构造函数注入.UsingConstructor(typeof(IComputer)).Named<IPerson>("person");
builder.RegisterType<Programmer>().Named<IPerson>("programmer");
var container = builder.Build();
IPerson programmer = container.ResolveNamed<IPerson>("programmer");
IPerson person = container.ResolveNamed<IPerson>("person");
programmer.Work();
person.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.Gamer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Programmers are building software...
The player is playing...
指定参数注册
修改接口
internal interface IMouse
{string Type { get; set; }
}
修改实现类
internal class LogitechMouse : ConstructBase, IMouse
{public LogitechMouse() : base() { }public LogitechMouse(string type) : base(){Type = type;}public string Type { get; set; }
}
注入
var builder = new ContainerBuilder();
builder.RegisterType<LogitechMouse>().WithParameter("type","502").As<IMouse>();
var container = builder.Build();
IMouse mouse = container.Resolve<IMouse>();
Console.WriteLine("mouse type: " + mouse.Type);
输出
Zhy.IoC.Autofac.LogitechMouse - 被构造了
mouse type: 502
生命周期
Instance Per Dependency(默认) 每次请求组件时都会创建一个新的实例。这是默认的生命周期管理模式。
builder.RegisterType<MyService>().As<IMyService>();
Singleton 在整个容器生命周期内,只有一个实例。
builder.RegisterType<MyService>().As<IMyService>().SingleInstance();
Instance Per Lifetime Scope 在每个生命周期范围内,共享一个实例。每个生命周期范围都会创建一个新的实例,但在该范围内共享该实例。
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Instance Per Matching Lifetime Scope 在特定的生命周期范围内共享实例,需要指定标记。
builder.RegisterType<MyService>().As<IMyService>().InstancePerMatchingLifetimeScope("my-scope");
Instance Per Request 通常用于 web 应用程序,在每个 HTTP 请求期间共享一个实例。
builder.RegisterType<MyService>().As<IMyService>().InstancePerRequest();
Externally Owned 组件由外部代码管理生命周期,Autofac 不会在容器释放时释放该实例。
builder.RegisterType<MyService>().As<IMyService>().ExternallyOwned();
Instance Per Dependency 每次依赖请求时都会创建一个新实例。
builder.RegisterType<MyService>().As<IMyService>().InstancePerDependency();
默认生命周期
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
IComputer computer1 = container.Resolve<IComputer>();
Console.WriteLine("computer0: " + computer0.GetHashCode());
Console.WriteLine("computer1: " + computer1.GetHashCode());
Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 22687807
computer0 == computer1: False
单例生命周期
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>().SingleInstance();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
IComputer computer1 = container.Resolve<IComputer>();
Console.WriteLine("computer0: " + computer0.GetHashCode());
Console.WriteLine("computer1: " + computer1.GetHashCode());
Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 32347029
computer0 == computer1: True
每个周期范围一个生命周期
var builder = new ContainerBuilder();
builder.RegisterType<LenovoComputer>().As<IComputer>().InstancePerLifetimeScope();
var container = builder.Build();
IComputer computer0 = container.Resolve<IComputer>();
using (var scope = container.BeginLifetimeScope())
{IComputer computer1 = scope.Resolve<IComputer>();IComputer computer2 = scope.Resolve<IComputer>();Console.WriteLine("computer0: " + computer0.GetHashCode());Console.WriteLine("computer1: " + computer1.GetHashCode());Console.WriteLine("computer2: " + computer2.GetHashCode());Console.WriteLine($"computer0 == computer1: {computer0 == computer1}");Console.WriteLine($"computer1 == computer2: {computer1 == computer2}");
}
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.LenovoComputer - 被构造了
computer0: 32347029
computer1: 22687807
computer2: 22687807
computer0 == computer1: False
computer1 == computer2: True
依赖配置
Nuget
配置文件
Json
{"components": [{"type": "Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac","services": [{"type": "Zhy.IoC.Core.IComputer,Zhy.IoC.Core"}],"autoActivate": true,"instanceScope": "singleinstance"},{"type": "Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac","services": [{"type": "Zhy.IoC.Core.IKeyboard,Zhy.IoC.Core"}],"autoActivate": true,"instanceScope": "singleinstance"},{"type": "Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac","services": [{"type": "Zhy.IoC.Core.IMouse,Zhy.IoC.Core"}],"parameters": {"places": 4},"autoActivate": true,"instanceScope": "singleinstance"},{"type": "Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac","services": [{"type": "Zhy.IoC.Core.IPerson,Zhy.IoC.Core"}],"autoActivate": true,"instanceScope": "singleinstance"}]
}
XML
<?xml version="1.0" encoding="utf-8" ?>
<autofac><components name="0"><type>Zhy.IoC.Autofac.LenovoComputer,Zhy.IoC.Autofac</type><services name="0" type="Zhy.IoC.Core.IComputer,Zhy.IoC.Core" /></components><components name="1"><type>Zhy.IoC.Autofac.TogarKeyboard,Zhy.IoC.Autofac</type><services name="0" type="Zhy.IoC.Core.IKeyboard,Zhy.IoC.Core" /></components><components name="2"><type>Zhy.IoC.Autofac.LogitechMouse,Zhy.IoC.Autofac</type><services name="0" type="Zhy.IoC.Core.IMouse,Zhy.IoC.Core" /></components><components name="3"><type>Zhy.IoC.Autofac.Programmer,Zhy.IoC.Autofac</type><services name="0" type="Zhy.IoC.Core.IPerson,Zhy.IoC.Core" /></components>
</autofac>
调用
var config = new ConfigurationBuilder();
config.AddJsonFile("DI-Autofac.json");
// config.AddXmlFile("DI-Autofac.xml");
var module = new ConfigurationModule(config.Build());
var builder = new ContainerBuilder();
builder.RegisterModule(module);
var container = builder.Build();
IPerson programmer = container.Resolve<IPerson>();
programmer.Work();
输出
Zhy.IoC.Autofac.LenovoComputer - 被构造了
Zhy.IoC.Autofac.TogarKeyboard - 被构造了
Zhy.IoC.Autofac.LogitechMouse - 被构造了
Zhy.IoC.Autofac.Programmer - 被构造了
Programmers are building software...
AOP
Nuget安装
定义接口、实现类
public interface IMyService
{void DoWork();
}
public void DoWork()
{Console.WriteLine("Doing work...");
}
定义切面
using Castle.DynamicProxy;public class LoggingInterceptor : IInterceptor
{public void Intercept(IInvocation invocation){Console.WriteLine($"Invoking method {invocation.Method.Name} at {DateTime.Now}");invocation.Proceed();Console.WriteLine($"Method {invocation.Method.Name} has completed at {DateTime.Now}");}
}
容器配置
var builder = new ContainerBuilder();
builder.Register(c => new LoggingInterceptor());
builder.RegisterType<MyService>().As<IMyService>().EnableInterfaceInterceptors().InterceptedBy(typeof(LoggingInterceptor));
var container = builder.Build();
var service = container.Resolve<IMyService>();
service.DoWork();
输出
Invoking method DoWork at 2024/5/30 16:49:34
Doing work...
Method DoWork has completed at 2024/5/30 16:49:34
参考资料
IOC容器之Unity与AutoFac_unity autofac-CSDN博客
Autofac/src/Autofac at develop · autofac/Autofac (github.com)
控制容器的反转和依赖关系注入模式 (martinfowler.com)
相关文章:

.NET IoC 容器(三)Autofac
目录 .NET IoC 容器(三)AutofacAutofacNuget 安装实现DI定义接口定义实现类依赖注入 注入方式构造函数注入 | 属性注入 | 方法注入注入实现 接口注册重复注册指定参数注册 生命周期默认生命周期单例生命周期每个周期范围一个生命周期 依赖配置Nuget配置文…...

Day44 动态规划part04
背包问题 01背包问题:每件物品只能用一次完全背包问题:每件物品可以使用无数次 01背包问题 暴力解法:每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是 o…...

html期末复习速览
一.基础标签 1.段落标签<p></p> 特点:分段分割 2.标题标签<h1></h1>……<h6></h6> 特点:文字加粗,单独占一行 3.换行标签<br /> 特点:单标签,强制换行 二.文本格式化…...

CTFHUB-信息泄露-目录遍历和PHPINFO
目录 目录遍历 PHPINFO 目录遍历 很简单,挨着把每个目录都点开看一下 发现2目录下有个 flag.txt 文件,点开发现了本关的flag PHPINFO 这关也很简单,进来之后是一个phpinfo页面,按 CTRL F键打开查询,输入flag&#…...

面向Java程序员的Go工程开发入门流程
对于一个像我这样没有go背景的java程序员来说,使用go开发一个可用的程序的速度是肉眼可见的缓慢。 其难点不在于go语言本身,而是搭建整个工程链路的过程,即所谓的“配环境”。 本文主要讲述如何配出一个适合go开发的环境,以免有同…...
vue3开发高德地图
在vue3的index.html 使用动态注入地址名和key <html lang"en"><head><meta charset"UTF-8" /><link rel"icon" type"image/svgxml" href"/vite.svg" /><meta name"viewport" conten…...

通过DLL方式链接glfw3.dll
主要是CMakeLists.txt文件变化 cmake_minimum_required(VERSION 3.10) project(glfwTest) set(CMAKE_CXX_STANDARD 11) aux_source_directory(. SRC_SOURCES) set(GLFW_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) set(GLFW_LIBRARY_DIR ${CMAKE_SOURCE_DIR}/lib/glfw) add_ex…...

Python自然语言处理(NLP)库之NLTK使用详解
概要 自然语言处理(NLP)是人工智能和计算机科学中的一个重要领域,涉及对人类语言的计算机理解和处理。Python的自然语言工具包(NLTK,Natural Language Toolkit)是一个功能强大的NLP库,提供了丰富的工具和数据集,帮助开发者进行各种NLP任务,如分词、词性标注、命名实体…...

sqoop操作
介绍 sqoop是隶属于Apache旗下的, 最早是属于cloudera公司的,是一个用户进行数据的导入导出的工具, 主要是将关系型的数据库(MySQL, oracle...)导入到hadoop生态圈(HDFS,HIVE,Hbase...) , 以及将hadoop生态圈数据导出到关系型数据库中 操作 将数据从mysql中导入到HDFS中 1.全量…...

【Qt秘籍】[002]-开始你的Qt之旅-下载
一、Qt的开发工具有哪些? Qt的开发工具概述Qt支持多种开发工具,其中最常见的开发工具是 1.QtCreator 【易上手/有少量bug/适合新手】 2.VisualStudio 【功能强大/易出错/需要更多额外配置】 3.Eclipse 【清朝老兵IDE/不建议使用】 【注意࿱…...
【自动驾驶】点与向量从ego系转odometry系
1.点从ego系转odometry系(ego -> odometry) struct Point {float x;float y;float angle; }; Point trans; // is the odom to ego transform Point odom_coord; is the odom coord Point ego_coord; is the ego coordfloat odom_coord.x = (ego_coord.x - trans.x) * st…...

jsmug:一个针对JSON Smuggling技术的测试PoC环境
关于jsmug jsmug是一个代码简单但功能强大的JSON Smuggling技术环境PoC,该工具可以帮助广大研究人员深入学习和理解JSON Smuggling技术,并辅助提升Web应用程序的安全性。 背景内容 JSON Smuggling技术可以利用目标JSON文档中一些“不重要”的字节数据实…...

Qt 控件提升
什么是控件提升(Widget Promotion) 控件提升是一个在Qt编程中常见但容易被忽视的概念。简单来说,控件提升就是将一个基础控件(Base Widget)转换为一个更特定、更复杂的自定义控件(Custom Widget)…...

封装一个websocket,支持断网重连、心跳检测,拿来开箱即用
封装一个websocket,支持断网重连、心跳检测 代码封装 编写 WebSocketClient.js import { EventDispatcher } from ./dispatcherexport class WebSocketClient extends EventDispatcher {constructor(url) {console.log(url, urlurl)super()this.url url}// #soc…...

推荐一款开源电子签章/电子合同系统
文章目录 前言一、项目介绍二、项目地址三、技术架构四、代码结构介绍五、功能模块六、功能界面首页面手写签名面板电子印章制作数字证书生成 总结 前言 大家好!我是智航云科技,今天为大家分享一个免费开源的电子签字系统。 一、项目介绍 开放签电子签…...

Qt Creator(Qt 6.6)拷贝一行
Edit - Preference - Environment: 可看到,拷贝一行的快捷键是: ctrl Ins...
红队内网攻防渗透:内网渗透之数据库权限提升技术
红队内网攻防渗透 1. 内网权限提升技术1.1 数据库权限提升技术1.1.1 数据库提权流程1.1.1.1 先获取到数据库用户密码1.1.1.2 利用数据库提权工具进行连接1.1.1.3 利用建立代理解决不支持外联1.1.1.4 利用数据库提权的条件及技术1.1.2 Web到Win-数据库提权-MSSQL1.1.3 Web到Win-…...

从0开始制作微信小程序
目录 前言 正文 需要事先准备的 需要事先掌握的 什么是uniapp 平台应用的分类方式 什么是TypeScript 创建项目 项目文件作用 源码地址 尾声 🔭 Hi,I’m Pleasure1234🌱 I’m currently learning Vue.js,SpringBoot,Computer Security and so on.…...

Linux学习笔记:日志文件的编写
日志文件Log.hpp 日志文件的作用简单的日志文件编写 日志文件的作用 日志文件可以很好的帮我们显示出程序运行的信息,例如,进程pid,运行时间,运行状况等,通过日志记录程序的执行路径、变量值、函数调用等,可以帮助我们快速定位和修复代码中的错误。 简单的日志文件…...
为什么要保持方差为1
1.数值稳定性: 在机器学习和深度学习中,维持激活函数输入的方差在一个合理范围内(如1)是很重要的,这有助于防止在训练过程中发生梯度消失或梯度爆炸的问题。如果方差过大或过小,经过多层网络后输出结果的方…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...