【Spring】之Ioc和Aop快速了解

这里写目录标题

  • 1.Spring框架是什么?
        • 简介:
          • 总结:Spring框架,可以理解为是一个管理者:管理整个分层架构(MVC)中的每一个对象;(每一个对象称之为bean)
  • 2.Spring框架的优缺点
    • 2.1优点
    • 2.2缺点
  • 3.框架学习什么?
  • 4.Spring框架做什么?
          • 目的:管理对象
          • IOC控制反转:(Inversion Of Control),即就是:将对象的控制权从自己new改为跟Spring要;
  • 5.Spring之IoC
    • 5.1核心概念
    • 5.2 IoC的技术实现
    • 5.3 完成IoC的步骤
    • 5.4 Spring容器对象的方法
    • 5.5 IoC的依赖注入:DI
    • 5.6 基于注解的di(重点)
      • 5.6.1 @Component注解
      • 5.6.2 @Respotory、@Service、@Controller 注解
      • 5.6.3 @Value
      • 5.6.4 @Autowired
      • 5.6.5 @Resource

1.Spring框架是什么?

简介:

Spring就像是整个项目中装配bean(对象)的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象。也可以称之为项目中的粘合剂。Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地new一个对象,而是让Spring框架帮你来完成这一切。(包括:对象的创建、对象之间的关系)

总结:Spring框架,可以理解为是一个管理者:管理整个分层架构(MVC)中的每一个对象;(每一个对象称之为bean)

2.Spring框架的优缺点

2.1优点

  • 轻量:Spring 框架运行占用的资源少,运行效率高。不依赖其他 jar
  • 针对接口编程,解耦合:Spring 提供了 Ioc 控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成。对象之间的依赖解耦合。
  • AOP 编程的支持:通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
  • 方便集成各种优秀框架:Spring提供了对各种优秀框架(如 Struts,Hibernate、MyBatis)等的直接支持。简化框架的使用。Spring 像插线板一样,其他框架是插头,可以容易的组合到一起。

2.2缺点

  • 最大的缺点就是:配置繁琐,启动慢
  • 经常要考虑第三方工具的兼容性
  • 项目的依赖管理耗时耗力

3.框架学习什么?

Spring最主要的学习内容:两个核心Ioc+Aop
Spring框架是一个软件,其它人写好的软件,所以我们要掌握的就是:

  • 1.IOC :Inversion Of Control 控制反转
    2.DI:Dependency Injection 依赖注入: 本质就是给属性赋值
    DI是依附在IOC的基础上 才得以实现
    3.AOP Aspect Oriented Programming 面向切面的编程
  • 知道框架能做什么, mybatis–访问数据库, 对表中的数据执行增删改查。
  • 框架的语法, 框架要完成一个功能,需要一定的步骤支持的,
  • 框架的内部实现, 框架内部怎么做。 原理是什么。
  • 通过学习,可以实现一个框架

4.Spring框架做什么?

目的:管理对象

Spring的核心思想是IOC(控制反转),把对象的控制权给了Spring,(底层是通过反射)即:不再需要程序员去显式地new一个对象,而是让Spring框架帮你来完成这一切。

IOC控制反转:(Inversion Of Control),即就是:将对象的控制权从自己new改为跟Spring要;
  • 最常见的方式:DI:依赖注入Dependency Injection;
  • 还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

5.Spring之IoC

5.1核心概念

  • IoC (Inversion of Control) :控制反转, 是一个理论,概念,思想。描述的:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。
    • 控制: 创建对象,对象的属性赋值,对象之间的关系管理。
    • 反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。
    • 正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
  • 容器:是一个服务器软件, 一个框架(spring就是一个容器,帮我们创建对象,管理对象之间的关系)

5.2 IoC的技术实现

DI 是ioc的技术实现

  • DI(Dependency Injection):依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,赋值,查找都由容器内部实现。
  • spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制。因此只需要传一个类名,Spring就可以创建对象。
  • spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。

5.3 完成IoC的步骤

在这里插入图片描述

  1. 添加依赖。
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.5.RELEASE</version>
</dependency>

2.创建类、接口、实现类。Spring在MVC三层架构中是针对service层的框架。

​ 3.Spring配置文件。通常命名为:applicationContext.xml。该文件类似Servlet的web.xml,在配置文件中注册类,这样Spring才能完成IOC

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--告诉spring创建对象声明bean , 就是告诉spring要创建某个类的对象id:对象的自定义名称,唯一值。 spring通过这个名称找到对象class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)spring就完成 SomeService someService = new SomeServiceImpl();spring是把创建好的对象放入到map中, spring框架有一个map存放对象的。springMap.put(id的值, 对象);例如 springMap.put("someService", new SomeServiceImpl());一个bean标签声明一个对象。--><bean id="someService" class="com.xd.service.impl.SomeServiceImpl"></bean><!--bean标签的scope属性:prototype:表示可以一次创建多个该类型对象,即多例singleton:默认值,表示一次只能创建一个该类型对象,即单例单例模式下,对象是在工厂初始化的时候创建的。多例模式是在工厂初始化之后,获取对象的时候创建的。--><bean id="someService1" class="com.xd.service.impl.SomeServiceImpl" scope="prototype"></bean><!--spring能创建一个非自定义类的对象吗, 创建一个存在的某个类的对象。--><bean id="myDate" class="java.util.Date"></bean>
</beans>
<!--    spring的配置文件1.beans : 是根标签,spring把java对象成为bean。2.spring-beans.xsd 是约束文件,和mybatis指定  dtd是一样的。都是用来控制标签里面出现的内容
-->

4. 测试类中创建Spring容器,调用Spring容器中的方法可以创建对象、获取对象的信息。

@Test
public void test02(){//使用spring容器创建的对象//1.指定spring配置文件的名称String config="applicationContext.xml";//2.创建表示spring容器的对象, ApplicationContext// ApplicationContext就是表示Spring容器,通过容器获取对象了// ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件ApplicationContext ac = new ClassPathXmlApplicationContext(config);//从容器中获取某个对象, 你要调用对象的方法//getBean("配置文件中的bean的id值")SomeService service = (SomeService) ac.getBean("someService");//使用spring创建好的对象service.doSome();
}/*
以下代码的执行原理:通过ClassPathXmlApplicationContext创建容器对象,创建容器对象的同时,ClassPathXmlApplicationContext会根据配置文件的路径去解析配置文件,解析的过程会将配置文件中所有<bean>标签中的类创建对象,默认调用无参构造方法,之后将创建好的对象以及bean标签的id保存在map中,其中id为key。在测试文件中可以调用容器对象ac的getBean方法通过id获取创建好的对象,要强转,然后调用对应方法。
*/
public void test06(){String path = "applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(path);Date nowTime = (Date)ac.getBean("myDate");System.out.println(nowTime);
}

注意:

  • ApplicationContext是一个接口,有多个实现类,通常使用ClassPathXmlApplicationContext。
  • spring默认创建对象的时间:创建spring的容器时,会创建配置文件中的所有的对象。并把这些对象放到springMap中,之后通过bean标签中的id获取创建好的对象 spring创建对象:默认调用的是无参数构造方法。

5.4 Spring容器对象的方法

//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//根据bean标签的id获取创建好的对象,getBean返回Object类型,要强转。通过service调用该类的方法
SomeService service = (SomeService) ac.getBean("someService");
//获取容器中定义的对象的数量
int nums = ac.getBeanDefinitionCount();
//容器中每个定义的对象的名称,知道了对象的名称,就可以通过getBean获取创建好的对象。
String[] names = ac.getBeanDefinitionNames();

5.5 IoC的依赖注入:DI

  • 依赖就是属性,注入就是赋值。
  • 注入的方式有set注入以及构造注入,也就是对应正转里的通过类的set方法给对象赋值,以及通过构造方法给类属性赋值。
  • 使用set注入,Spring是根据属性名去寻找对应的set方法并执行,与有没有属性,set方法中写什么内容无关。Spring只是负责找到set方法并执行。set注入也分为简单类型的注入以及引用类型的注入。
    在这里插入图片描述

具体实现:

 <?xml version="1.0" encoding="UTF-8"?>
<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"<!--声明student对象注入:就是赋值的意思简单类型: spring中规定java的基本数据类型和String都是简单类型。di:给属性赋值1. set注入(设值注入) :spring调用类的set方法, 你可以在set方法中完成属性赋值1)简单类型的set注入<bean id="xx" class="yyy"><property name="属性名字" value="此属性的值"/>一个property只能给一个属性赋值<property....></bean>2) 引用类型的set注入 : spring调用类的set方法<bean id="xxx" class="yyy"><property name="属性名称" ref="bean的id(对象的名称)" /></bean>2.构造注入:spring调用类有参数构造方法,在创建对象的同时,在构造方法中给属性赋值。构造注入使用 <constructor-arg> 标签<constructor-arg> 标签:一个<constructor-arg>表示构造方法一个参数。<constructor-arg> 标签属性:name:表示构造方法的形参名index:表示构造方法的参数的位置,参数从左往右位置是 0 , 1 ,2的顺序value:构造方法的形参类型是简单类型的,使用valueref:构造方法的形参类型是引用类型的,使用ref注意:Spring的配置文件中不用考虑bean标签的顺序,因为Spring很智能,会二次扫描--><!--set注入--><bean id="myStudent" class="com.xd.ba02.Student"><property name="name" value="张三"/><property name="age" value="20"/><property name="email" value="zhangsan@qq.com"/><!--引用类型,注意引用注入,要先要在bean中定义一个引用对象,将该对象id作为ref的值。--><property name="school" ref="mySchool"/><!--setSchool(mySchool)--></bean><!--声明School对象--><bean id="mySchool" class="com.xd.ba02.School"><property name="name" value="西安电子科技大学"/><property name="address" value="西安市雁塔区"/></bean><!--使用name属性实现构造注入--><bean id="myStudent" class="com.xd.ba03.Student"><!--实现原理:Spring扫描到该bean,看到他里面是constructor-arg标签,并且是三个该标签就知道是构造注入,并且去com.xd.ba03.Student类中找含有三个参数的有参构造方法,进行赋值。与set注入同理:Spring只是负责找有参构造方法,然后去执行,但是构造方法的声明以及方法体是由我们写的。有参构造方法声明了只能保证Spring找到了,不会报异常但是如果方法体中没有赋值,结果就是:Student对象:Student{name='null', age=0, school=null}--><constructor-arg name="name" value="张三"/><constructor-arg name="age" value="20"/><constructor-arg name="school" ref="mySchool"/></bean><!--使用index属性--><bean id="myStudent1" class="com.xd.ba03.Student"><constructor-arg index="0" value="李四"/><constructor-arg index="1" value="22"/><constructor-arg index="2" ref="mySchool"/></bean><!--省略index--><bean id="myStudent2" class="com.xd.ba03.Student"><constructor-arg value="李四"/><constructor-arg value="22"/><constructor-arg ref="mySchool"/></bean><!--声明School对象--><bean id="mySchool" class="com.xd.ba03.School"><property name="name" value="西安xxx大学"/><property name="address" value="西安市雁塔区"/></bean><!--创建File,使用构造注入--><!--构造注入创建文件对象--><bean id="myFile" class="java.io.File"><constructor-arg name="parent" value="F:\计算机\Java学习\SSM\04-Spring\源码\ch02-di-xml"/><constructor-arg name="child" value="readme.txt"/></bean>

5.6 基于注解的di(重点)

  • 基于注解的di: 通过注解完成java对象创建,属性赋值
  • 使用注解的步骤:
    1. 加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖。使用注解必须使用spring-aop依赖
    2. 在类中加入spring的注解(多个不同功能的注解)
    3. 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置
  • 组件扫描器(component-scan):组件就是java对象。使用方式实在spring配置文件中引入组件扫描器。
<!--声明组件扫描器(component-scan),组件就是java对象base-package:指定注解在你的项目中的包名。component-scan工作方式: spring会扫描遍历base-package指定的包,把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。加入了component-scan标签,配置文件的变化:1.加入一个新的约束文件spring-context.xsd2.给这个新的约束文件起个命名空间的名称-->
<context:component-scan base-package="com.xd.ba01"/>
  • 学习的注解:@Component、@Respotory、@Service、@Controller、@Value、@Autowired、@Qualifier、@Resource

5.6.1 @Component注解

@Component: 创建对象的, 等同于的功能。

  • 语法格式:@Component(value = “myStudent”) 等同于
    • 属性:value 就是对象的名称,也就是bean的id值,value的值是唯一的,创建的对象在整个spring容器中就一个;
    • 位置:在类的上面
//使用value属性,指定对象名称
//@Component(value = "myStudent")
//不指定对象名称,由spring提供默认名称: 类名的首字母小写
//@Component@Component("myStudent")  //常用
public class Student {private String name;private int age;public Student() {System.out.println("student无参构造方法执行");}setter@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

5.6.2 @Respotory、@Service、@Controller 注解

  • @Respotory、@Service、@Controller这三个注解与Component功能类似,都是创建对象。但是又有其特殊的用途,是给项目的对象分层的。
  • @Repository(用在持久层类的上面) : 放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的。
  • @Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
  • @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。
  • 对于@Component、@Respotory、@Service、@Controller。毋庸置疑的是,持久层dao用@Respotory、业务层用@Service、页面层用@Controller。对于其它不在这三层的类,但是又想创建对象,就用@Component注解。

5.6.3 @Value

  • @Value注解的作用是给对象简单类型属性赋值
  • 属性:@Value注解里的值必须是String类型,赋的值要用双引号括起来
  • 位置:
    1. 在属性定义的上面,无需set方法,推荐使用。底层用反射快。
    2. 在set方法的上面使用,调set方法。
@Component("myStudent")
public class Student {@Value("张三")private String name;@Value("20")private int age;//@Value("20") 调set方法public void setAge(int age) {System.out.println("student的set方法执行了");this.age = age;}
}

5.6.4 @Autowired

  • @Autowired注解的作用是给对象引用类型属性赋值。使用的是自动注入原理 ,支持byName, byType。默认byType。

  • 位置:

    1. 在属性定义的上面,无需set方法, 推荐使用
    2. 在set方法的上面
    @Autowired  //按byType注入
    private School school;
    
  • 如果要使用byName方式,需要做的是:

    1. 在属性上面加入@Autowired
    2. 在属性上面加入@Qualifier(value=“bean的id”) :表示使用指定名称的bean完成赋值。
    @Component("mySchool")
    public class School {
    }@Autowired
    @Qualifier(value = "mySchool") //mySchool为id
    private School school;
    
  • @Autowired注解的request属性,是一个boolean类型的,默认true。一般使用true,方便排错。

    • required=true:表示引用类型赋值失败,程序报错,并终止执行。
    • required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null,不建议用,因为赋值为null以后会出空指针异常。
    //@Autowired(required = true) 默认
    //@Autowired(required = false)不报错,不建议用
    @Autowired
    @Qualifier(value = "mySchool")
    private School school;
    

5.6.5 @Resource

  • @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,完成引用类型的自动注入,支持byName,byType。默认byName

  • 位置:

    1. 在属性定义的上面,无需set方法,推荐使用。
    2. 在set方法的上面
    @Component("school")
    public class School {
    }@Resource //默认是byName: 先使用byName自动注入,如果byName赋值失败,再使用byType
    private School school;
    
  • @Resource只使用byName方式,需要增加一个属性 name,name的值是bean的id(名称)

    @Resource(name = "mySchool")
    private School school;
    

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

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

相关文章

太空旅行:计算机技术的崭新航程

太空旅行&#xff1a;计算机技术的崭新航程 一、引言 自古以来&#xff0c;人类就对浩渺的宇宙充满了无尽的好奇和渴望。随着科技的飞速发展&#xff0c;太空旅行已经从科幻小说中的构想变为现实。在这个过程中&#xff0c;计算机技术起到了不可或缺的作用。从阿波罗时代的初…

​FL Studio2024最新版本好不好用?有哪些新功能

FL Studio2024版是一款在国内非常受欢迎的多功能音频处理软件&#xff0c;我们可以通过这款软件来对多种不同格式的音频文件来进行编辑处理。而且FL Studio 2024版还为用户们准备了超多的音乐乐器伴奏&#xff0c;我们可以直接一键调取自己需要的音调。 FL Studio 2024版不仅拥…

HarmonyOS4.0从零开始的开发教程15HTTP数据请求

HarmonyOS&#xff08;十三&#xff09;HTTP数据请求 1 概述 日常生活中我们使用应用程序看新闻、发送消息等&#xff0c;都需要连接到互联网&#xff0c;从服务端获取数据。例如&#xff0c;新闻应用可以从新闻服务器中获取最新的热点新闻&#xff0c;从而给用户打造更加丰富…

MySQL进阶2 - 索引

MySQL进阶1 - 索引 1. 索引概述2. 索引结构2.1 二叉树2.2 B-Tree(多路平衡查找树)2.3 BTree2.4 Hash 3. 索引分类4. 索引语法5. SQL性能分析5.1 SQL执行频率5.2 慢查询日志5.3 profile5.4 explain执行计划5.3.1 EXPLAIN执行计划各字段含义&#xff1a; 6. 索引使…

SpringBoot+FastJson 优雅的过滤 Response Body

Spring 源码系列 1、Spring 学习之扩展点总结之后置处理器&#xff08;一&#xff09; 2、Spring 学习之扩展点总结之后置处理器&#xff08;二&#xff09; 3、Spring 学习之扩展点总结之自定义事件&#xff08;三&#xff09; 4、Spring 学习之扩展点总结之内置事件&#xf…

手把手教你Linux查找Java的安装目录并设置环境变量以及Linux下执行javac未找到命令的保姆级教学

查找Java的安装目录 输入 java -version&#xff0c;查看是否成功安装Java 输入 which java&#xff0c;查看Java的执行路径 输入 ls -lrt /usr/bin/java 输入 ls -lrt /etc/alternatives/java&#xff0c;/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7.x86_64 就是J…

自动化测试(终章)webdriver的常用api(2)以及新的开始

目录 多层框架/窗口定位 多层框架的定位 frame是什么&#xff1f; 多层窗口定位 层级定位 使用 XPath 进行层级定位&#xff1a; 使用 CSS 选择器进行层级定位&#xff1a; 下拉框处理 alert、confirm、prompt 的处理 Alert 弹窗&#xff1a; Confirm 弹窗&#xff…

IDEA安装插件搜索不到插件的解决方法

解决idea安装所需插件&#xff0c;插件搜索不到的问题 1.通过设置代理和去掉使用安装链接的方式来解决的 File–>Settings–>Appearance & Behavior–>System Settings—>HTTP Proxy(修改为图片所示) 2.在系统设置中将更新选项中的“use secure connection”…

Xml与Json格式在线转换器

具体请前往&#xff1a;在线Json转Form表单参数工具

C语言之函数式宏

目录 函数和数据类型 函数式宏 函数和函数式宏 函数式宏和对象式宏 不带参数的函数式宏 函数式宏和逗号运算符 函数式宏和函数类似并且比函数更加灵活&#xff0c;下面我们就来学习函数式宏的相关内容。 函数和数据类型 我们来编写一个程序&#xff0c;它能计算出所读取…

Jetpack Compose开发一个Android WiFi导航应用

在以前的一篇文章构建一个WIFI室内定位系统_wifi定位系统-CSDN博客中&#xff0c;我介绍了如何用Android来测量WiFi信号&#xff0c;上传到服务器进行分析后&#xff0c;生成室内不同地方的WiFi指纹&#xff0c;从而帮助进行室内导航。当时我是用的HTML5的技术来快速开发一个An…

QQ邮箱发送工具类的实现

我们在日常开发中&#xff0c;需要实现一个对邮箱的发送&#xff0c;今天就实现邮箱的发送工具类&#xff0c;只需要一些注册邮箱之后的配置即可&#xff0c;我这边使用的是qq邮箱 0.加上依赖 <!--邮箱--><dependency><groupId>org.springframework.boot&l…

基于vue开发 - 编写登录页面样式

vue创建项目&#xff0c;使用可视化界面安装插件-CSDN博客 使用vue UI安装路由插件-CSDN博客 基于vue开发-创建登录页-CSDN博客 在src/views文件夹中创建登录页面login.vue&#xff0c;在router/index.js文件中加入登录页的路由&#xff0c;然后在浏览器中输入登录页的路径就…

FL Studio终身永久2024中文版下载安装详细操作图文步骤教程

FL Studio2024版是一款在国内非常受欢迎的多功能音频处理软件&#xff0c;我们可以通过这款软件来对多种不同格式的音频文件来进行编辑处理。而且FL Studio 2024版还为用户们准备了超多的音乐乐器伴奏&#xff0c;我们可以直接一键调取自己需要的音调。 FL Studio 2024版不仅拥…

算法设计基础——综合

算法设计基础中最基础的几种算法&#xff1a;分治法、减治法、贪心法、动态规划法、回溯法基本都掌握后&#xff0c;我们现在可以对这些算法做整体的比较&#xff0c;本次实验使用蛮力法、动态规划法、回溯法来求解0/1背包问题&#xff0c;来比较各个算法的优劣。 1. 蛮力法 …

代码随想录27期|Python|Day16|二叉树|104.二叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数

二叉树专题&#xff0c;重点掌握后续的递归和中间节点的处理。 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 本题在前一章已经解决了层序遍历的解法&#xff0c;现在来聊一下递归法。 首先需要明确两个概念&#xff1a;深度和高度。&#xff08;注意&…

抠图软件哪个好用?什么软件可以抠图换背景?

抠图软件哪个好用&#xff1f;在图片处理中&#xff0c;抠图换背景是一项常见的操作。很多新手可能会对此感到困惑&#xff0c;不知道应该使用什么软件来进行抠图换景。实际上&#xff0c;现在市面上有很多图片处理软件都具备抠图换背景的功能&#xff0c;每款软件都有其优缺点…

LVS负载均衡群集部署 DR模式

目录 DR模式直接路由 LVS-DR工作原理 LVS-DR 数据包流向分析 DR 模式的特点 DR模式 LVS负载均衡群集部署 DR模式直接路由 Direct Routing&#xff0c;简称DR模式&#xff0c;采用半开放式的网络结构&#xff0c;与TUN模式的结构类似&#xff0c;但各节点并不是分散在各地…

c语言链表的基本操作

在C语言中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表的基本操作包括创建、插入、删除和遍历等。 下面是一个简单的链表节点结构体定义&#xff1a; struct Node { int da…

Python实现员工管理系统(Django页面版 ) 六

本篇博客主要实现用户账号管理&#xff0c;这与之前的账号管理不同&#xff0c;之前的账号管理你可以理解为公司在外面买的一些手机号然后需要发放给员工做内部使用&#xff0c;而本篇博客的用户账号管理主要是为了后续的登录网页实现&#xff0c;那么我们开始今天的项目实现吧…