当前位置: 首页 > news >正文

【Springboot】依赖注入方式

【Springboot】依赖注入方式

  • 【一】可选方式
    • 【1】构造器注入
    • 【2】字段注入
    • 【3】Setter注入
  • 【二】区别
    • 【1】构造器注入
    • 【2】字段注入
    • 【3】Setter注入
  • 【三】选型场景建议
    • 【1】优先构造器注入(推荐🌟)​​
    • 【2】可选字段注入​
  • 【四】⚠️ 关键注意事项
    • 【1】循环依赖陷阱​
    • 【2】final字段要求​
    • 【3】Lombok优化写法​
    • 【4】总结
  • 【五】特殊案例
    • 【1】构造器注解
      • (1)📋 Lombok构造器注解对比
      • (2)🎯 选择指南
      • (3)⚠️ 注意事项
      • (4)🎖️ 最佳实践
    • 【2】xxljob任务中使用@PostConstruct注入线程池
    • 【3】使用案例
      • (1)@AllArgsConstructor注解构造器
      • (2)构造器方法
      • (3)@Autowired注解注入

【一】可选方式

在Spring Boot项目中,依赖注入(DI)主要有三种方式:构造器注入、Setter注入和字段注入(通过@Autowired注解直接注入字段)

【1】构造器注入

通过类的构造器来注入依赖,通常在构造器上使用@Autowired注解(Spring 4.3以后,如果类只有一个构造器,可以省略@Autowired)。

@Service
public class MyService {private final RedisTemplate<String, String> redisTemplate;private final RedissonClient redissonClient;public MyService(RedisTemplate<String, String> redisTemplate, RedissonClient redissonClient) {this.redisTemplate = redisTemplate;this.redissonClient = redissonClient;}
}

【2】字段注入

直接在字段上使用@Autowired注解。

@Service
public class MyService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Autowiredprivate RedissonClient redissonClient;
}

【3】Setter注入

通过在Setter方法上使用@Autowired注解。

@Service
public class MyService {private RedisTemplate<String, String> redisTemplate;private RedissonClient redissonClient;@Autowiredpublic void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {this.redisTemplate = redisTemplate;}@Autowiredpublic void setRedissonClient(RedissonClient redissonClient) {this.redissonClient = redissonClient;}
}

【二】区别

【1】构造器注入

(1)不可变性​:依赖字段可以被声明为final,这意味着一旦对象被创建,这些依赖就不会被改变。这有助于保证依赖的不可变性和线程安全。
(2)强制依赖​:构造器注入要求依赖在对象创建时就必须提供,确保对象被完整地初始化。这样,在使用对象时,所有依赖都已经被设置,避免了空指针异常。
(3)​循环依赖​:如果使用构造器注入,Spring在启动时就能发现循环依赖问题(会抛出BeanCurrentlyInCreationException),而不是等到运行时。
(4)​测试友好​:在单元测试中,你可以直接通过构造器传入依赖的模拟对象(Mock对象),而不需要Spring容器。

【2】字段注入

(1)​简洁​:代码简洁,不需要写构造器或Setter方法。
(2)灵活性​:但是,字段注入使得依赖可以被随意更改(除非使用反射,但通常不推荐),因此不够安全。
(3)​不可变​:字段不能声明为final(因为注入是容器在对象创建后通过反射设置的),所以不能保证不可变性。
(4)隐藏依赖​:一个类可能有很多依赖,但它们都隐藏在类中,不容易从外部发现。而构造器可以明确地展示一个类需要哪些依赖。

【3】Setter注入

(1)​可选依赖​:适合那些不是必须的依赖,或者可能需要更换的依赖。Setter注入允许在对象创建后重新注入依赖。
(2)灵活性​:可以在对象创建后改变依赖,但通常我们不希望这样,因为这可能导致状态不一致。
(3)不可变性​:同样,不能将字段设置为final。

在这里插入图片描述

【三】选型场景建议

【1】优先构造器注入(推荐🌟)​​

(1)​适用场景​:
强制依赖(如RedisTemplate、线程池等基础设施)
需不可变状态的组件(如Service层、Util工具类)
高安全要求场景(避免NPE)
需要脱离容器进行单元测试的类
(2)示例代码​:

@Service
public class OrderService {private final RedisTemplate<String, Object> redisTemplate;private final RedissonClient redissonClient;// 构造器注入(Spring 4.3+可省略@Autowired)public OrderService(RedisTemplate<String, Object> redisTemplate, RedissonClient redissonClient) {this.redisTemplate = redisTemplate;this.redissonClient = redissonClient;}
}

【2】可选字段注入​

(1)适用场景​:
原型(Prototype)作用域的Bean
可选依赖(如@Autowired(required=false))
遗留代码维护(渐进式改造)
临时调试场景
​(2)示例代码​:

@Component
public class PaymentProcessor {@Autowired  // 字段注入private RedisTemplate<String, Double> redisTemplate;
}

【四】⚠️ 关键注意事项

【1】循环依赖陷阱​

构造器注入:强制在启动时暴露循环依赖问题(如A→B→A),​推荐提前解耦。
字段注入:可能通过三级缓存延迟解决,但会掩盖设计问题。

【2】final字段要求​

构造器注入允许依赖字段定义为final(线程安全+不变性),而字段注入不可用final。

【3】Lombok优化写法​

结合@RequiredArgsConstructor简化构造器注入:

@Service
@RequiredArgsConstructor // 为final字段自动生成构造器
public class InventoryService {private final RedissonClient redissonClient;private final ExecutorService bulkTaskExecutor;
}

【4】总结

请添加图片描述

【五】特殊案例

【1】构造器注解

Lombok提供了几个用于生成构造器的注解,它们在不同场景下使用,主要区别在于生成的构造器的访问权限和包含的字段。以下是常见的几个构造器注解及其区别:

(1)📋 Lombok构造器注解对比

(1)@NoArgsConstructor:生成一个无参构造器。
参数:access(访问权限,如AccessLevel.PUBLIC、AccessLevel.PRIVATE等)、force(如果设置为true,则所有final字段都会被初始化为0/false/null,常用于JPA和Hibernate)等。

(2)@RequiredArgsConstructor:生成一个包含所有必需参数的构造器。必需的参数是指所有final字段和带有@NonNull注解且未初始化的字段。

参数:access(访问权限)、staticName(如果设置,则生成一个静态工厂方法,而不是公共构造器)等。

(3)@AllArgsConstructor:生成一个包含所有非静态字段的构造器(每个字段都是一个参数)。

参数:access(访问权限)、staticName(静态工厂方法)等。

(4)@Builder:使用建造者模式生成一个构造器,实际上会生成一个建造者类和一个私有构造器(通过建造者类来构造对象)。

(5)@Data:这是一个组合注解,包含@Getter、@Setter、@ToString、@EqualsAndHashCode和@RequiredArgsConstructor。

(2)🎯 选择指南

(1)如果你需要一个无参构造器(比如某些框架需要),使用@NoArgsConstructor。
(2)如果你只需要一个包含final字段和@NonNull字段的构造器,使用@RequiredArgsConstructor。这在依赖注入时特别有用,尤其是通过构造器注入时。
(3)如果你需要包含所有字段的构造器,使用@AllArgsConstructor。
(4)如果你想要更灵活的对象构建方式(特别是很多可选参数时),使用@Builder。

注意:如果类中有final字段,且没有使用@NoArgsConstructor并且设置了force=true,那么必须确保这些字段在无参构造器中有默认值(通过force=true可以强制初始化为默认值,但通常不推荐,除非必要如JPA)。

(3)⚠️ 注意事项

(1)字段顺序问题​:@AllArgsConstructor的参数顺序与字段声明顺序一致,可能带来隐晦问题
(2)与JPA的配合​:JPA实体需要无参构造器,可使用@NoArgsConstructor(access = AccessLevel.PROTECTED)
(3)final字段处理​:@NoArgsConstructor需要与force = true配合才能处理final字段
(4)继承问题​:父类的构造器不会被Lombok注解影响,需要单独处理
(5)与MapStruct配合​:构造器注解可以帮助MapStruct更好地生成映射代码

(4)🎖️ 最佳实践

(1)Spring项目优先使用@RequiredArgsConstructor进行依赖注入
(2)实体类使用@NoArgsConstructor和@AllArgsConstructor满足JPA和业务需求
(3)​复杂对象创建使用@Builder提高代码可读性
(4)考虑使用staticName参数创建更有意义的静态工厂方法

【2】xxljob任务中使用@PostConstruct注入线程池

在Spring Boot项目中整合XXL-Job,并在调度任务中使用@PostConstruct注解完成线程池的注入,需要注意以下几点:

(1)XXL-Job的执行器(JobHandler)是由XXL-Job框架通过反射创建的,因此Spring的依赖注入无法直接通过构造函数或字段注入生效。
(2)我们可以通过将JobHandler交由Spring管理,并在JobHandler中使用@PostConstruct注解来初始化线程池或其他依赖。

实现步骤:
(1)在项目中配置XXL-Job执行器。
(2)创建一个JobHandler,并使用@Component注解将其交由Spring管理。
(3)在JobHandler中,使用@PostConstruct注解的方法来初始化线程池。

注意:由于XXL-Job框架会自己实例化JobHandler,所以我们需要在XXL-Job的配置中指定使用Spring容器中的JobHandler Bean,而不是让XXL-Job自己new一个实例。

但是,XXL-Job的默认行为是自行实例化,因此我们需要通过某种方式将Spring容器中的Bean注入到XXL-Job的调度中心。这通常可以通过在XXL-Job的配置中设置JobHandler的Bean名称,并在Spring容器中注册该Bean。

@Component
public class SampleXxlJob {// 线程池实例private ExecutorService asyncTaskExecutor;// 使用@PostConstruct确保Spring容器初始化完成后创建线程池@PostConstructpublic void init() {// 创建自定义线程池asyncTaskExecutor = new ThreadPoolExecutor(5,      // 核心线程数10,     // 最大线程数60L,    // 空闲线程存活时间TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),  // 任务队列new ThreadFactoryBuilder().setNameFormat("async-task-%d").build(), // 线程命名new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略);log.info("线程池初始化完成,核心线程数:{},最大线程数:{}", 5, 10);}@PreDestroypublic void destroy() {if (asyncTaskExecutor != null) {asyncTaskExecutor.shutdown();log.info("线程池已关闭");}}/*** 示例任务 - 使用线程池处理异步任务*/@XxlJob("demoJobHandler")public void demoJobHandler() throws Exception {XxlJobHelper.log("XXL-JOB开始执行,准备提交任务到线程池");// 创建任务列表List<Callable<String>> tasks = new ArrayList<>();for (int i = 0; i < 20; i++) {final int taskId = i;tasks.add(() -> {try {// 模拟业务处理Thread.sleep(1000);XxlJobHelper.log("任务{}执行完成,线程:{}", taskId, Thread.currentThread().getName());return "Task-" + taskId + "-Success";} catch (InterruptedException e) {Thread.currentThread().interrupt();return "Task-" + taskId + "-Failed";}});}// 提交所有任务到线程池List<Future<String>> futures = asyncTaskExecutor.invokeAll(tasks);// 等待所有任务完成for (Future<String> future : futures) {try {String result = future.get(2, TimeUnit.SECONDS);XxlJobHelper.log("任务结果: {}", result);} catch (TimeoutException e) {XxlJobHelper.log("任务超时");} catch (Exception e) {XxlJobHelper.log("任务执行异常: {}", e.getMessage());}}XxlJobHelper.log("XXL-JOB执行完成,共处理{}个任务", tasks.size());}/*** 另一个示例任务 - 分片广播任务*/@XxlJob("shardingJobHandler")public void shardingJobHandler() throws Exception {// 分片参数int shardIndex = XxlJobHelper.getShardIndex();int shardTotal = XxlJobHelper.getShardTotal();XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);// 模拟分片数据处理List<String> dataList = fetchDataByShard(shardIndex, shardTotal);// 使用线程池并行处理分片数据List<CompletableFuture<Void>> futures = dataList.stream().map(data -> CompletableFuture.runAsync(() -> {processData(data);}, asyncTaskExecutor)).collect(Collectors.toList());// 等待所有任务完成CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();XxlJobHelper.log("分片任务完成,处理{}条数据", dataList.size());}private List<String> fetchDataByShard(int shardIndex, int shardTotal) {// 模拟根据分片参数获取数据List<String> allData = IntStream.range(0, 100).mapToObj(i -> "Data-" + i).collect(Collectors.toList());// 分片处理return IntStream.range(0, allData.size()).filter(i -> i % shardTotal == shardIndex).mapToObj(allData::get).collect(Collectors.toList());}private void processData(String data) {try {// 模拟数据处理Thread.sleep(500);XxlJobHelper.log("处理数据: {},线程: {}", data, Thread.currentThread().getName());} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

【3】使用案例

(1)@AllArgsConstructor注解构造器

package com.allen.study.application.api;import com.allen.study.application.elasticSearch.ElasticsearchTemplateUtil;
import com.allen.study.application.elasticSearch.es_entity.ProductES;
import com.allen.study.common.base.ApiResponse;
import com.allen.study.common.utils.CamundaUtils;
import com.allen.study.common.utils.ThreadPoolConfig;
import com.allen.study.common.utils.datax.DataXUtils;
import com.allen.study.common.utils.kafka.KafkaUtils;
import com.allen.study.common.utils.redis.*;
import com.allen.study.common.utils.uuid.IdUtils;
import com.allen.study.domain.repository.IEmployeeInfoRepo;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 用户信息表测试对象注入接口** @author AllenSun* @since 2025-02-26 23:58*/
@RequestMapping(value = "/4.2.0/testdi")
@RestController
@AllArgsConstructor
@Tag(name = "用户信息表测试对象注入接口", description = "用户信息表测试对象注入接口")
@Slf4j
public class EmployeeInfoTestDIApi {// 布隆过滤器private final BloomFilterUtil bloomFilterUtil;private final RedisTemplate redisTemplate;private final RedisLock redisLock;private final RedisUtils redisUtils;private final RedisUtils2 redisUtils2;private final RedissonConfig redissonConfig;private final ElasticsearchTemplateUtil elasticsearchTemplateUtil;private final ElasticsearchRestTemplate elasticsearchRestTemplate;private final DataXUtils dataXUtils;private final KafkaUtils kafkaUtils;private final ThreadPoolConfig threadPoolConfig;private final IEmployeeInfoRepo employeeInfoRepo;@GetMapping("")public ApiResponse<String> batchInitEmps() {boolean mightContain = bloomFilterUtil.mightContain("1111111");List<String> queryAllIdList = employeeInfoRepo.queryAllIdList();Object redisVal01 = redisTemplate.opsForValue().get("111");Object redisVal02 = redisUtils.get("111");Object redisVal03 = redisUtils2.get("111");RLock rLock01 = redisLock.getRLock("lockKey01");RLock rLock02 = redissonConfig.redissonClient().getLock("lockKey02");long documentCount = elasticsearchTemplateUtil.getDocumentCount(ProductES.class);int hashCode = elasticsearchRestTemplate.hashCode();int i = dataXUtils.hashCode();int i1 = kafkaUtils.hashCode();boolean processDefinitionExists = CamundaUtils.isProcessDefinitionExists("111");String uuid = IdUtils.randomUUID();int poolSize = threadPoolConfig.customThreadPool().getPoolSize();return ApiResponse.ok();}}

(2)构造器方法

package com.allen.study.application.api;import com.allen.study.application.elasticSearch.ElasticsearchTemplateUtil;
import com.allen.study.application.elasticSearch.es_entity.ProductES;
import com.allen.study.common.base.ApiResponse;
import com.allen.study.common.utils.CamundaUtils;
import com.allen.study.common.utils.ThreadPoolConfig;
import com.allen.study.common.utils.datax.DataXUtils;
import com.allen.study.common.utils.kafka.KafkaUtils;
import com.allen.study.common.utils.redis.*;
import com.allen.study.common.utils.uuid.IdUtils;
import com.allen.study.domain.repository.IEmployeeInfoRepo;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 用户信息表测试对象注入接口** @author AllenSun* @since 2025-02-26 23:58*/
@RequestMapping(value = "/4.2.0/testdi")
@RestController
// @AllArgsConstructor
@Tag(name = "用户信息表测试对象注入接口", description = "用户信息表测试对象注入接口")
@Slf4j
public class EmployeeInfoTestDIApi {private final BloomFilterUtil bloomFilterUtil;private final RedisTemplate redisTemplate;private final RedisLock redisLock;private final RedisUtils redisUtils;private final RedisUtils2 redisUtils2;private final RedissonConfig redissonConfig;private final ElasticsearchTemplateUtil elasticsearchTemplateUtil;private final ElasticsearchRestTemplate elasticsearchRestTemplate;private final DataXUtils dataXUtils;private final KafkaUtils kafkaUtils;private final ThreadPoolConfig threadPoolConfig;private final IEmployeeInfoRepo employeeInfoRepo;public EmployeeInfoTestDIApi(BloomFilterUtil bloomFilterUtil, RedisTemplate redisTemplate, RedisLock redisLock, RedisUtils redisUtils, RedisUtils2 redisUtils2, RedissonConfig redissonConfig, ElasticsearchTemplateUtil elasticsearchTemplateUtil, ElasticsearchRestTemplate elasticsearchRestTemplate, DataXUtils dataXUtils, KafkaUtils kafkaUtils, ThreadPoolConfig threadPoolConfig, IEmployeeInfoRepo employeeInfoRepo) {this.bloomFilterUtil = bloomFilterUtil;this.redisTemplate = redisTemplate;this.redisLock = redisLock;this.redisUtils = redisUtils;this.redisUtils2 = redisUtils2;this.redissonConfig = redissonConfig;this.elasticsearchTemplateUtil = elasticsearchTemplateUtil;this.elasticsearchRestTemplate = elasticsearchRestTemplate;this.dataXUtils = dataXUtils;this.kafkaUtils = kafkaUtils;this.threadPoolConfig = threadPoolConfig;this.employeeInfoRepo = employeeInfoRepo;}@GetMapping("")public ApiResponse<String> batchInitEmps() {boolean mightContain = bloomFilterUtil.mightContain("1111111");List<String> queryAllIdList = employeeInfoRepo.queryAllIdList();Object redisVal01 = redisTemplate.opsForValue().get("111");Object redisVal02 = redisUtils.get("111");Object redisVal03 = redisUtils2.get("111");RLock rLock01 = redisLock.getRLock("lockKey01");RLock rLock02 = redissonConfig.redissonClient().getLock("lockKey02");long documentCount = elasticsearchTemplateUtil.getDocumentCount(ProductES.class);int hashCode = elasticsearchRestTemplate.hashCode();int i = dataXUtils.hashCode();int i1 = kafkaUtils.hashCode();boolean processDefinitionExists = CamundaUtils.isProcessDefinitionExists("111");String uuid = IdUtils.randomUUID();int poolSize = threadPoolConfig.customThreadPool().getPoolSize();return ApiResponse.ok();}}

(3)@Autowired注解注入

package com.allen.study.application.api;import com.allen.study.application.elasticSearch.ElasticsearchTemplateUtil;
import com.allen.study.application.elasticSearch.es_entity.ProductES;
import com.allen.study.common.base.ApiResponse;
import com.allen.study.common.utils.CamundaUtils;
import com.allen.study.common.utils.ThreadPoolConfig;
import com.allen.study.common.utils.datax.DataXUtils;
import com.allen.study.common.utils.kafka.KafkaUtils;
import com.allen.study.common.utils.redis.*;
import com.allen.study.common.utils.uuid.IdUtils;
import com.allen.study.domain.repository.IEmployeeInfoRepo;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** 用户信息表测试对象注入接口** @author AllenSun* @since 2025-02-26 23:58*/
@RequestMapping(value = "/4.2.0/testdi")
@RestController
// @AllArgsConstructor
@Tag(name = "用户信息表测试对象注入接口", description = "用户信息表测试对象注入接口")
@Slf4j
public class EmployeeInfoTestDIApi {@Autowiredprivate BloomFilterUtil bloomFilterUtil;@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate RedisLock redisLock;@Autowiredprivate RedisUtils redisUtils;@Autowiredprivate RedisUtils2 redisUtils2;@Autowiredprivate RedissonConfig redissonConfig;@Autowiredprivate ElasticsearchTemplateUtil elasticsearchTemplateUtil;@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Autowiredprivate DataXUtils dataXUtils;@Autowiredprivate KafkaUtils kafkaUtils;@Autowiredprivate ThreadPoolConfig threadPoolConfig;@Autowiredprivate IEmployeeInfoRepo employeeInfoRepo;@GetMapping("")public ApiResponse<String> batchInitEmps() {boolean mightContain = bloomFilterUtil.mightContain("1111111");List<String> queryAllIdList = employeeInfoRepo.queryAllIdList();Object redisVal01 = redisTemplate.opsForValue().get("111");Object redisVal02 = redisUtils.get("111");Object redisVal03 = redisUtils2.get("111");RLock rLock01 = redisLock.getRLock("lockKey01");RLock rLock02 = redissonConfig.redissonClient().getLock("lockKey02");long documentCount = elasticsearchTemplateUtil.getDocumentCount(ProductES.class);int hashCode = elasticsearchRestTemplate.hashCode();int i = dataXUtils.hashCode();int i1 = kafkaUtils.hashCode();boolean processDefinitionExists = CamundaUtils.isProcessDefinitionExists("111");String uuid = IdUtils.randomUUID();int poolSize = threadPoolConfig.customThreadPool().getPoolSize();return ApiResponse.ok();}
}
http://www.xdnf.cn/news/1363069.html

相关文章:

  • Linux 离线安装lrzsz(rz、sz上传下载小插件)
  • IntelliJ IDEA 新手入门教程-Java、Web、Maven创建(带图解)
  • 疯狂星期四文案网第49天运营日记
  • 使用现代 <img> 元素实现完美图片效果(2025 深度实战版)
  • 【图像处理基石】基于Real-ESRGAN的实时图像超分辨率技术实现
  • MongoDB vs MySQL:NoSQL 和 SQL 的核心区别与适用场景
  • Portswigger靶场之Visible error-based SQL injection通关秘籍
  • ADQ3系列USB 3.2接口版本数字化仪隆重登场
  • 将本地jar包推到远程仓库
  • KeepAlived+Haproxy实现负载均衡(SLB)
  • 集成电路学习:什么是Caffe深度学习框架
  • 聊聊负载均衡架构
  • OpenGL 几何着色器
  • Linux学习-TCP网络协议(补充)
  • ViT系列网络系统性分析:从架构创新到未来趋势
  • [QMT量化交易小白入门]-八十四、LSTM模型对期货市场的秒级Tick数据进行预测
  • AI背后使用的技术
  • 《信息检索与论文写作》实验报告一 EI数据库检索
  • 【文献阅读】SparseGPT: Massive Language Models Can be Accurately Pruned in One-Shot
  • ios webgl音频问题
  • 设置密钥连接服务器
  • Charles安装到使用全流程教程
  • Gemini 2.5 Flash-Lite 与 GPT-5-mini:高性能低成本模型,如何选择?
  • 第十七节:高级材质 - ShaderMaterial揭秘
  • 物联网时序数据库IoTDB架构解析
  • h5和微信小程序查看pdf文件
  • DrissionPage 能控制火狐或edge吗
  • 20.14 QLoRA微调Whisper-Large-v2终极指南:3倍速训练+显存直降68%调参秘籍
  • ADB 调试工具的学习[特殊字符]
  • 【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(2):智慧城市西安与一带一路