Spring IOC 控制反转(注解版)
Spring IOC 控制反转
文章目录
- Spring IOC 控制反转
- 一、前言
- 什么是控制反转(IOC)
- 什么是依赖注入(DI)
- 二、介绍 IOC
- 2.1 传统思想代码
- 2.2 解决方案
- 2.3 IOC思想代码
- 2.4 IOC 使用(@Autowired依赖注入)
- 2.5 IOC 优势
- 三、IOC详解
- 3.1 从Spring容器中获取对象:Spring上下文
- 3.2 Bean的存储
- 3.2.1 为什么要这么多类注解?
- 3.3 方法注解@Bean
- 3.3.1 @Bean方法注解一定要配合类注解使用
- 3.3.2 @Bean方法定义多个对象
- 3.3.3 重命名@Bean
- 3.4 扫描路径
- 四、三种依赖注入方式(DI)
- 4.1 属性注入
- 4.1.1 @Autowired存在问题
- 4.2 构造方法注入
- 4.3 Setter注入
- 五、常见面试题
- 5.1 常见面试题:@Autowired与@Resource的区别
- 5.2 常见面试题:三种注入方式的优缺点
- 六、附加总结
一、前言
Spring 框架中的核心概念之一就是控制反转(Inversion of Control,IoC)。
IOC就是一种思想,而依赖注入(Dependency Injection, DI) 是控制反转的一种实现方式。
Spring本身是一个容器,存的是对象。对象这个词,在 Spring的范围内,称之为 Bean。
什么是控制反转(IOC)
控制反转(Inversion of Control,IoC)是一种设计原则,它将对象的创建和依赖关系的管理从程序代码中解耦出来,交由框架或容器进行处理。传统的编程方式中,应用程序代码主动创建和管理对象,而通过IoC,框架或容器负责对象的创建和管理,应用程序代码只需要声明依赖关系。转换对象控制权,让Spring帮我们管理或创建 bean。
什么是依赖注入(DI)
依赖注入(Dependency Injection,DI)是一种设计模式,它将对象所依赖的其他对象的创建和管理职责从对象自身剥离出来,通过外部容器(如Spring IoC容器)将所需的依赖对象注入到目标对象中,从而实现对象之间的解耦和提高代码的可维护性和可测试性。
二、介绍 IOC
下面将通过案例来分析什么是IOC
需求:造一辆车
2.1 传统思想代码
public class NewCarExample {public static void main(String[] args) {Car car = new Car(20);car.run();}/*** 汽车对象*/static class Car {private Framework framework;public Car(int size) {framework = new Framework(size);System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}/***车身类*/static class Framework {private Bottom bottom;public Framework(int size) {bottom = new Bottom(size);System.out.println("Framework init...");}}/*** 底盘类*/static class Bottom {private Tire tire;public Bottom(int size) {this.tire = new Tire(size);System.out.println("Bottom init...");}}/*** 轮胎类*/static class Tire {// 尺寸private int size;public Tire(int size){this.size = size;System.out.println("轮胎尺寸:" + size);}}
}
从上述代码中可以看到,以上程序的问题是代码耦合性过高,导致修改底层代码后,需要调整整体的代码。
2.2 解决方案
利用IOC思想,控制反转。
具体操作是将原来由我们自己创建的下极类,改为传递的方式(也就是注入的方式)。
因为我们不需要在当前类中创建下极类了,所以下极类及时发生变化,当前类本身也无需修改任何代码,这样就完成了解耦合。
2.3 IOC思想代码
public class IocCarExample {public static void main(String[] args) {Tire tire = new Tire(20);Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.run();}static class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}}static class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("Framework init...");}}static class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("Bottom init...");}}static class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("轮胎尺寸:" + size);}}
}
2.4 IOC 使用(@Autowired依赖注入)
Spring 作为一个IOC容器帮我们管理对象,其主要功能就是 存 和 取 。
存:存的是对象bean,可以使用 @Component或者其他注解(下文中会讲到)
取:告诉 Spring ,从容器中取出这个对象,赋值给当前对象的属性。也就是依赖注入 使用注解 @Autowired
2.5 IOC 优势
传统开发中,对象创建的顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦代码的创建顺序是:Tire -> Bottom -> Framework -> Car
我们发现了一个规律,通用程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,而改进之后的控制权发生的反转,不再是使用方对象创建并控制依赖对象了 ,而是把依赖对象注入将当前对象中,依赖对象的控制权不再由当前类控制了。
这样的话,即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
上述改进后的程序main中的代码就是IOC容器需要存储的数据。
从上面也可以看出来, IoC容器具备以下优点:
资源不由使用资源的双方管理,而由不使用资源的第三方管理。
- 资源的集中管理:IOC会帮我们管理一些资源(对象等),需要的时候,直接去IOC中取即可。
- 在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,降低耦合度。
三、IOC详解
前面提到的IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。也就是存储bean。
3.1 从Spring容器中获取对象:Spring上下文
在学习如何存储对象之前,先来看如何从Spring容器中获取对象?
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//String上下文ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//获取到这个类的对象context.getBean(Class<T> aClass);//根据bean名称获取beancontext.getBean(String s);}
}
获取Bean的三种常用方法
通过Bean名称来获取Bean,如果没有显式的提供名称(BeanId),Spring容器将为该bean生成唯一的名称。
Bean的命名约定:查看官方文档
其大致意思是,bean名称以小写字母开头,然后使用驼峰式大小写
比如:
类名:UserController,Bean的名称为:userController;
类名:AccountManager,Bean的名称为:accountManage;
也有特殊情况:
比如 :
类名:UController,Bean的名称为:UController;
类名:AController,Bean的名称为:AController;
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//上下文ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//通过类名获取beanUserController usercontroller1 = context.getBean(UserContorller.class);//通过Bean名获取beanUserController usercontroller2 = context.getBean(userController);system.out.println(usercontroller1);system.out.println(usercontroller2);}
}
3.2 Bean的存储
在Spring中,要把某个对象交给IOC容器管理,需要在类上添加注解,下文中就会讲到Spring框架为服务web应用程序,提供了丰富的注解。
共有两类注解类型可以实现:
- 类注解:@Controller、@Service、@Repository、@Component、@Configuration
- 方法注解:@Bean
观察下面类注解的源代码,都是@component的衍生类,因此@Component的作用范围更广。
@Controller控制存储器
@Service服务存储
@Repository仓库存储
@Component组件存储
@Configuration配置存储
3.2.1 为什么要这么多类注解?
最直接的一个原因就是,可以让程序员看到类注解之后,就能直接了解当前类的用途。
- @Controller:控制层, 接收请求, 对请求进行处理, 并进行响应.
- @Servie:业务逻辑层, 处理具体的业务逻辑.
- @Repository:数据访问层,也称为持久层. 负责数据访问操作
- @Configuration:配置层. 处理项目中的一些配置信息
3.3 方法注解@Bean
五大注解只能加在类上,并且只能加在自己的代码上,如果我引入了一个第三方jar包,也希望交给Spring管理,是没有办法加五大注解。比如说:数据库操作,定义多个数据源
。
@Bean方法一定要配合类注解使用
使用@Bean注解时,bean的名称是方法名。
3.3.1 @Bean方法注解一定要配合类注解使用
在 Spring 框架的设计中,方法注解 要配合类注解才能将对象正常的存储到 Spring 容器中,下代码所示:
@Component
public class BeanConfig {@Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}
3.3.2 @Bean方法定义多个对象
对于同一个类,如何定义多个对象呢?
比如说,多数据源的场景,类是同一个,但是配置不同,指向的数据源也不同。
@Component
public class BeanConfig {@Beanpublic User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2(){User user = new User();user.setName("lisi");user.setAge(19);return user;}
}
此时,如果通过类型获取对象的话,Spring就会给我们报错,因为有两个对象,Spring不知道取哪个。接下来根据名称来获取bean对象。
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//根据bean名称, 从Spring上下文中获取对象// User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");System.out.println(user1);System.out.println(user2);}
}
3.3.3 重命名@Bean
@Bean(name = {"u1","user1"})
public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;
}
3.4 扫描路径
SpringBoot 特点就是约定大于配置。其中之一的体现就是扫描路径。
默认扫描路径:启动类所在的目录及其子孙目录
如果更改启动类所在目录,而未进行路径的标注就会出现报错。
通过@ComponentScan()这个注解可以指定扫描路径。
@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//从Spring上下文中获取对象User u1 = (User) context.getBean("u1");//使用对象System.out.println(u1);}
}
四、三种依赖注入方式(DI)
上面我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注入DI的细节。依赖注入是一个过程,是指IoC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象。在上面程序案例中,我们使用了@Autowired
这个注解,完成了依赖注入的操作。
关于依赖注入,Spring也给我们提供了三种方式:
- 属性注入
- 构造方法注入
- Setter注入
4.1 属性注入
属性注入是使用@Autowired
实现的。
下面是将Service类注入到Controller类中。
//Service类
import org.springframework.stereotype.Service;
@Service
public class UserService {public void sayHi() {System.out.println("Hi,UserService");}
}
@Controller
public class UserController {//注入方法1: 属性注入@Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}
}
4.1.1 @Autowired存在问题
当一个类存在多个bean时,使用@Autowored会存在问题
@Component
public class BeanConfig {@Bean()public User user1() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}
}
@Controller
public class UserController {@Autowiredprivate UserService11 userService;//此时注入的user,Spring不知道是user1还是user2@Autowiredprivate User user;public void sayHi() {System.out.println("hi,UserController...");userService.sayHi();System.out.println(user);}
}
运行程序就会报错
报错原因是非唯一的Bean对象。
Spring提供了以下几种解决方案:
- Primary
- Qualifier
- Resource
使用@Primary注解: 当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现.
@Component
public class BeanConfig {//此时Spring默认的就是user1()@Primary@Bean()public User user1() {User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}
}
使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。
@Controller
public class UserController @Autowiredprivate UserService11 userService;@Qualifier("user2") //指定bean名称@Autowiredprivate User user;public void sayHi() {System.out.println("hi,UserController...");userService.sayHi();System.out.println(user);}
}
使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
@Controller
public class UserController @Autowiredprivate UserService11 userService;@Resource(name = "user2")private User user;public void sayHi() {System.out.println("hi,UserController...");userService.sayHi();System.out.println(user);}
}
4.2 构造方法注入
构造方法注入是在类的构造方法中实现注入,代码如下:
@Controller
public class UserController2 {//注入方法2: 构造方法private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}
}
4.3 Setter注入
Setter注入和属性的Setter方法实现类似,只不过在设置 set 方法的时候需要加上@Autowired注解,代码如下:
@Controller
public class UserController3 {//注入方法3: Setter方法注入private UserService us;@Autowiredpublic void setUS(UserService us) {this.us = us;}public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}
}
五、常见面试题
5.1 常见面试题:@Autowired与@Resource的区别
@Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
@Autowired 默认是按照类型注入,而@Resource是按照名称注入. 相比于@Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。
5.2 常见面试题:三种注入方式的优缺点
- 属性注入(大部分情况下使用)
- 优点:简洁、使用方便。
- 缺点:
- 不能注入一个Final修饰的属性。
- 只能用于IOC容器,如果是非IOC容器则不可用。并且在使用的时候才会出现 NPE(空指针异常)
- 构造函数注入(Spring 4.x推荐)
- 优点:
- 可以注入Final修饰的属性。
- 注入的对象不会被修改。
- 通用性比较好,构造方法是JDK支持的,因此更换框架也是适用的。
- 缺点:注入多个对象时,代码比较复杂。
- 优点:
- Setter注入(Spring 3.x推荐)
- 优点:方便在类实例之后,重新对该对象进行配置或注入。
- 缺点:
- 不能注入一个Final修饰的对象。
- 注入对象有被修改的风险。
六、附加总结
相关文章:

Spring IOC 控制反转(注解版)
Spring IOC 控制反转 文章目录 Spring IOC 控制反转一、前言什么是控制反转(IOC)什么是依赖注入(DI) 二、介绍 IOC2.1 传统思想代码2.2 解决方案2.3 IOC思想代码2.4 IOC 使用(Autowired依赖注入)2.5 IOC 优…...
串口触摸屏的键盘控制
(text 属性txt_maxl 800) ①变量loadpageid.val:调用页的页面ID。 ②变量loadcmpid.val:调用页的控件ID。 ③定时器tm0:让输入框有个光标不断闪烁,如果不需要,控件属性en0即可。 ④变量inputlen…...

xss初识(xss-lab)
XSS跨站脚本 XSS漏洞概述 XSS被称为跨站脚本攻击(Cross-site scripting),由于和CSS(Cascading Style Sheets) 重名,所以改为XSS。 XSS主要基于javascript语言完成恶意的攻击行为,因为javascri…...
Autodesk Revit产品痛点
1.Revit已有20多年的历史,大多数软件公司认为大多数代码最多只有10年的生命周期。 2.Revit核心部分仍局限于单个CPU核心上,严重制约性能提升。 3.Revit只在数据库的大小和小细节上的改动。 4.Revit陈旧的绘图技术和性能难以提升。 5.Revit的致命弱点是模型增长的…...

如何使用Windows备份轻松将数据转移到新电脑?这里有详细步骤
序言 我们都知道那种买了一台新电脑,就想直接上手的感觉。我记得在过去的日子里,要花几个小时传输我的文件,并试图复制我的设置。在当今传输数据的众多方法中,Windows备份提供了一个简单可靠的解决方案。 登录到你的Microsoft帐户 Microsoft在传输过程中使用其云存储来保…...

【linux】操作系统使用wget下载网络文件,内核tcpv4部分运行日志
打印日志代码及运行日志(多余日志被删除了些): 登录 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/commit/55a53caa06c1472398fac30113c9731cb9e3b482 测试步骤和手段: 1、清空 kern.log; 2、使用wget 下载linux-6.9.tar.gz&…...
QT中常用控件的样式美化,已上传相应的qss样式和图片资源
1、QComboBox /*仅仅输入框*/ QComboBox {background-color: transparent;border-image: url(:/images/systemSetImage/common/comboBoxBk.png);border: 1px solid #7285CA...
Vue form表单验证
el-form 标签添加 ref、rules <el-form ref"form" :inline"true" :model"form" :rules"rules">el-form-item 添加prop <el-form-item label"姓名" prop"name"><el-input placeholder"请输入姓…...
vue.extend解决vue页面转构造函数暴露js供全局使用
用途: 解决在一些微前端项目中, B工程使用A工程的弹窗代码 // MaterialListPlugin.js文件, 在项目入口引入 // eg: 在main.js中添加一行 import /components/MaterialListPlugin.jsimport Vue from vue import MaterialListPlugin from /components/MaterialListPlugin.vue //…...
Java中如何处理异常?
在Java中处理异常是确保软件健壮性和提高代码质量的重要手段。以下是Java异常处理的一些关键点和最佳实践: 1:理解异常类型: Java中的异常分为检查异常( checked exceptions)和非检查异常(un-checked exc…...

wordpress站群搭建3api代码生成和swagger使用
海鸥技术下午茶-wordpress站群搭建3api代码生成和swagger使用 目标:实现api编写和swagger使用 0.本次需要使用到的脚手架命令 生成 http server 代码 goctl api go -api all.api -dir ..生成swagger文档 goctl api plugin -plugin goctl-swagger"swagger -filename st…...
如何在使用 Qt 时打印到控制台
在开发过程中,打印变量值到控制台对于调试和监控非常重要。使用 Qt 和 C 开发时,有多种方法可以实现这一点。在本文中,我们将探索几种在 Qt 中打印到控制台的专业方法。 1. 使用 qDebug、qWarning、qCritical 和 qFatal Qt 提供了一些方便的…...

ffmpeg音视频开发从入门到精通——ffmpeg下载编译与安装
音视频领域学习ffmpeg的重要性 音视频领域中ffmpeg的广泛应用,包括直播、短视频、网络视频、实时互动和视频监控等领域。掌握FM和音视频技术可以获得更好的薪酬。 学习建议音视频学习建议与实战应用 音视频处理机制的学习,需要勤加练习,带…...

数据通信与网络(三)
物理层概述: 物理层是网络体系结构中的最低层 它既不是指连接计算机的具体物理设备,也不是指负责信号传输的具体物理介质, 而是指在连接开放系统的物理媒体上为上一层(指数据链路层)提供传送比特流的一个物理连接。 物理层的主要功能——为…...

盲盒小程序模式?有什么功能?
近些年,盲盒成为了热门的休闲娱乐消费方式,深深吸引着消费者的目光,行业更是持续上升发展,成为了具有巨大发展前景的行业之一。 随着市场的逐步发展,盲盒也开始向线上模式发展,以互联网为媒介,…...

【MySQL进阶之路 | 高级篇】InnoDB搜索引擎行格式
1. COMPACT行格式 COMPACT行格式是MySQL5.1的默认行格式.其结构示意图如下. 大体可以分为两部分. 记录的额外信息.这里面有包括变长字段长度列表,NULL值列表和记录头信息.记录的真实数据. (1).变长字段长度列表 MySQL支持一些变长的数据类型.比如VARCHAR(m), VA…...
大数据面试-Scala
谈谈scala的闭包、柯里化、高阶函数 如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包。 闭包在函数式编程中是一个重要的概念,广泛用于高阶函数、柯里化等技术中。 函数…...
76.最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。 注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存…...

深度学习算法informer(时序预测)(三)(Encoder)
一、EncoderLayer架构如图(不改变输入形状) 二、ConvLayer架构如图(输入形状中特征维度减半) 三、Encoder整体 包括三部分 1. 多层EncoderLayer 2. 多层ConvLayer 3. 层归一化 代码如下 class AttentionLayer(nn.Module):de…...

HTML和CSS基础(一)
前言 HTML(HyperText Markup Language)是一种用于创建网页的标准标记语言。它由各种标签组成,这些标签定义了网页的结构和内容。HTML的早期形式诞生于1989年,由CERN的物理学家Tim Berners-Lee发明,最初用于在科学家之…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
基于Uniapp的HarmonyOS 5.0体育应用开发攻略
一、技术架构设计 1.混合开发框架选型 (1)使用Uniapp 3.8版本支持ArkTS编译 (2)通过uni-harmony插件调用原生能力 (3)分层架构设计: graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...