Spring IoC和DI

目录

IoC是什么?

理解IoC

示例

为什么要使用IOC

DI是什么?

IoC

@Controller(控制器存储)

@Controller的使用 

ApplicationContext

@Service(服务存储) 

类注解总结

@Bean

方法注解的使用

定义多个对象

Bean的重命名

扫描路径

DI

属性注入 

构造方法注入

Setter注入

三种注入方法分析

@Autowired存在的问题

@Primary

@Qualifier

@Resource


Spring可以总结为:包含了众多方法工具的IoC容器

什么是 IoC ?什么是容器

我们通过本篇文章来进行学习

IoC是什么?

理解IoC

IoC(Inversion of Control)控制反转,即控制权反转,指在传统的程序设计中,流程的控制权通常由程序内部实现,而使用IoC,对象对自己所依赖的资源不再负责获取和管理,而是把这些控制权交给外部容器来实现。

什么是容器?

容器:也就是用来容纳物品的装置(如生活中的箱子)。在计算机中,我们容纳的是应用程序和相关组件,因此,容器是一种用于封装应用程序及其所有相关组件的技术

什么是控制权反转?

在传统的程序开发过程中, 当我们需要某个对象时,需要自己通过new创建对象,而IoC有专门的容器来创建这些对象,即IoC容器来控制对象的创建,此时,我们可以将创建对象的任务交给容器,程序只需要依赖注入(DI)就可以了。在此过程中,我们获取对象的过程,由主动(自己创建)变为了被动(从IoC容器中获取),控制权颠倒,因此叫做控制反转

我们通过一个例子来进一步理解IoC:

示例

需求:造一辆车

在进行传统程序开发时,我们的思路是这样的:要造一辆车,首先要有轮胎

 然后将Tire类主动注入到用Car中

简单代码演示:

Tire:


public class Tire {private int size;public Tire(){this.size = 20;System.out.println("轮胎尺寸:" + size);System.out.println("Tire init");}public void run(){System.out.println("Tire");}
}

Car: 

public class Car {private Tire tire;public Car(){tire = new Tire();System.out.println("Car init");}public void run(){System.out.println("Car");}
}

 然而,当轮胎的尺寸发生变化,需要通过用户的指定来造轮胎,此时,我们需要修改代码:

对应的,Car也需要进行修改:

此时,修改底层代码,调用该类的代码都需要修改, 程序的耦合性非常高

在上述程序中,我们在造车时根据车轮的大小设计汽车,车轮一修改,汽车的设计就得修改

我们可以换一种思路:我们不需要完成汽车和轮胎的所有设计,将轮胎外包出去,当轮胎的尺寸发生改变时,我们只需向工厂下订单,工厂就会帮我们造好轮胎

在代码中体现为:我们不在类中创建依赖的对象,而是通过传递(也就是注入)的方式

这样,即使Tire中发生改变,Car本身也不需要修改任何代码

底层类发生变化,调用它的类不用做任何代码,也就实现了代码之间的解耦,从而程序设计更加灵活

在传统的代码中,对象创建的顺序是:Car -> Tire

而改进后的代码,对象创建的顺序是:Tire -> Car

我们可以发现:传统开发中,Car控制并创建了Tire,而改进后,控制权发生了反转,不再是由使用方创建并控制依赖对象了,而是将依赖对象注入到对象中,依赖对象的控制权不再由使用方控制

而 IOC有专门的容器来创建这些对象,即IoC容器来控制对象的创建,使用方需要时,只需将依赖注入就可使用依赖对象

为什么要使用IOC

通过上述过程,我们可以看出,使用IoC容器,资源不再由使用资源的双方管理,而是由不使用资源的第三方管理,此时:

1. 能够降低耦合度:IoC容器可以帮助管理对象之间的依赖关系,将对象的创建和管理交给容器来实现,从而降低了使用资源双方的依赖程度,使得代码更易于理解、维护和扩展。

2. 简化配置和管理:IoC容器可以集中管理资源,统一进行配置和管理,减少了对资源的手动管理工作,提高了系统的可维护性和管理效率。

3. 提高了灵活性:通过IoC容器管理对象的依赖关系,可以使系统更加灵活,能够更方便地进行替换、升级或扩展,而不需要修改大量的代码。

DI是什么?

DI(Dependency Injection):依赖注入,在容器运行期间,动态的为应用程序提供运行时所依赖的资源,即程序在运行时需要资源,此时容器就为其提供这个资源

因此,依赖注入可以看做是实现控制反转的一种方式

在示例的改进代码中,是通过构造函数的方式,将依赖对象注入到需要使用的对象中的:

在了解了 IoC 和 DI的基本概念后,我们来学习 Spring IoC 和 DI 的代码实现

Spring 是一个 IoC容器,作为容器,就具备两个功能:存 和 取

Spring容器管理的主要是对象,而这些被管理的对象,我们称之为 Bean。我们将对象交给 Spring 进行管理,由 Spring 来负责对象的创建和销毁,程序只需要告诉 Spring,哪些需要存取,以及如何取

IoC

要将对象交给IoC容器进行管理,需要使用注解,而Spring框架为更好的服务web应用程序,提供了丰富的注解:

类注解:@Controller @Service @Repository @Component @Configuration

方法注解:@Bean

我们先学习类注解

@Controller(控制器存储)

@Controller的使用 

使用@Controller存储bean:

@Controllerpublic class UserController {public void hello(){System.out.println("hello...");}
}

如何观察这个对象是否已经存在Spring容器中了呢?

若是能从Spring容器中获取这个对象,则这个对象就已经存在Spring容器中了

我们使用ApplicationContext来帮助我们获取对象

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserController bean = context.getBean(UserController.class);bean.hello();}
}

我们观察运行结果,发现成功从Spring中获取到Controller对象,且执行了Controller的hello方法:

若我们将@Controller删除,再观察运行结果:

此时程序报错:找不到类型为:com.example.demo.controller.UserController 的bean

ApplicationContext

ApplicationContext是什么呢?

 ApplicationContext,即Spring上下文

对象交由Spring进行管理,要从Spring中获取对象,首先要拿到Spring的上下文

我们来理解上下文的概念:

在做语文阅读理解的时候,常会遇见这样的问题:请根据上下文,分析你对...的理解  其中的上下文,指的是文章中与某一词语或文句相连的上文和下文

在学习多线程时,应用进行线程切换的时候,在切换之前会将线程的状态信息暂时存储起来,这里的上下文就包括了当前线程的信息,等下次该线程又得到CPU时间时,就能从上下文中拿到线程上次运行的信息

而在Spring框架中,上下文指的是 Spring IoC 容器管理的对象之间的环境和状态。其中包括 bean 的定义、依赖注入、AOP配置等。

在上述代码中,我们是通过类型(DemoApplication.class)来查找对象的,还有其他的方式获取bean

获取bean的方式

ApplicationContext提供了许多获取bean的方式,而ApplicationContext获取bean对象的功能是父类 BeanFactory 提供的功能

在上述获取bean的方法中,常用的是第1,2,4种

其中涉及到根据名称获取bean,bean的名称是什么呢?

Spring bean 是Spring框架在运行时管理的对象,Spring会给管理的对象起一个名字(例如,学校会给每个学生分配一个学号,根据学号就能够找到对应的学生)

而在Spring中也是如此,为每个对象起一个名字,根据bean的名称,就可以找到对应对象,从而获取对应对象

在分配学号时,学校会根据学生的入学年份、专业、班级等信息分配学号,也就是学号的制定规则

在Spring,是如何命名的呢?Bean的命名约定是什么呢?

命名约定使用Java标准约定作为实例字段名,即 使用小驼峰命名规则

例如:UserController,bean的名称为:userController

根据这个命名规则,我们来获取bean:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserController bean = context.getBean(UserController.class);//根据 类型 获取UserController userController = (UserController) context.getBean("userController");//根据 名称 获取UserController userController1 = context.getBean("userController", UserController.class);//根据名称 + 类型 获取System.out.println(bean);System.out.println(userController);System.out.println(userController1);}
}

运行结果:

根据结果我们也可以发现:三种方法获取的对象地址一样,这说明获取的对象是同一个

但是,命名时也有一些特殊情况:

@Controller
public class UController {public void run(){System.out.println("UController");}
}
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UController uController = (UController) context.getBean("uController");}
}

此时,运行结果为:

错误为:没有名称为 uController 的 bean

这是因为,当有多个字符,且第一个和第二个字符都是大写时,要保留原始大小写

因此,UController,bean 的名称为 UController

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UController uController = (UController) context.getBean("UController");}
}

我们来总结一下bean的命名约定:

当有多个字符且第一个和第二个字符都是大写时,保留原始大小写

其他情况,则使用小驼峰命名规则 

接下来,我们来看@Service

@Service(服务存储) 

 使用@Service 存储 bean:

@Service
public class UserService {public void runService(){System.out.println("service...");}
}

获取 bean:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserService userService = context.getBean(UserService.class);userService.runService();}
}

@Repository(仓库存储) @Component(组件存储) @Configuration(配置存储)的使用也是类似的,这里就不再一一演示了

类注解总结

为什么要有这么多的类注解呢?

这与 应用分层 类似,为了在看到类注解后,就能直接了解当前类的用途

@Controller:控制层,接收请求,对请求进行处理,并进行响应

@Service:业务逻辑层,处理具体的业务逻辑

@Repository:数据访问层,也称为持久层,处理数据访问操作

@Configuration:配置层,处理项目中的一些配置信息

@Component:泛指组件,当组件不好归类时,可以使用这个注解

类注解之间的关系:

我们观察 @Controller @Service @Repository @Configuration 和 @Component 的源码:

 @Controller @Service @Repository @Configuration 这些注解里面都有一个注解 @Component,说明 它们 属于 @Component 的 “子类”

@Component 是一个 元注解,也就是可以注解其他类的注解,@Controller @Service等,这些注解被称为@Component的衍生注解

类注解是添加到某个类上的,但在某些情况下也会出现问题问题:

1. 使用外部包里的类时,没办法添加类注解

2. 一个类需要多个对象时

此时,我们就需要使用方法注解

@Bean

方法注解的使用

@Datapublic class User {private int id;private String name;public User(){}public User(int id, String name) {this.id = id;this.name = name;}
}
public class Users {@Beanpublic User user() {return new User(1, "aaa");}
}

尝试获取:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user = context.getBean(User.class);System.out.println(user);}
}

运行结果:

程序报错:找不到 类型为 com.example.demo.model.User 的 bean

为什么会报错呢?

 这是因为方法注解要配合类注解使用

我们加上类注解:

@Component
public class Users {@Beanpublic User user() {return new User(1, "aaa");}
}

运行结果:

定义多个对象

若此时同一个类中有多个对象呢?

@Component
public class Users {@Beanpublic User user1() {return new User(1, "aaa");}@Beanpublic User user2(){return new User(2, "bbb");}
}

我们根据类型来获取对象:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user = context.getBean(User.class);System.out.println(user);}
}

运行结果:

报错显示:期望只有一个匹配,结果发现了两个:user1,user2

我们可以报错信息中看出:@Bean注解的bean,bean的名称就是它的方法名

我们根据名称来获取bean:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");System.out.println(user1);System.out.println(user2);}
}

 运行结果:

根据 名称 + 类型来获取bean:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user1 = (User) context.getBean("user1", User.class);User user2 = (User) context.getBean("user2", User.class);System.out.println(user1);System.out.println(user2);}
}

运行结果:

由此可以看出:@Bean可以针对同一个类定义多个对象

Bean的重命名

可以通过设置name属性对Bean进行重命名:

@Component
public class Users {@Bean(name = {"us1", "user1"})public User user1() {return new User(1, "aaa");}@Beanpublic User user2(){return new User(2, "bbb");}
}

此时就可以使用 us1来获取User对象了:

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user1 = (User) context.getBean("us1");User user2 = (User) context.getBean("user2", User.class);System.out.println(user1);System.out.println(user2);}
}

运行结果:

其中 name = 可以省略:

    @Bean({"us1", "user1"})public User user1() {return new User(1, "aaa");}

而当只有一个名称时,{}也可以省略:

    @Bean("us1")public User user1() {return new User(1, "aaa");}

扫描路径

bean想要生效,需要被Spring扫描

我们修改项目工程的目录结构:

此时再运行代码:

程序报错:没有找到名称为us1的bean

为什么没有找到呢? 

使用注解声明的bean想要生效需要配置扫描路径,让Spring能够扫描到这些注解

通过 @ComponentScan 来配置扫描路径:

@SpringBootApplication
@ComponentScan({"com.example.demo"})
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);User user1 = (User) context.getBean("us1");User user2 = (User) context.getBean("user2", User.class);System.out.println(user1);System.out.println(user2);}
}

{} 中可以配置多个包路径

为什么前面没有配置 @ComponentScan 注解也能够扫描?

 @ComponentScan 虽然没有显示配置,但其实已经包含在启动类声明注解 @SpringBootApplication 中了

其中,扫描的默认范围是 SpringBoot 启动类所在的包及其子包

(在配置类上添加 @ComponentScan 注解,该注解默认会扫描该类所在包下的所有配置类)

因此,将启动类放在我们所希望扫描的包的路径下,这样,定义的bean就可以被扫描到了

DI

在进一步学习了控制反转IoC后,我们来学习依赖注入DI

依赖注入是一个过程,在IoC容器创建bean时,提供运行时所依赖的资源

使用 @Autowired 注解来完成依赖注入

Spring 为我们提供了三种注入方式:

1. 属性注入 (Field Injection)

2. 构造方法注入 (Constructor Injection)

3. Setter注入(Setter Injection)

属性注入 

属性注入是通过在类的属性上使用 @Autowired 注解或在配置文件中进行配置,将依赖对象注入到类的属性中

我们将UserService类注入到UserController类中:

UserService:

@Service
public class UserService {public void runService(){System.out.println("service...");}
}

UserController:

@Controller
public class UserController {@Autowiredprivate UserService userService;public void hello(){System.out.println("hello...");userService.runService();}
}

获取UserController中的hello方法:

@SpringBootApplication
@ComponentScan({"com.example.demo"})
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserController userController = context.getBean(UserController.class);userController.hello();}
}

运行结果:

若去掉 @Autowired:

程序报错:不能调用 com.example.demo.service.UserService.runService(),因为 this.userService 为空

构造方法注入

 构造方法注入是在类的构造方法中实现注入:

@Controller
public class UserController {private UserService userService;@Autowiredpublic UserController(UserService userService){this.userService = userService;}public void hello(){System.out.println("hello...");userService.runService();}
}

运行结果:

若此时类中只有一个构造方法,则 @Autowired 注解可以省略:

@Controller
public class UserController {private UserService userService;// @Autowiredpublic UserController(UserService userService){this.userService = userService;}public void hello(){System.out.println("hello...");userService.runService();}
}

但若类中有多个构造方法,此时就需要添加 @Autowired 注解来明确指定使用哪个构造方法

@Controller
public class UserController {private UserService userService;public UserController(){}@Autowiredpublic UserController(UserService userService){this.userService = userService;}public void hello(){System.out.println("hello...");userService.runService();}
}

若此时去掉 @Autowired 注解,程序报错:

Setter注入

Setter注入与属性的Setter方法类似,只不过需要在设置set方法时添加上 @Autowired 注解:

@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}public void hello(){System.out.println("hello...");userService.runService();}
}

此时,若 去掉 @Autowired:

同样的,程序报错

三种注入方法分析

属性注入:

优点:

 简洁方便,可以直接在属性上进行注入,代码简洁,不需要编写额外的构造方法或 Setter 方法

缺点: 

1. 只能用于IoC容器

2. 不能注入 final 修饰的属性

构造函数注入:

优点:

1. 可以注入 final 修饰的属性

2. 注入的对象不会被修改

3. 依赖对象在使用前一定会被完全初始化(因为依赖是在类的构造方法中执行的,而构造方法在类加载阶段就会执行)

4. 通用性好,构造方法是JDK支持的,更换框架后也是适用的

缺点:

注入多个对象时,代码量相对较多

Setter注入:

优点:

1. 方便在类实例后,重新对该对象进行配置或注入

2. 可选依赖,可以只提供部分 Setter 方法,不影响其他依赖的注入

缺点:

1. 不能注入 final修改的属性

2. 注入对象可能会发生改变(setter方法可能被多次调用,就有被修改的风险)

3.  需要为每个需要注入的属性编写相应的 Setter 方法,增加了代码量

因此, 选择使用哪种依赖注入方式取决于具体的需求和场景。

@Autowired存在的问题

若同一类型中存在多个bean,此时适用@Autowired会存在问题:

@Controller
public class UserController {@Autowiredprivate User user;public void hello(){System.out.println("hello...");System.out.println(user);;}
}

 运行结果:

程序报错:UserController 需要一个 bean,但是发现了两个,即非唯一的bean

如何解决该问题呢?

其实报错信息下面就给出了解决方法: 

@Primary

当多个类型相同的bean注入时,加上 @Primary 注解,来确定默认的实现:

@Component
public class Users {@Primary//指定 该 bean 为默认bean实现@Beanpublic User user1() {return new User(1, "aaa");}@Beanpublic User user2(){return new User(2, "bbb");}
}

运行结果:

@Qualifier

使用 @Qualifier 注解,指定当前要注入的对象,在 @Qualifier 的 value属性中,指定注入的 bean的名称,@Qualifier注解不能单独使用,必须配合 @Autowired 使用 

@Controller
public class UserController {@Qualifier("user2")@Autowiredprivate User user;public void hello(){System.out.println("hello...");System.out.println(user);;}
}

运行结果:

@Resource

@Resource注解,是按照 bean 的名称进行注入,通过 name 属性指定要注入的 bean 的名称 

@Controller
public class UserController {@Resource(name = "user1")private User user;public void hello(){System.out.println("hello...");System.out.println(user);;}
}

运行结果:

@Autowired 与 @Resource 的区别

@Autowired 是 Spring 框架提供的注解,而 @Resource 是JDK 提供的注解

@Autowired 默认是按照类型注入的,而 @Resource 是按照名称注入的,相比于 @Autowired,@Resource 支持更多的参数设置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/292327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

A Simple Problem with Integers(线段树)

目录 描述 输入 输出 样例输入 样例输出 思路 建树 第一次错误解法(正确解法在下面,可跳过这一步) 正确解法 code 描述 You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of …

Qt for WebAssembly 环境搭建 - Windows新手入门

Qt for WebAssembly 环境搭建 - Windows新手入门 一、所需工具软件1、安装Python2、安装Git2.1 注册Github账号2.2 下载安装Git2.2.1配置Git:2.2.2 配置Git环境2.2.3解决gitgithub.com: Permission denied (publickey) 3 安装em编译器 二、Qt配置编译器三、参考链接…

git基本操作二(小白快速上手)

1、前言 接上篇我们接着来继续讲 2、.gitignore忽略文件 创建一个.gitignore文件,并将其置于项目的根目录下,Git将自动识别并根据该规则忽略相应的文件和目录。 # 忽略所有的 .log 文件 *.log# 但跟踪所有的 build.log 文件 !build.log# 忽略所有的 /lo…

elementUI this.$msgbox msgBox自定义 样式自定义 富文本

看这个效果是不是很炫?突出重点提示内容,对于用户交互相当的棒! 下来说说具体实现: let self = this const h = self.$createElement; this.$msgbox({title: null,message: h("p", {style: "margin-top:10px"}, [h("i", {class: "el-i…

C# wpf 嵌入wpf控件

WPF Hwnd窗口互操作系列 第一章 嵌入Hwnd窗口 第二章 嵌入WinForm控件 第三章 嵌入WPF控件(本章) 第四章 底部嵌入HwndHost 文章目录 WPF Hwnd窗口互操作系列前言一、如何实现?1、继承HwndHost2、添加Content属性3、创建wpf窗口并设置Conten…

IDEA的使用(概念,安装,配置,)以及什么是字符集,模版

目录 Intellij IDEA IDE的概念 IntelliJ IDEA的安装 IntelliJ IDEA的使用 基本配置 JDK配置 创建Module 基本用法 字体配置 主题配置 字符集 设置IDEA默认字符集 注释模板 字符集 字符集简介 常见字符集 Intellij IDEA 我们不可能一直使用记事本之类变成&#…

2014年认证杯SPSSPRO杯数学建模C题(第一阶段)土地储备方案的风险评估全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 C题 土地储备方案的风险评估 原题再现: 土地储备,是指市、县人民政府国土资源管理部门为实现调控土地市场、促进土地资源合理利用目标,依法取得土地,进行前期开发、储存以备供应土地的行为。土地…

深度学习pytorch——经典卷积网络之ResNet(持续更新)

错误率前五的神经网络(图-1): 图-1 可以很直观的看到,随着层数的增加Error也在逐渐降低,因此深度是非常重要的,但是学习更好的网络模型和堆叠层数一样简单吗?通过实现表明(图-2&…

Collection与数据结构 链表与LinkedList (一):链表概述与单向无头非循环链表实现

1.ArrayList的缺点 上篇文章我们已经对顺序表进行了实现,并且对ArrayList进行了使用,我们知道ArrayList底层是使用数组实现的. 由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时…

帆软报表在arm架构的linux

有朋友遇到一个问题在部署帆软报表时遇到报错。 问 我在 arm架构的linux服务器上部署帆软报表遇到了一个棘手的问题,你有空帮忙看下嘛。 我看后台日志报的错是 需要升级 gcc、libmawt.so ,是系统中缺少Tomcat需要的依赖库,你之前处理过类似…

ClickHouse10-ClickHouse中Kafka表引擎

Kafka表引擎也是一种常见的表引擎,在很多大数据量的场景下,会从源通过Kafka将数据输送到ClickHouse,Kafka作为输送的方式,ClickHouse作为存储引擎与查询引擎,大数据量的数据可以得到快速的、高压缩的存储。 Kafka大家…

CSS(四)---【链接美化、浮动布局、三种定位】

零.前言 本篇主要讲解<a>标签链接美化、页面的浮动布局&#xff0c;以及“相对定位”、“绝对定位”、“固定定位”三种定位。 关于其它请查看作者其它文章&#xff1a; CSS(一)---【CSS简介、导入方式、八种选择器、优先级】-CSDN博客 CSS(二)---【常见属性、复合属…

鸿蒙OS开发实例:【窥探网络请求】

HarmonyOS 平台中使用网络请求&#xff0c;需要引入 "ohos.net.http", 并且需要在 module.json5 文件中申请网络权限, 即 “ohos.permission.INTERNET” 本篇文章将尝试使用 ohos.net.http 来实现网络请求 场景设定 WeiBo UniDemo HuaWei : 请求顺序WeiBo1 UniDem…

Python之Opencv教程(3):人脸识别

1、人脸识别代码 直接上代码&#xff1a; import cv2# 加载训练数据集文件 recogizer cv2.face.LBPHFaceRecognizer_create()recogizer.read(trainer/trainer.yml)# 准备识别的图片 img cv2.imread(images/lisa.jpg) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)face_dete…

Stata 15 for Mac:数据统计分析新标杆,让研究更高效!

Stata 是一种统计分析软件&#xff0c;适用于数据管理、数据分析和绘图。Stata 15 for Mac 具有以下功能&#xff1a; 数据管理&#xff1a;Stata 提供强大的数据管理功能&#xff0c;用户可以轻松导入、清洗、整理和管理数据集。 统计分析&#xff1a;Stata 提供了广泛的统计…

sqli第24关二次注入

注入点 # Validating the user input........$username $_SESSION["username"];$curr_pass mysql_real_escape_string($_POST[current_password]);$pass mysql_real_escape_string($_POST[password]);$re_pass mysql_real_escape_string($_POST[re_password]);if($p…

算法学习——LeetCode力扣动态规划篇5

算法学习——LeetCode力扣动态规划篇5 198. 打家劫舍 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统…

Android MediaPlayer

MediaPlayer 类是媒体框架最重要的组成部分之一。此类的对象能够获取、解码以及播放音频和视频&#xff0c;而且只需极少量设置。它支持多种不同的媒体源&#xff0c;例如&#xff1a; • 本地资源 • 内部 URI&#xff0c;例如您可能从内容解析器那获取的 URI • 外部网址…

光明源@智慧厕所公厕软件系统有哪些核心功能?

在现代城市的建设中&#xff0c;智慧公厕的建设成为了提升城市品质和居民生活质量的重要举措。而智慧公厕的核心&#xff0c;不仅仅在于其硬件设备的智能化&#xff0c;同样重要的是其背后支持的智慧厕所公厕软件系统。让我们一起探讨&#xff0c;智慧厕所公厕软件系统有哪些核…

C语言-编译和链接

目录 1.前言2.编译2.1预处理&#xff08;预编译&#xff09;2.1.1 #define 定义常量2.1.2 #define 定义宏2.1.3带有副作用的宏参数2.1.4宏替换规则2.1.5 #和##2.1.5.1 #运算符2.1.5.2 ## 运算符 2.1.6 命名约定2.1.7 #undef2.1.8 条件编译2.1.9 头文件的包含2.1.9.1 本地文件包…