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

【Spring】Spring IOC DI

Spring IOC & DI

  • IOC DI入门
    • 什么是Spring
      • 什么是容器
      • 什么是IOC
    • IOC介绍
      • 传统程序开发
      • 解决方案
    • DI
  • IOC详解
    • Bean的存储
      • @Controller(控制器存储)
      • @Service(服务存储)
      • @Repository(仓库存储)
      • @Component(组件存储)
      • @Configuration(配置存储)
    • 为什么需要这么多类注解
    • 类注解之间的关系
    • 方法注解@Bean
      • 定义多个对象
    • 重命名Bean
    • 扫描路径
  • DI详解
    • 属性注入
    • 构造方法注入
    • Setter注入
    • 三种注入优缺点分析
    • @Autowired存在问题
      • @Primary
      • @Qualifier
      • @Resource

IOC DI入门

什么是Spring

Spring是一个开源的轻量级Java开发框架,它提供了全面的基础设施支持和广泛的应用程序级特性,使得Java开发变得更加简单和高效。 Spring框架的核心特点包括依赖注入(Dependency Injection)、面向切面编程(AOP)、容器、事务管理等。

依赖注入允许开发人员将组件之间的依赖关系外部化,这样可以降低类之间的耦合度,使得代码更容易维护和测试。面向切面编程则允许开发人员定义横切关注点,比如日志、事务管理等,从而实现模块化的开发。

Spring框架还提供了一个轻量级的IoC容器,用于管理JavaBean的生命周期和配置。此外,Spring还支持各种各样的应用程序级特性,包括Web开发、数据访问、安全性、远程调用等。

总的来说,Spring框架在Java企业应用开发中扮演着重要的角色,它提供了丰富的功能和灵活的设计理念,使得开发人员能够更加高效地编写可维护、可扩展的应用程序。

什么是容器

容器是⽤来容纳某种物品的(基本)装置。
⽣活中的⽔杯, 垃圾桶, 冰箱等等这些都是容器.

• List/Map -> 数据存储容器
• Tomcat -> Web 容器

什么是IOC

IOC(Inverse of Control,控制反转)是面向对象编程中的一种设计原则,它是软件开发中依赖注入(DI)的一种实现方式。在IOC中,控制权从传统的应用程序代码中转移到了外部容器或框架,使得对象之间的依赖关系由外部来管理和注入。

在传统的编程模式中,一个对象通常会直接创建和管理它所依赖的其他对象。而在IOC容器中,对象的依赖关系由容器在创建对象时进行注入,而不是由对象自身负责。这种控制权的转移使得对象之间的耦合度降低,也更有利于代码的可测试性和可维护性。

Spring框架就是一个典型的IOC容器,它通过依赖注入的方式来管理对象之间的依赖关系。开发人员只需要描述组件之间的依赖关系,比如通过配置文件或注解,然后由Spring容器负责实例化对象并注入它们之间的依赖关系。

总的来说,IOC通过将对象之间的依赖关系外部化,使得系统更加灵活、可扩展,并且有利于降低代码之间的耦合度。

IOC介绍

接下来我们通过案例来了解⼀下什么是IoC
需求: 造⼀辆⻋

传统程序开发

我们的实现思路是这样的:
先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦.

在这里插入图片描述
这样的设计看起来没有问题,但是可维护性却很低

例如我们要修改轮胎的尺寸 因为底盘是根据轮胎制造的 所以底盘的尺寸也需要修改 因为车身是根据底盘制造的 车身也需要修改 因为整个车是根据车身来制造的 所以整个车也需要修改 此时我们发现 有一处小修改则整体要受到很大的改变 可维护性很低

解决方案

在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改~

我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋
在这里插入图片描述
如何来实现呢:

我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改.此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修改任何代码,这样就完成了程序的解耦.

例如这种方式的开发 使程序之间实现解耦 就叫做IOC程序开发

IOC容器
在这里插入图片描述
从上⾯也可以看出来, IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集中管理,实现资源的可配置和易管理。第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。

  1. 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取
    就可以了
  2. 我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度.
    Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理.

DI

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊

程序运行时需要某个资源,此时容器就为其提供这个资源
从这点来看,依赖注入和控制反转是从不同角度描述同一件事情,就是通过引入IOC容器,利用依赖注入的方式,实现对对象的解耦
ioc容器中存放着对象,而我们通过di的方式,来从容器中取出这个对象来使用

IOC详解

Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出对象

通过上⾯的案例, 我们已经知道了Spring IoC 和DI的基本操作, 接下来我们来系统的学习Spring IoC和DI
的操作.前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对
象。也就是bean的存储.

Bean的存储

在之前的⼊⻔案例中,要把某个对象交给IOC容器管理,需要在类上添加⼀个注解:@Component
⽽Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解

共有两种注解可以实现

  1. 类注解: @Controller @Service @Repository @Component @Configuration
  2. 方法注解: @Bean

@Controller(控制器存储)

import org.springframework.stereotype.Controller;@Controller
public class UserController {public void sayHi(){System.out.println("hi UserController");}
}

如何观察这个对象已经存在于Spring容器中了呢?
接下来学习如何从Spring容器中获取对象

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(DemoApplication.class, args);//从Spring上下文中获取对象UserController userController = context.getBean(UserController.class);//使用对象userController.sayHi();}
}

在这里插入图片描述

上述代码是根据类型来查找对象, 如果Spring容器中, 同⼀个类型存在多个bean的话, 怎么来获取呢?
ApplicationContext 也提供了其他获取bean的⽅式, ApplicationContext 获取bean对象的功能, 是⽗类BeanFactory提供的功能
在这里插入图片描述
常用的是第一种 第二种 第五种

第一种是根据bean名获取bean
第二种是根据bean名和类型获取bean
第五种是按照bean类型和构造函数参数动态创建bean 只适用于具有原型作用域的bean

但是其中涉及到的bean 的名称 那么bean的名称是什么呢?

Bean的命名约定
程序开发人员不需要为bean指定名称,如果没有显式的提供名称,Spring容器将为该bean生成唯一的名称

  1. 命名约定使用Java标准约定作为实例字段名,也就是说,bean的名称以小写字母开头,然后使用驼峰式大小写
    比如类名UserController Bean的 名称为userController
  2. 当有多个字符并且第一个和第二个字符都是大写时,将保留原始的大小写
    比如类名UController Bean 的名称为UController

ApplicationContext 和 BeanFactory的对比

  1. 从继承关系和功能方面来说 Spring容器有两个顶级的接口 BeanFactory和ApplicationContext 其中BeanFactory提供基础的访问容器的能力 而ApplicationContext属于BeanFactory的子类,他除了继承BeanFactory的所有功能之外,还具有独特的特性,还添加了对国际化支持,资源访问支持,以及事件传播等方面的支持
  2. 从性能方面来说: ApplicationContext是一次性加载并初始化所有的Bean对象,而BeanFactory是需要哪个才去加载哪个,因此更加轻量

@Service(服务存储)

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

在这里插入图片描述
在这里插入图片描述

@Repository(仓库存储)

@Repository
public class UserRepository {public void sayHi(){System.out.println("hi UserRepository");}
}

在这里插入图片描述
在这里插入图片描述

@Component(组件存储)

@Component
public class UserComponent {public void sayHi(){System.out.println("hi UserComponent");}
}

在这里插入图片描述
在这里插入图片描述

@Configuration(配置存储)

@Configuration
public class UserConfiguration {public void sayHi(){System.out.println("hi UserConfiguration");}
}

在这里插入图片描述
在这里插入图片描述

为什么需要这么多类注解

这里的类注解和应用分层是呼应的,程序员在看到类注解之后,就能够直接了解当前类的用途

• @Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.
• @Servie:业务逻辑层, 处理具体的业务逻辑.
• @Repository:数据访问层,也称为持久层. 负责数据访问操作
• @Configuration:配置层. 处理项⽬中的⼀些配置信息

在这里插入图片描述

类注解之间的关系

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:其实这些注解里面都有一个注解@Component 说明他们本身是基于@Component的子类

@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,@Repository 等. 这些注解被称为 @Component 的衍⽣注解.

@Controller , @Service 和 @Repository ⽤于更具体的⽤例(分别在控制层, 业务逻辑层, 持久化层), 在开发过程中, 如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择

方法注解@Bean

类注解是添加到某个类上的, 但是存在两个问题:

  1. 使⽤外部包⾥的类, 没办法添加类注解
  2. ⼀个类, 需要多个对象, ⽐如多个数据源
    这种场景, 我们就需要使⽤⽅法注解 @Bean
@Component
public class BeanConfig {@Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}

在这里插入图片描述
在这里插入图片描述
方法注解要配合类注解使用

定义多个对象

对于同一个类,如何定义多个对象呢?

比如多数据源的场景,类是同一个,但是配置不同,指向不同的数据源

@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(20);return user;}
}

当我们定义了多个对象时,我们根据类型获取对象,获取到的是哪个对象呢?
在这里插入图片描述

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.Model.User' available: expected single matching bean but found 2: user1,user2at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1273)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:494)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1178)at com.example.demo.DemoApplication.main(DemoApplication.java:35)

我们发现此时代码报错了,根据报错信息,期望只有一个匹配,结果发现了两个对象 user1和user2

从报错信息中可以看出来,@Bean注解的Bean,Bean的名称就是他的方法名
我们可以通过名称来获取Bean对象

User user1 = (User) context.getBean("user1");
User user2 = (User) context.getBean("user2");
System.out.println(user1);
System.out.println(user2);

在这里插入图片描述

重命名Bean

可以通过设置name属性给Bean对象进行重命名操作
在这里插入图片描述
此时我们既可以通过user1这个名称获取User对象 也可以通过u1这个名称获取到User对象了

name=可以省略
在这里插入图片描述
只有一个名称时 括号也可以省略
在这里插入图片描述

扫描路径

使用四个注解声明的bean一定会生效吗? 答案是不一定 因为bean要想生效 还需要被Spring扫描

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

也就是使用@ComponentScan来配置扫描路径

为什么我们在之前没有配置扫描路径也可以扫描到bean呢?
我们虽然没有显示的配置@ComponentScan,但是在启动类的注解上已经包含了这个注解了
在这里插入图片描述
默认的扫描范围是SpringBoot启动类所在包及其子包

DI详解

上面我们详解了控制反转IoC的细节,下面我们介绍DI的细节

依赖注⼊是⼀个过程,是指IoC容器在创建Bean时, 去提供运⾏时所依赖的资源,⽽资源指的就是对象.在上⾯程序案例中,我们使⽤了@Autowired这个注解,完成了依赖注⼊的操作.简单来说, 就是把对象取出来放到某个类的属性中.

在⼀些⽂章中, 依赖注⼊也被称之为 “对象注⼊”, “属性装配”, 具体含义需要结合⽂章的上下⽂来理解

关于依赖注入,Spring也给我们提供了三种方式

  1. 属性注入
  2. 构造方法注入
  3. Setter注入

属性注入

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中。
Service 类的实现代码如下:

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

Controller类实现

@Controller
public class UserController {@Autowired//将UserService注入到Usercontroller中private UserService userService;public void sayHi(){System.out.println("hi UserController");userService.sayHi();}
}

在这里插入图片描述
在这里插入图片描述

构造方法注入

@Controller
public class UserController {//方式二:构造方法注入//将UserService注入到Usercontroller中private UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi UserController");userService.sayHi();}
}

注意事项:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法

Setter注入

注意事项:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法

@Controller
public class UserController {//方式三:Setter注入//将UserService注入到Usercontroller中private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi UserController");userService.sayHi();}
}

在这里插入图片描述

三种注入优缺点分析

构造方法注入:

优点:构造方法注入可以保证对象的完整性,因为它要求在创建对象时必须提供所需的属性值。这样可以避免对象处于不完整或不一致的状态。同时,构造方法注入也使得对象在创建后就可以是不可变的。
缺点:构造方法注入在参数较多的情况下会显得冗长,特别是当属性较多、属性之间有依赖关系时。此外,对于每个依赖项,都需要提供一个相应的构造方法,这可能会导致类的构造方法过于臃肿。

Setter方法注入:

优点:Setter方法注入相对于构造方法注入,使用起来更加灵活,不需要在创建对象时传递所有依赖项。可以通过调用各个Setter方法来逐个注入属性。同时,Setter方法注入也便于后续修改或替换属性的值。
缺点:Setter方法注入破坏了对象的完整性,因为依赖项可以在对象创建后的任何时候进行注入。这可能导致对象在某些操作中处于不一致的状态。此外,它也增加了类的可变性,可能导致对象的不可变性和线程安全性问题。

字段注入:

优点:字段注入简单直观,没有构造方法或Setter方法的冗长代码。对于小型的应用或快速原型开发,字段注入可能更加方便。
缺点:字段注入破坏了封装性,将依赖项直接暴露为公共字段。这违反了面向对象编程的原则,可能导致代码可维护性和测试性的问题。此外,字段注入也不利于单元测试和模拟依赖项。

@Autowired存在问题

当同一个类型存在多个bean时,使用@Autowired会存在问题

@Controller
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate User user;public void sayHi() {System.out.println("hi UserController");userService.sayHi();System.out.println(user);}
}

在这里插入图片描述

报错的原因是,非唯一的Bean对象
那么如何解决上述问题呢? Spring提供了以下几种解决方案

@Primary

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

@Component
public class BeanConfig {@Primary@Bean("user1")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(20);return user;}
}

@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。 在@Qualifier的value属性中,指定注⼊的bean的名称。

@Controller
public class UserController {@Autowiredprivate UserService userService;@Autowired@Qualifier("user2")private User user;public void sayHi() {System.out.println("hi UserController");userService.sayHi();System.out.println(user);}
}

@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Resource

使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

@Controller
public class UserController {@Autowiredprivate UserService userService;@Resource(name = "user2")private User user;public void sayHi() {System.out.println("hi UserController");userService.sayHi();System.out.println(user);}
}

@Autowird 与 @Resource的区别
@Autowired 是spring框架提供的注解,⽽@Resource是JDK提供的注解
@Autowired 默认是按照类型注⼊,⽽@Resource是按照名称注⼊

相关文章:

【Spring】Spring IOC DI

Spring IOC & DI IOC DI入门什么是Spring什么是容器什么是IOC IOC介绍传统程序开发解决方案 DI IOC详解Bean的存储Controller(控制器存储)Service(服务存储)Repository(仓库存储)Component(组件存储)Configuration(配置存储) 为什么需要这么多类注解类注解之间的关系方法注…...

一招解密网络流量瓶颈!

前言 我们曾介绍过观测云提供全面的基础设施监测方案(参见《全方位监控基础设施,坚实守护您的业务稳定!》),能够高效全面地帮助您实时观测所有的基础设施对象及云产品等,赋能您的业务稳定发展。今天我们将…...

某校帮签到小程序m 加密参数解析

小程序解密清参考我以前的文章 VX小程序逆向 js版本 function n(e, a) {var t (65535 & e) (65535 & a);return (e >> 16) (a >> 16) (t >> 16) << 16 | 65535 & t };function i(e, a, t, n, r, i, s) {return o(a & n | t &…...

Node.js |(六)express框架 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;express使用&#x1f407;初体验&#x1f407;express路由⭐️路由的使用⭐️获取请求参数⭐️获取路由参数&#x1f525;练习&#xff1a;根据路由参数响应歌手信息…...

包教包会:Mysql主从复制搭建

笑小枫的专属目录 一、无聊的理论知识1. 主从复制原理2. 主从复制的工作过程3. MySQL四种同步方式 二、docker下安装、启动mysql1. 安装主库2. 安装从库 三、配置Master(主)四、配置Slave(从)五、链接Master(主)和Slave(从)六、主从复制排错1. 错误&#xff1a;error connectin…...

Subset Selection

白话解释&#xff1a;https://www.geeksforgeeks.org/feature-subset-selection-process/ 貌似有一种比较常见的方法&#xff0c;称为多元逐步回归有3种筛选自变量的方法 &#xff08;1&#xff09;向前法&#xff1a;n个因变量情况&#xff0c;慢慢增加因变量到方程中&#x…...

【测开求职】面试题:计算机网络 精简版整理

本篇文章整理的是在秋招过程中遇到的计算机网络高频面试题,应付部分中小厂的测试开发工程师面试完全没有问题,如果时间充足的话,建议再看一下笔者的另外一篇文章:【测开求职】面试题:计算机网络 详细版整理,会让你对整个计算机网络有足够全面深刻的理解,亲测应付各个大厂…...

设计模式-代理模式(delegate)

什么是代理&#xff1f; 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方…...

MongoDB 安装与配置

MongoDB 安装与配置 MongoDB 是一个高性能、开源的 NoSQL 数据库&#xff0c;它提供了丰富的查询功能和高可用性。本文将详细讲解 MongoDB 的安装与配置过程。 1. MongoDB 安装 1.1 Windows 平台安装 下载 MongoDB 安装包 访问 MongoDB 官方下载页面&#xff08;https://w…...

rabbitMq创建交换机,以及路由键绑定队列教程

创建交换机&#xff1a; 创建队列&#xff1a; 创建路由&#xff0c;绑定到交换机&#xff1a;...

odoo16前端框架源码阅读——ormService.js

odoo16前端框架源码阅读——ormService.js 路径&#xff1a;addons\web\static\src\core\orm_service.js 简单翻译一下代码中的注释&#xff1a; ORM服务是js代码和python的ORM层通信的标准方法。 然后讲了One2many and Many2many特使的指令格式&#xff0c;每个指令都是3元…...

详谈滑动窗口算法与KMP算法区别以及二者在什么场景下使用

什么是滑动窗口算法 滑动窗口算法是一种用于解决数组&#xff08;或字符串&#xff09;中子数组&#xff08;或子字符串&#xff09;问题的算法。该算法通过维护一个固定大小的窗口&#xff08;通常是两个指针&#xff09;&#xff0c;该窗口在数组上滑动&#xff0c;以寻找符…...

k8s、数据存储

数据存储的概念 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的状态&#xff08;镜像最初的状态&#xff09;…...

Vue生命周期全解析:从工厂岗位到任务执行,一览无遗!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、生…...

常见产品结构四大类型 优劣势比较

一般&#xff0c;我们通过产品架构来构建用户体验&#xff0c;这样可以提供更清晰的导航和组织、优化用户流程和交互、增强产品的可扩展性和可维护性&#xff0c;提升用户的满意度和忠诚度。如果没有明确的产品结构&#xff0c;可能会导致功能冗余或功能缺失、交互流程混乱等问…...

如何优雅的开发?试试这个低代码项目

一、前言 众所周知&#xff0c;开发一个大型的企业级系统&#xff0c;公司往往需要大量的人力做支持后盾&#xff0c;如需要需求分析师、数据库管理员、前台美工、后台程序员、测试人员等。 在快速发展中的企业里&#xff0c;尤其是中小企业&#xff0c;都是一个萝卜多个坑&…...

个人开发常用idea插件

idea重装后必须要配置的几项&#xff1a; Maven&#xff1a; File-->Settings-->Maven字体&#xff1a; IDE字体设置&#xff1a;File-->Settings-->Appearance&#xff0c;设置成Consolas&#xff0c;Size&#xff1a;18代码字体设置&#xff1a;File-->Setti…...

如何使用ArcGIS Pro制作个性三维地形图

制作三维地图制作的多了&#xff0c;想着能不能换个“口味”&#xff0c;恰好看见制作六边形蜂窝图&#xff0c;灵光一闪&#xff0c;想着将二者结合&#xff0c;将平滑的三维地形图改成柱状图&#xff0c;从结果来看还可以&#xff0c;这里将制作方法分享给大家&#xff0c;希…...

支撑企业数字化经营,《2023指标平台白皮书》正式发布

导语 随着宏观经济步入新常态和市场不确定性加剧&#xff0c;我国企业的经营环境正在发生深刻变化。为了更好地应对挑战&#xff0c;企业需转向高质量发展&#xff0c;通过精细化管理等手段优化业务结构、提高运营效率和创新能力。在数字经济时代&#xff0c;借助数字化手段实现…...

【Linux】Linux的两种连接文件方法(ln | 符号链接和硬链接)

在一次线上配置文件时&#xff0c;不小心将配置文件config.py放在了错误的地方&#xff0c;而目前项目已经运行&#xff0c;又不能重新配置启动项目&#xff0c;那么如何将其他地方的文件放在当前配置目录来使用&#xff0c;并实现其他地方文件改动&#xff0c;配置目录下文件也…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统

Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

用递归算法解锁「子集」问题 —— LeetCode 78题解析

文章目录 一、题目介绍二、递归思路详解&#xff1a;从决策树开始理解三、解法一&#xff1a;二叉决策树 DFS四、解法二&#xff1a;组合式回溯写法&#xff08;推荐&#xff09;五、解法对比 递归算法是编程中一种非常强大且常见的思想&#xff0c;它能够优雅地解决很多复杂的…...

动态规划-1035.不相交的线-力扣(LeetCode)

一、题目解析 光看题目要求和例图&#xff0c;感觉这题好麻烦&#xff0c;直线不能相交啊&#xff0c;每个数字只属于一条连线啊等等&#xff0c;但我们结合题目所给的信息和例图的内容&#xff0c;这不就是最长公共子序列吗&#xff1f;&#xff0c;我们把最长公共子序列连线起…...

HTML中各种标签的作用

一、HTML文件主要标签结构及说明 1. <&#xff01;DOCTYPE html> 作用&#xff1a;声明文档类型&#xff0c;告知浏览器这是 HTML5 文档。 必须&#xff1a;是。 2. <html lang“zh”>. </html> 作用&#xff1a;包裹整个网页内容&#xff0c;lang"z…...

解密鸿蒙系统的隐私护城河:从权限动态管控到生物数据加密的全链路防护

摘要 本文以健康管理应用为例&#xff0c;展示鸿蒙系统如何通过细粒度权限控制、动态权限授予、数据隔离和加密存储四大核心机制&#xff0c;实现复杂场景下的用户隐私保护。我们将通过完整的权限请求流程和敏感数据处理代码&#xff0c;演示鸿蒙系统如何平衡功能需求与隐私安…...