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

Java基础 | SpringBoot实现自启动的方式

Java基础 | SpringBoot实现自启动的方式

  • 一、什么是自启动?
  • 二、方式一:@PostConstruct注解(常用度★★★★★)
    • 场景一:初始化当前Bean的内部状态或变量(加载专属配置)
    • 场景二:校验当前Bean的依赖是否合法
    • 场景三:注册当前Bean的内部监听器
    • 场景四:执行当前Bean的预加载逻辑
  • 三、方式二:CommandLineRunner接口(常用度★★★★)
    • 场景一:初始化全局共享资源(所有服务可用)
    • 场景二:根据命令行参数执行特定操作
    • 场景三:启动全局定时任务
    • 场景四:执行跨Bean的初始化逻辑
  • 四、方式三:ApplicationRunner接口(常用度★★★)
    • 场景一:根据命名参数切换环境配置
    • 场景二:处理带键的复杂参数
    • 场景三:处理多值参数
  • 五、方式四:监听Spring容器事件(常用度★★★)
    • 场景一:`ApplicationReadyEvent`(应用完全就绪):通知外部系统应用已启动
    • 场景二:`ContextRefreshedEvent`(容器刷新完成):扫描所有Bean并检查规范
    • 场景三:`ApplicationReadyEvent`(应用完全就绪):打印应用启动最终信息
    • 场景四:`ContextRefreshedEvent`(容器刷新完成):注册全局Bean监听器
  • 六、方式五:SmartInitializingSingleton接口(常用度★★)
    • 场景一:收集所有实现特定接口的Bean(构建策略工厂)
    • 场景二:对所有单例Bean执行统一初始化操作
    • 场景三:校验所有单例Bean的依赖关系
  • 七、方式六:自定义init-method(常用度★)
    • 场景一:@Bean注解指定初始化方法(替代XML配置)
    • 场景二:XML配置中指定初始化方法(老项目)
    • 场景三:框架源码中显式指定初始化方法
  • 总结

一、什么是自启动?

在SpringBoot项目中,“自启动”指的是应用程序在启动过程中或启动完成后,自动执行特定方法的机制。
这些方法无需手动触发,通常用于完成初始化操作(如加载配置、初始化缓存)、执行启动任务(如数据同步、服务注册)等,确保应用就绪后处于预期的运行状态。

二、方式一:@PostConstruct注解(常用度★★★★★)

项目常用度:★★★★★(最常用)

特点

  • 属于JSR-250 Java标准注解,不依赖Spring特定API,通用性强;
  • 执行时机:单个Bean的构造方法执行后→依赖注入(@Autowired等)完成后,仅针对当前Bean执行;
  • 多个Bean的@PostConstruct方法执行顺序与Bean加载顺序相关(无依赖时顺序不确定,无法通过@Order控制);
  • 方法无参数、无返回值,方法名可自定义。

涉及场景(按常用度排序)

场景一:初始化当前Bean的内部状态或变量(加载专属配置)

当Bean需要加载自身专属的配置参数或初始化内部变量时,@PostConstruct能确保在依赖注入完成后执行,避免空指针。

具体例子

@Component
public class PaymentConfig {@Value("${payment.timeout:3000}") // 从配置文件取值,默认3000msprivate int payTimeout;private long payTimeoutMillis; // 内部变量(转换为毫秒)// 依赖注入完成后,初始化内部变量@PostConstructpublic void initTimeout() {this.payTimeoutMillis = payTimeout * 1000L; // 转换为毫秒System.out.println("PaymentConfig初始化:支付超时时间 = " + this.payTimeoutMillis + "ms");}// 提供获取方法供其他地方使用public long getPayTimeoutMillis() {return payTimeoutMillis;}
}

场景二:校验当前Bean的依赖是否合法

当Bean依赖其他组件时,需确保依赖已正确注入,避免后续使用中出现空指针,@PostConstruct可用于依赖校验。

@Autowired(required = false) 该做法不提倡,在特定场景下不得不使用,加上以后就相当于这个对象可用可不用。
以下只为用于举例说明,意思就是可以告诉你可以通过@PostConstruct去判断一下这个对象是否可用。

具体例子

@Component
public class OrderService {@Autowired(required = false) // required = false 表示:能找到就塞进来,找不到也不报错,会赋予为nullprivate OrderMapper orderMapper;// 校验依赖是否存在@PostConstructpublic void checkDependencies() {if (orderMapper == null) {throw new IllegalStateException("OrderService依赖的OrderMapper未注入!请检查配置");}if (orderMapper != null) { //不为null,就可以执行这个里面的方法orderMapper.xxxx();}}
}

场景三:注册当前Bean的内部监听器

某些Bean需要在初始化后注册自身的内部监听器(如缓存过期监听),@PostConstruct能保证监听器在Bean可用时正确注册。

具体例子

@Component
public class CacheService {private final LocalCache localCache = new LocalCache(); // 内部缓存// 注册缓存过期监听器(仅当前Bean的缓存生效)@PostConstructpublic void registerCacheListener() {localCache.addExpireListener((key, value) -> {System.out.println("缓存" + key + "已过期,值:" + value);// 执行过期后的处理(如重新加载)});System.out.println("CacheService初始化:已注册缓存过期监听器");}
}

场景四:执行当前Bean的预加载逻辑

对于需要预先加载少量数据(仅当前Bean使用)的场景,可通过@PostConstruct在Bean初始化后执行预加载。

具体例子

@Component
public class DictService {@Autowiredprivate DictMapper dictMapper;private Map<String, String> genderDict; // 仅当前Bean使用的性别字典缓存@PostConstructpublic void preloadGenderDict() {// 预加载性别字典(仅当前Bean业务用)genderDict = dictMapper.selectByType("gender").stream().collect(Collectors.toMap(Dict::getCode, Dict::getName));System.out.println("DictService预加载性别字典:" + genderDict);}public String getGenderName(String code) {return genderDict.getOrDefault(code, "未知");}
}

三、方式二:CommandLineRunner接口(常用度★★★★)

项目常用度:★★★★☆(非常常用)

特点

  • SpringBoot提供的接口,执行时机:应用启动完成后(所有Bean初始化就绪)
  • 接收原始命令行参数(String[] args),可根据参数执行不同操作;
  • 支持通过@Order注解指定多个实现类的执行顺序(值越小越先执行)。

涉及场景(按常用度排序)

场景一:初始化全局共享资源(所有服务可用)

应用启动后,需初始化全局共享的缓存、配置等资源(供多个服务使用),CommandLineRunner适合这种全局初始化。

具体例子

@Component
@Order(1)
public class GlobalDictRunner implements CommandLineRunner {@Autowiredprivate DictMapper dictMapper;@Autowiredprivate RedisTemplate<String, Object> redisTemplate; // 全局缓存(Redis)@Overridepublic void run(String... args) throws Exception {System.out.println("开始初始化全局字典缓存...");// 查询所有字典数据(依赖dictMapper就绪)List<Dict> allDicts = dictMapper.selectAll();// 存入Redis(所有服务可通过Redis获取)redisTemplate.opsForValue().set("GLOBAL:DICTS", allDicts);System.out.println("全局字典缓存初始化完成,共" + allDicts.size() + "条数据");}
}

场景二:根据命令行参数执行特定操作

启动时可通过命令行参数(如java -jar app.jar initDb)触发特定初始化(如数据库初始化),CommandLineRunner能方便处理这些参数。

具体例子

@Component
@Order(2)
public class DbInitRunner implements CommandLineRunner {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void run(String... args) throws Exception {// 命令行参数包含"initDb"时执行初始化if (Arrays.asList(args).contains("initDb")) {System.out.println("开始执行数据库初始化...");// 创建基础表jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS sys_log (id BIGINT PRIMARY KEY AUTO_INCREMENT, content VARCHAR(255))");// 插入初始数据jdbcTemplate.update("INSERT INTO sys_log (content) VALUES (?)", "系统启动初始化日志");System.out.println("数据库初始化完成");}}
}

场景三:启动全局定时任务

应用中常需要全局定时任务(如日志清理、数据同步),这些任务依赖多个业务Bean就绪,CommandLineRunner可在启动后启动任务。

具体例子

@Component
@Order(3)
public class ScheduledTaskRunner implements CommandLineRunner {@Autowiredprivate ScheduledExecutorService scheduler;@Autowiredprivate LogCleanService logCleanService; // 日志清理服务@Overridepublic void run(String... args) throws Exception {System.out.println("启动全局定时任务...");// 每天凌晨3点执行日志清理(依赖logCleanService就绪)scheduler.scheduleAtFixedRate(() -> logCleanService.cleanExpiredLogs(30), // 清理30天前的日志0, 1, TimeUnit.DAYS);System.out.println("全局定时任务启动完成:每天凌晨3点清理过期日志");}
}

定时任务可替代方案:

  • 使用 CompletableFuture.runAsync+自定义线程池
  • 使用 @Async+@EnableAsync+自定义线程池

场景四:执行跨Bean的初始化逻辑

当初始化需要多个Bean协作时,CommandLineRunner能确保所有参与Bean就绪,顺利执行跨Bean操作。

具体例子

@Component
@Order(4)
public class CrossBeanInitRunner implements CommandLineRunner {@Autowiredprivate UserService userService;@Autowiredprivate RoleService roleService;@Overridepublic void run(String... args) throws Exception {System.out.println("执行跨Bean初始化:为默认用户分配角色");// 依赖userService和roleService都已就绪User defaultUser = userService.getDefaultUser();Role adminRole = roleService.getAdminRole();userService.assignRole(defaultUser.getId(), adminRole.getId());System.out.println("跨Bean初始化完成:默认用户已分配管理员角色");}
}

四、方式三:ApplicationRunner接口(常用度★★★)

项目常用度:★★★☆☆(较常用)

特点

  • 与CommandLineRunner功能类似,执行时机相同(应用启动完成后,所有Bean就绪);
  • 区别:接收ApplicationArguments对象,支持解析命名参数(如--env=dev--type=test),参数处理更灵活;
  • 支持通过@Order注解控制执行顺序。

涉及场景(按常用度排序)

场景一:根据命名参数切换环境配置

多环境部署时,通过命名参数指定环境(如生产、测试),ApplicationRunner能方便解析并切换配置。

启动命令:java -jar app.jar --syncType=user --pageSize=100

具体例子

@Component
public class EnvConfigRunner implements ApplicationRunner {@Autowiredprivate ConfigService configService;@Overridepublic void run(ApplicationArguments args) throws Exception {// 获取命名参数--env的值(如--env=prod → [prod])List<String> envList = args.getOptionValues("env");if (envList != null && envList.contains("prod")) {configService.loadProdConfig(); // 加载生产环境配置System.out.println("已加载生产环境配置");} else if (envList != null && envList.contains("test")) {configService.loadTestConfig(); // 加载测试环境配置System.out.println("已加载测试环境配置");}}
}

可替代方案
使用 Spring Boot 原生支持的–spring.profiles.active=env参数,直接激活环境(无需自定义 Runner),官方推荐且更简洁:

java -jar myapp.jar --spring.profiles.active=prod # 直接激活生产环境

场景二:处理带键的复杂参数

当命令行参数为键值对形式(如指定同步类型、分页大小)时,ApplicationRunner解析更清晰。

具体例子

@Component
public class ComplexParamRunner implements ApplicationRunner {@Autowiredprivate DataSyncService syncService;@Overridepublic void run(ApplicationArguments args) throws Exception {// 获取命名参数--syncType和--pageSizeList<String> syncTypeList = args.getOptionValues("syncType");List<String> pageSizeList = args.getOptionValues("pageSize");if (syncTypeList != null && !syncTypeList.isEmpty() && pageSizeList != null && !pageSizeList.isEmpty()) {String syncType = syncTypeList.get(0);int pageSize = Integer.parseInt(pageSizeList.get(0));System.out.println("开始同步:类型=" + syncType + ",分页大小=" + pageSize);syncService.sync(syncType, pageSize);}}
}

最优替代方案
通过@ConfigurationProperties将命令行参数绑定到实体类,参数管理更规范,尤其适合参数较多的场景:

启动命令:java -jar app.jar --syncType=user --pageSize=100

@ConfigurationProperties(prefix = "") // 绑定根级参数
public class SyncParams {private String syncType;private int pageSize;// getters/setters
}// 使用时直接注入
@Component
public class SyncService {@Autowiredprivate SyncParams syncParams; // 直接使用参数
}

场景三:处理多值参数

对于同一键对应多个值的参数(如--ids=1 --ids=2),ApplicationRunner能直接获取所有值,无需手动解析。

具体例子

@Component
public class MultiParamSyncRunner implements ApplicationRunner {@Autowiredprivate DataSyncService syncService;@Overridepublic void run(ApplicationArguments args) throws Exception {// 获取多值参数--syncTypes(如--syncTypes=user --syncTypes=order → [user, order])List<String> syncTypes = args.getOptionValues("syncTypes");if (syncTypes != null) {System.out.println("开始同步类型:" + syncTypes);syncService.syncByTypes(syncTypes); // 按类型同步数据}}
}

最优替代方案:
同场景二,通过@ConfigurationProperties绑定到List类型,更符合 “面向对象” 编程习惯,参数访问更直观。

五、方式四:监听Spring容器事件(常用度★★★)

项目常用度:★★★☆☆(中等常用)

特点

  • 基于Spring事件发布/监听机制,可监听容器启动特定阶段的事件;
  • 常用事件(按执行顺序):
    • ContextRefreshedEvent:容器刷新完成(所有单例Bean就绪);
    • ApplicationStartedEvent:SpringBoot启动完成(容器就绪,Runner未执行);
    • ApplicationReadyEvent:应用完全就绪(所有Runner执行完成);
  • 可通过@EventListener注解或实现ApplicationListener接口实现监听。

涉及场景(按常用度排序)

场景一:ApplicationReadyEvent(应用完全就绪):通知外部系统应用已启动

应用完全就绪后,需通知外部系统(如服务发现中心、监控系统),以便外部系统感知应用状态。

具体例子

@Component
public class ServiceRegistryListener {@Autowiredprivate EurekaClient eurekaClient;@Value("${spring.application.name}")private String appName;@Value("${server.port}")private int port;// 应用完全就绪后,注册到Eureka@EventListener(ApplicationReadyEvent.class)public void registerToEureka(ApplicationReadyEvent event) {InstanceInfo instance = InstanceInfo.Builder.newBuilder().setAppName(appName).setHostName("localhost").setPort(port).setStatus(InstanceStatus.UP).build();eurekaClient.registerInstance(appName, instance);System.out.println("应用" + appName + "已注册到Eureka,端口:" + port);}
}

最优替代方案:
服务发现中心(如 Nacos、Eureka)提供自动注册机制,通过配置spring.cloud.nacos.discovery.server-addr等参数即可自动注册,无需手动监听事件,更可靠且无需重复开发。

场景二:ContextRefreshedEvent(容器刷新完成):扫描所有Bean并检查规范

容器刷新完成后,所有单例Bean已就绪,可扫描Bean检查是否符合项目规范(如特定注解是否添加)。

具体例子

@Component
public class BeanCheckListener {// 容器刷新完成后,检查所有@Service是否加了@Transactional@EventListener(ContextRefreshedEvent.class)public void checkServiceAnnotations(ContextRefreshedEvent event) {ApplicationContext context = event.getApplicationContext();// 获取所有@Service注解的BeanMap<String, Object> serviceBeans = context.getBeansWithAnnotation(Service.class);for (Map.Entry<String, Object> entry : serviceBeans.entrySet()) {Class<?> beanClass = entry.getValue().getClass();if (!beanClass.isAnnotationPresent(Transactional.class)) {System.out.println("警告:Service Bean " + entry.getKey() + " 未加@Transactional注解");}}System.out.println("Bean规范检查完成");}
}

场景三:ApplicationReadyEvent(应用完全就绪):打印应用启动最终信息

应用完全就绪后,打印启动耗时、环境信息等日志,方便了解启动情况。

具体例子

@Component
public class StartupInfoListener {@Value("${spring.profiles.active:default}")private String activeProfile;@EventListener(ApplicationReadyEvent.class)public void printStartupInfo(ApplicationReadyEvent event) {long startupTime = System.currentTimeMillis() - event.getTimestamp();System.out.println("======================================");System.out.println("应用启动完成!");System.out.println("环境:" + activeProfile);System.out.println("启动耗时:" + startupTime + "ms");System.out.println("======================================");}
}

场景四:ContextRefreshedEvent(容器刷新完成):注册全局Bean监听器

容器刷新完成后,可注册全局监听器,监听所有Bean的创建、销毁等事件,用于全局监控。

具体例子

@Component
public class GlobalBeanListener {@EventListener(ContextRefreshedEvent.class)public void registerGlobalListener(ContextRefreshedEvent event) {ApplicationContext context = event.getApplicationContext();// 获取Bean工厂ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();// 注册全局Bean后置处理器(监听Bean初始化)beanFactory.addBeanPostProcessor(new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean初始化完成:" + beanName);return bean;}});System.out.println("全局Bean监听器注册完成");}
}

最优替代方案:
直接定义BeanPostProcessor组件(无需监听事件),Spring 会自动注册并生效,代码更简洁:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("Bean初始化完成:" + beanName);return bean;}
}

六、方式五:SmartInitializingSingleton接口(常用度★★)

项目常用度:★★☆☆☆(中低常用)

特点

  • Spring提供的接口,执行时机:所有非懒加载的单例Bean初始化完成后(每个Bean的@PostConstruct执行完毕);
  • 确保所有单例Bean都已存在,适合依赖全部单例Bean的操作。

涉及场景(按常用度排序)

场景一:收集所有实现特定接口的Bean(构建策略工厂)

当应用中存在多个实现同一接口的Bean(如策略模式中的策略类),可通过该接口收集所有实现类,构建策略工厂。

具体例子

@Component
public class PaymentStrategyCollector implements SmartInitializingSingleton {@Autowiredprivate ApplicationContext context;private Map<String, PaymentStrategy> strategyMap = new HashMap<>(); // 策略映射(支付类型→处理器)@Overridepublic void afterSingletonsInstantiated() {// 收集所有实现PaymentStrategy接口的单例Bean(确保所有策略Bean已初始化)Map<String, PaymentStrategy> beans = context.getBeansOfType(PaymentStrategy.class);// 构建映射(key:支付类型,如"alipay"、"wechat")beans.values().forEach(strategy -> strategyMap.put(strategy.getPayType(), strategy));System.out.println("已收集" + strategyMap.size() + "种支付策略:" + strategyMap.keySet());}// 提供获取策略的方法(供其他服务使用)public PaymentStrategy getStrategy(String payType) {return strategyMap.get(payType);}
}// 支付策略接口
public interface PaymentStrategy {String getPayType(); // 返回支付类型(如"alipay")void pay(BigDecimal amount);
}

场景二:对所有单例Bean执行统一初始化操作

需要为所有特定类型的单例Bean(如所有Service的子类)执行统一初始化(如设置日志对象)时,可使用该接口。

具体例子

@Component
public class BaseServiceInitializer implements SmartInitializingSingleton {@Autowiredprivate ApplicationContext context;@Overridepublic void afterSingletonsInstantiated() {// 获取所有BaseService的子类(假设所有业务Service继承BaseService)Map<String, BaseService> serviceBeans = context.getBeansOfType(BaseService.class);// 统一设置日志对象serviceBeans.values().forEach(service -> service.setLogger(LoggerFactory.getLogger(service.getClass())));System.out.println("已为" + serviceBeans.size() + "个BaseService子类设置日志对象");}
}

场景三:校验所有单例Bean的依赖关系

在大型项目中,可通过该接口校验所有单例Bean之间的依赖关系是否合法,避免依赖缺失问题。

具体例子

@Component
public class DependencyCheck implements SmartInitializingSingleton {@Autowiredprivate ApplicationContext context;@Overridepublic void afterSingletonsInstantiated() {// 获取所有单例Bean名称String[] singletonNames = context.getBeanDefinitionNames();for (String beanName : singletonNames) {Object bean = context.getBean(beanName);// 检查Bean的@Autowired字段是否都已注入(简化逻辑)Field[] fields = bean.getClass().getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Autowired.class) && !field.getAnnotation(Autowired.class).required()) {field.setAccessible(true);try {if (field.get(bean) == null) {System.out.println("警告:Bean " + beanName + " 的字段 " + field.getName() + " 注入为null");}} catch (IllegalAccessException e) {// 处理异常}}}}System.out.println("单例Bean依赖关系校验完成");}
}

七、方式六:自定义init-method(常用度★)

项目常用度:★☆☆☆☆(低常用)

特点

  • Spring传统的初始化方式,可通过XML配置或@Bean注解指定Bean的初始化方法;
  • 执行时机与@PostConstruct类似(构造方法→依赖注入→init-method);
  • 现代项目中较少使用,多在老项目或框架源码中出现。

涉及场景(按常用度排序)

场景一:@Bean注解指定初始化方法(替代XML配置)

在Java配置类中,通过@Bean的initMethod属性指定初始化方法,适用于需要显式指定方法名称的场景。

具体例子

@Configuration
public class StorageConfig {// 显式指定init-method为init()@Bean(initMethod = "init")public StorageManager storageManager() {return new StorageManager();}
}public class StorageManager {// 初始化方法(与@Bean(initMethod)一致)public void init() {System.out.println("StorageManager初始化:连接分布式存储服务");// 实际连接逻辑...}
}

场景二:XML配置中指定初始化方法(老项目)

传统XML配置项目中,通过标签的init-method属性指定初始化方法,是早期Spring项目的常用方式。

具体例子

<!-- src/main/resources/applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 指定init-method为init() --><bean id="fileUploader" class="com.example.FileUploader" init-method="init"/>
</beans>// 对应的类
public class FileUploader {// 初始化方法(与XML中init-method一致)public void init() {System.out.println("FileUploader初始化:创建上传目录 /upload");new File("/upload").mkdirs();}
}

场景三:框架源码中显式指定初始化方法

框架开发中,为避免依赖特定注解(如@PostConstruct),常通过init-method显式指定初始化方法,增强通用性。

具体例子

// 框架中的配置类
@Configuration
public class FrameworkConfig {// 框架内部Bean,显式指定init-method@Bean(initMethod = "start")public FrameworkServer frameworkServer() {return new FrameworkServer();}
}// 框架内部服务类
public class FrameworkServer {// 初始化方法(框架启动逻辑)public void start() {System.out.println("FrameworkServer启动:初始化核心组件");// 框架内部初始化逻辑...}
}

总结

SpringBoot提供了多种自启动方式,选择时需结合执行时机业务需求

  • 单个Bean的初始化逻辑(如加载自身配置)→ 优先用@PostConstruct
  • 全局初始化+简单命令行参数 → 用CommandLineRunner
  • 全局初始化+命名参数 → 用ApplicationRunner
  • 容器特定阶段操作(如通知外部系统)→ 用事件监听;
  • 依赖所有单例Bean的操作 → 用SmartInitializingSingleton
  • 老项目或框架兼容 → 用init-method

合理选择自启动方式,能确保应用启动过程中完成必要的初始化,保证应用正常运行。

http://www.dtcms.com/a/613641.html

相关文章:

  • 【ZeroRange WebRTC】UDP无序传输与丢包检测机制深度分析
  • 零基础建设网站视频教程抚州的电子商务网站建设公司
  • qt显示类控件--- Label
  • 【深度学习】基于Faster R-CNN与HRNet的豆类品种识别与分类系统
  • 专业建设网站公司东莞阿里巴巴代运营
  • 【深度学习】YOLOv10n-MAN-Faster实现包装盒flap状态识别与分类,提高生产效率
  • 网站备案需要费用吗中国容桂品牌网站建设
  • 知识图谱与中医古籍的数智化融合:中医药多智能体大模型系统的未来展望
  • wordpress全站cdn法人变更在哪个网站做公示
  • 鸿蒙开发TypeScript第六课:对象
  • 【Linux日新月异(四)】CentOS 7进程管理深度指南:掌控系统生命线
  • 如何避免新手对 instanceof 的误解?
  • 每周AI看 | OpenAI发布GPT-5.1、网易云商自研内部知识问答Agent、商汤开源空间智能大模型
  • 移动端部署噩梦终结者:动态稀疏视觉Transformer的量化实战
  • 【LeetCode刷题】找到字符串中所有字母异位词
  • 榆林城乡建设规划官方网站中国室内设计师
  • oneinstack wordpress成都官网seo服务
  • Go语言编译 | 探讨Go语言编译原理与优化技巧
  • 【深入理解】动静态库的制作、使用与加载原理(附详细操作指南)
  • OpenFeign:完整学习笔记
  • Vue 3 的Suspense组件:讲解如何使用_Suspense_处理异步组件加载状态
  • 【go.sixue.work】2.2 面向对象:接口与多态
  • 建设网站需要收费吗做淘客找单子的网站
  • 视频号直播视频录制
  • 抓取资源的网站怎么做珠海网站设计培训班
  • CPO(Co-Packaged Optics) 是整个数据中心互连范式的下一代核心
  • 1.5 ShaderFeature
  • 暄桐教练日课·10天《梦瑛篆书千字文》报名啦~
  • 从代码规范到 AI Agent:现代前端开发的智能化演进
  • 【MySQL】01 数据库入门