Spring IOC 和 DI详解

news2024/9/24 1:17:00

目录

一、IOC介绍

1、什么是IOC

2、通过案例来了解IoC

 2.1 传统程序开发

2.2 问题分析

2.3 解决方案

 2.4 IoC程序开发

2.5 IoC 优势

二、DI介绍

三、IOC 详解

3.1 Bean的存储

3.1.1  @Controller(控制器存储)

3.1.2 @Service(服务存储)

 3.1.3 @Repository(仓库存储)

 3.1.4 @Component(组件存储)

 3.1.5 @Configuration(配置存储)

3.2 为什么要这么多类注解?

3.3 方法注解 @Bean

3.3.1 方法注解要配合类注解使用

 3.3.2 定义多个对象

3.3.3 重命名 Bean

四、DI 详解

4.1 属性注入

4.2 构造方法注入

4.3 Setter 注入

4.4 @Autowired存在问题


一、IOC介绍

1、什么是IOC

IOC 是Spring的核心思想。
其实IOC在前面 Spring MVC 部分我们就已经用到了。代码部分, 我们在类上添加@RestController 和 @Controller 注解, 就是把这个对象交给Spring管理Spring 框架启动时就会加载该类。 把对象交给Spring管理, 就是IoC思想。
IOC: Inversion of Control (控制反转), 也就是说 Spring 是一个"控制反转"的容器.
什么是控制反转呢? 也就是控制权反转。 什么的控制权发生了反转? 获得依赖对象的过程被反转了。
也就是说, 当需要某个对象时, 传统开发模式中需要自己通过 new 创建对象, 现在不需要再进行创 建, 把创建对象的任务交给容器, 程序中只需要依赖注入 (Dependency Injection,DI)就可以了.
这个容器称为:IoC容器. Spring是一个IoC容器, 所以有时Spring 也称为Spring 容器。

2、通过案例来了解IoC

 案例:造一辆车。

实现思路:
先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最 后根据车身设计好整个汽车(Car)。
这里就出现了⼀个"依赖"关系:汽车依赖车身,车身依赖底盘,底 盘依赖轮子。

 2.1 传统程序开发

最终程序的实现代码如下:
public class NewCarExample {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
    /**
     * 汽车对象
     */
    static class Car {
        private Framework framework;
        public Car() {
            framework = new Framework();
            System.out.println("Car init....");
        }
        public void run(){
            System.out.println("Car run...");
        }
    }
    /**
     * 车身类
     */
    static class Framework {
        private Bottom bottom;
        public Framework() {
            bottom = new Bottom();
            System.out.println("Framework init...");
        }
    }
    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        public Bottom() {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }
    /**
     * 轮胎类
     */
    static class Tire {
        // 尺⼨
        private int size;
        public Tire(){
            this.size = 17;
            System.out.println("轮胎尺⼨:" + size);
        }
    }
}

2.2 问题分析

这样的设计看起来没问题,但是可维护性却很低.
如果接下来需求有了变更: 随着对的车的需求量越来越大, 个性化需求也会越来越多,我们需要加工多种尺寸 的轮胎.
那这个时候就要对上面的程序进行修改了,修改后的代码如下所示:
 /**
     * 轮胎类
     */
    static class Tire {
        // 尺⼨
        private int size;
        public Tire(int size){
            this.size = size;
            System.out.println("轮胎尺⼨:" + size);
        }
    }

 修改之后, 底盘类就会报错:

那么我们将底盘类的构造方法也传一个参数后,底盘类方法不再报错。但其他调用程序又会出现错误,所以我们都要进行修改。

修改后完整代码:

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.3 解决方案

在上面的程序中, 我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改. 同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改, 也就是整个设计几乎都得改。
我们尝试换⼀种思路, 我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计 底盘,最后根据底盘来设计轮子. 这时候,依赖关系就倒置过来了。
如何来实现呢:
我们可以尝试不在每个类中自己创建下级类,如果自己创建下级类就会出现当下级类发生改变操作, 自己也要跟着修改.
此时,我们只需要将原来由自己创建的下级类, 改为传递的方式(也就是注入的方式) ,因为我们不 需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修 改任何代码,这样就完成了程序的解耦。
我们可以这样理解:
当我们造一辆汽车时,如果我们不自己制作轮胎,而是把轮胎外包出去,那 么即使当用户的需求发生改变,需要改变车轮尺寸大小时,我们只需要向代理工厂下订单就行了,我们自身是不需要出力的。

 2.4 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.5 IoC 优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car
我们发现了⼀个规律,改进之后程序的实现代码,类的创建顺序是反的。
传统代码是 Car 控制并创建了 Framework,Framework 控制并创建了 Bottom,依次往下,而改进之后的控制权发生了反转,不再 是使用方对象创建并控制依赖对象了,而是把依赖对象注入将当前对象中,依赖对象的控制权不再由当前类控制了.
这样的话, 即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的 实现思想。
那什么是控制反转容器呢, 也就是IoC容器:
这部分代码, 就是IoC容器做的工作.
IOC容器具备以下优点:
资源不由使用资源的双方管理,而由不使用资源的第三方管理 ,这可以带来很多好处。
第一,资源集 中管理,实现资源的可配置和易管理。
第⼆,降低了使用资源双方的依赖程度,也就是我们说的耦合 度。
  1. 资源集中管理: IoC容器会帮我们管理一些资源(对象等), 我们需要使用时, 只需要从IoC容器中去取就可以了
  2. 我们在创建实例的时候不需要了解其中的细节, 降低了使用资源双方的依赖程度, 也就是耦合度.

Spring 就是一种IoC容器, 帮助我们来做了这些资源管理。

二、DI介绍

DI: Dependency Injection(依赖注入)
容器在运行期间, 动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。
上述代码中, 是通过构造函数的方式, 把依赖对象注入到需要使用的对象中的。
IoC 是一种思想,也是"目标",而思想只是⼀种指导原则,最终还是要有可行的落地方案,而 DI 就属于 具体的实现。所以也可以说, DI 是IoC的一种实现

三、IOC 详解

既然 Spring 是一个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:
Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由 Spring来负责对象的创建和销毁。
我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出 对象。
IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对 象。 也就是bean的存储

3.1 Bean的存储

Spring框架为了更好地服务web应用程序, 提供了丰富的注解.
共有两类注解类型可以实现:
  • 类注解:@Controller、@Service、@Repository、@Component、@Configuration.
  • 法注解:@Bean.

3.1.1  @Controller(控制器存储)

 使用 @Controller 存储 bean 的代码如下:

@Controller // 将对象存储到 Spring 中
public class UserController {
    public void sayHi(){
        System.out.println("hi,UserController...");
    }
}

然后我们来验证一下Spring容器中是否已经有了该对象:

从Spring 容器中获取对象(bean):

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
		//从Spring上下⽂中获取对象
		UserController userController = context.getBean(UserController.class);
		//使⽤对象
		userController.sayHi();
	}
}
观察运行结果, 发现成功从Spring中获取到Controller对象, 并执行Controller的sayHi方法:
如果把@Controller删掉, 再观察运行结果,会发现报错,报错信息显示:找不到类型是: com.example.demo.controller.UserController 的 bean。
获取bean对象的其他方式:
上述代码是根据类型来查找对象, 如果Spring容器中,同一个类型存在多个bean的话, 怎么来获取呢?
ApplicationContext 也提供了其他获取bean的方式, ApplicationContext 获取bean对象的功能, 是父 类BeanFactory提供的功能.
我们来看一下其父类代码:
public interface BeanFactory {

	//以上省略...

	// 1. 根据bean名称获取bean
	Object getBean(String var1) throws BeansException;
	// 2. 根据bean名称和类型获取bean
	<T> T getBean(String var1, Class<T> var2) throws BeansException;
	// 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean
	Object getBean(String var1, Object... var2) throws BeansException;
	// 4. 根据类型获取bean
	<T> T getBean(Class<T> var1) throws BeansException;
	// 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的
	bean
	<T> T getBean(Class<T> var1, Object... var2) throws BeansException;

	//以下省略...
}

其中第一、二、四种方式,是常见的。其中有通过 bean 的名称来获取 bean。

Spring bean是Spring框架在运行时管理的对象, Spring会给管理的对象起一个名字. 给每个对象起一个名字, 根据Bean的名称(BeanId)就可以获取到对应的对象.

 Bean 命名约定

程序开发人员不需要为bean指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该 bean 生成唯一的名称.
命名约定使用Java标准约定作为实例字段名。也就是说, bean名称以小写字母开头,然后使用驼峰式大小写。

比如:

类名: UserController, Bean的名称为: userController
类名: AccountManager, Bean的名称为: accountManager
类名: AccountService, Bean的名称为: accountService

也有一些特殊情况, 当有多个字符并且第一个和第二个字符都是大写时, 将保留原始的大小写。

比如:
类名: UController, Bean的名称为: UController
类名: AManager, Bean的名称为: AManager

 在知道 bean 的名称约定之后,我们来看看以多种方式获取 bean 对象是如何实现的。

示例代码:

@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        //获取Spring上下⽂对象
        ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
        //从Spring上下⽂中获取对象

        //根据bean类型, 从Spring上下⽂中获取对象
        UserController userController1 = context.getBean(UserController.class);

        //根据bean名称, 从Spring上下⽂中获取对象
        UserController userController2 = (UserController)context.getBean("userController");

        //根据bean类型+名称, 从Spring上下⽂中获取对象
        UserController userController3 =
                context.getBean("userController",UserController.class);

        System.out.println(userController1);
        System.out.println(userController2);
        System.out.println(userController3);
    }
}

运行结果:

 

 我们可以看到,地址一样,说明对象是同一个。

3.1.2 @Service(服务存储)

使用 @Service 存储 bean 的代码如下所示:

@Service
public class UserService {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }
}

 获取 bean 的代码同 @Controller 部分的代码,我们可以获取 bean ,让 bean 对象执行 sayHi 方法,看打印结果,来判断是否获取到了bean。

此处,若把 @Service 注解去掉,会出现 与去掉 @Controller 注解 一样的错误。

 3.1.3 @Repository(仓库存储)

 使用@Repository 存储 bean 的代码如下所示:

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

 3.1.4 @Component(组件存储)

 使用@Component 存储 bean 的代码如下所示:

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

 3.1.5 @Configuration(配置存储)

使用 @Configuration 存储 bean 的代码如下所示:
@Configuration
public class UserConfiguration {
    public void sayHi() {
        System.out.println("Hi,UserConfiguration~");
    }
}

3.2 为什么要这么多类注解?

这与我们前面文章所介绍的应用分层是呼应的。可以让我们看到类注解之后,就能直接了解当前类的用途。
  • @Controller:控制层, 接收请求, 对请求进行处理, 并进行响应.
  • @Servie:业务逻辑层, 处理具体的业务逻辑.
  • @Repository:数据访问层,也称为持久层. 负责数据访问操作
  • @Configuration:配置层. 处理项目中的一些配置信息.

3.3 方法注解 @Bean

类注解是添加到某个类上的, 但是存在两个问题:
  1. 使用外部包里的类, 没办法添加类注解
  2. 一个类, 需要多个对象, 比如多个数据源
这种场景, 我们就需要使用方法注解 @Bean。

3.3.1 方法注解要配合类注解使用

在 Spring 框架的设计中, 方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中 如下代码所示:
@Component
public class BeanConfig {
    @Bean
    public User user(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
}

 来获取 bean 对象:

@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        //获取Spring上下⽂对象
        ApplicationContext context =
                SpringApplication.run(SpringIocDemoApplication.class, args);
        //从Spring上下⽂中获取对象
        User user = context.getBean(User.class);
        //使⽤对象
        System.out.println(user);
    }
}

执行代码,可以看到正确结果:

 3.3.2 定义多个对象

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

示例代码:
@Component
public class BeanConfig {
    @Bean
    public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
    @Bean
    public User user2(){
        User user = new User();
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}

在上述代码,我们一个类型(User),定义了多个对象。

那我们根据类型获取对象, 获取的是哪个对象呢?我们可以通过代码来看一下:
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        //获取Spring上下⽂对象
        ApplicationContext context =
                SpringApplication.run(SpringIocDemoApplication.class, args);
        //从Spring上下⽂中获取对象
        User user = context.getBean(User.class);
        //使⽤对象
        System.out.println(user);
    }
}
执行代码,我们可以发现报错了。
报错信息显示: 期望只有一个匹配, 结果发现了两个, user1, user2
从报错信息中, 也可以看出来, @Bean 注解的bean, bean的名称就是它的方法名。
接下来我们根据名称来获取bean对象:
@SpringBootApplication
public class SpringIocDemoApplication {
    public static void main(String[] args) {
        //获取Spring上下⽂对象
        ApplicationContext context =
                SpringApplication.run(SpringIocDemoApplication.class, args);
        //根据bean名称, 从Spring上下⽂中获取对象
        User user1 = (User) context.getBean("user1");
        User user2 = (User) context.getBean("user2");
        System.out.println(user1);
        System.out.println(user2);
    }
}

运行结果:

可以看到, @Bean 可以针对同一个类, 定义多个对象.

3.3.3 重命名 Bean

 我们可以通过设置 name 属性给 Bean 对象进行重命名操作,如下代码所示:

@Bean(name = {"u1","user1"})
public User user1(){
    User user = new User();
    user.setName("zhangsan");
    user.setAge(18);
    return user;
}

代码中,name={} 可以省略,直接写为:@Bean({"u1","user1"})

 此时我们使用名字 u1 就可以获取到 User 对象了。

注意:

使用五大注解声明的bean,不一定生效,要想生效,就必须让Spring扫描到这些注解。

启动类默认扫描的范围是 SpringBoot启动类所在包及其子包。
若想让 Spring 扫描到默认范围以外的地方,就需要通过 @ComponentScan 来配置扫描路径。

四、DI 详解

依赖注入是一个过程,是指IoC容器在创建Bean时, 去提供运行时所依赖的资源,而资源指的就是对象.
关于依赖注入, Spring也给我们提供了三种方式:
  1. 属性注入
  2. 构造方法注入
  3. Setter 注入

4.1 属性注入

属性注入是使用 @Autowired 实现的

我们以 Service 类注入到 Controller 类中 为例:

Service 类的实现代码如下:
@Service
public class UserService {
    public void sayHi() {
        System.out.println("Hi,UserService");
    }
}

Controller 类的实现代码如下:

@Controller
public class UserController {
    //注⼊⽅法1: 属性注⼊
    @Autowired
    private UserService userService;

    public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
    }
}

如果不加  @Autowired 注解,也就是userService对象没有注入进来,当执行到 userService.sayHi() 时,会报空指针异常。

4.2 构造方法注入

构造方法注入是在类的构造方法中实现注入,示例代码:
@Controller
public class UserController2 {
    //注⼊⽅法2: 构造⽅法
    private UserService userService;

    @Autowired
    public UserController2(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(){
        System.out.println("hi,UserController2...");
        userService.sayHi();
    }
}
注意事项: 如果类只有一个构造方法,那么 @Autowired 注解可以省略;如果类中有多个构造方法, 那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。

4.3 Setter 注入

Setter 注入和属性的 Setter 方法实现类似,只不过 在设置 set 方法的时候需要加上 @Autowired 注解 ,如下代码所示:
@Controller
public class UserController3 {
    //注⼊⽅法3: Setter⽅法注⼊
    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public void sayHi(){
        System.out.println("hi,UserController3...");
        userService.sayHi();
    }
}

4.4 @Autowired存在问题

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

示例代码:

@Component
public class BeanConfig {
    @Bean("u1") //bean 重命名为u1
    public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
    @Bean
    public User user2() {
        User user = new User();
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}
@Controller
public class UserController {
    //注⼊user
    @Autowired
    private User user;

    public void sayHi(){
        System.out.println("hi,UserController...");
        System.out.println(user);
    }
}

运行代码发现会报错,报错的原因是,非唯一的 Bean 对象。

为了解决上述问题,Spring提供了以下几种解决方案:
  1. @Primary
  2. @Qualifier
  3. @Resource

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

@Component
public class BeanConfig {

    @Primary //指定该bean为默认bean的实现
    @Bean("u1") //bean 重命名为u1
    public User user1(){
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
    @Bean
    public User user2() {
        User user = new User();
        user.setName("lisi");
        user.setAge(19);
        return user;
    }
}
使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean 的名称。
@Qualifier注解不能单独使用,必须配合@Autowired使用:
@Controller
public class UserController {
    @Qualifier("user2") //指定bean名称
    @Autowired
    private User user;
    public void sayHi(){
        System.out.println("hi,UserController...");
        System.out.println(user);
    }
}
使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
@Controller
public class UserController {
    @Resource(name = "user2")
    private User user;
    public void sayHi(){
        System.out.println("hi,UserController...");
        System.out.println(user);
    }
}
@Autowird 与 @Resource的区别:
  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。
  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入. 相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。

关于 Spring IOC(控制权反转)、DI(依赖注入)就先介绍到这里了,希望可以给你带来帮助呀!

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

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

相关文章

照片相似性搜索引擎Embed-Photos;赋予大型语言模型(LLMs)视频和音频理解能力;OOTDiffusion的基础上可控制的服装驱动图像合成

✨ 1: Magic Clothing Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上 Magic Clothing是一个以可控制的服装驱动图像合成为核心的技术项目&#xff0c;建立在OOTDiffusion的基础上。通过使用Magic Clothing&#xf…

hadoop安装记录

零、版本说明 centos [rootnode1 ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)jdk [rootnode1 ~]# java -version java version "1.8.0_311" Java(TM) SE Runtime Environment (build 1.8.0_311-b11) Java HotSpot(TM) 64-Bit Server VM (…

STL_List与萃取

List 参考文章: https://blog.csdn.net/weixin_45389639/article/details/121618243 List源码 List中节点的定义&#xff1a; list是双向列表&#xff0c;所以其中节点需要包含指向前一节点和后一节点的指针&#xff0c; data是节点中存储的数据类型 template <class _Tp&g…

海康Visionmaster-常见问题排查方法-启动阶段

VM试用版启动时&#xff0c;弹窗报错&#xff1a;加密狗未安装或检测异常&#xff1b;  问题原因&#xff1a;安装VM 的时候未选择软加密&#xff0c;选择了加密狗驱动&#xff0c;此时要使用软授权就出现了此现象。  解决方法&#xff1a; ① 首先确认软加密驱动正确安装…

网络工程师----第十一天

OSPF&#xff1a; 对称加密算法&#xff1a; 也称为私钥加密或单密钥算法&#xff0c;是一种加密方式&#xff0c;其中加密和解密使用相同的密钥。这种算法的优点包括加密解密速度快、计算量小&#xff0c;适用于大量数据的加密。然而&#xff0c;它的缺点是密钥的安全性难以保…

OpenCV-基于阴影勾勒的图纸清晰度增强算法

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 实现原理 大家在工作和学习中&#xff0c;无论是写报告还是论文&#xff0c;经常有截图的需求&#xff0c;比如图表、图纸等&…

医学影像图像去噪:滤波器方法、频域方法、小波变换、非局部均值去噪、深度学习与稀疏表示和字典学习

医学影像图像去噪是指使用各种算法从医学成像数据中去除噪声,以提高图像质量和对疾病的诊断准确性。MRI(磁共振成像)和CT(计算机断层扫描)是两种常见的医学成像技术,它们都会受到不同类型噪声的影响。 在医学影像中,噪声可能来源于多个方面,包括成像设备的电子系统、患…

计算机网络【CN】Ch4 网络层

总结 一台主机可以有多个IP地址&#xff0c;但是必须属于多个逻辑网络【不同的网络号】。 解决IP地址耗尽&#xff1a; IP地址结构&#xff1a; 划分子网&#xff1a;&#x1d43c;&#x1d443;地址<网络号>,<子网号>,<主机号> CIDR&#xff1a;IP地址{&…

C++:特殊成员函数

构造函数、析构函数和拷贝构造函数是C类中的三种特殊成员函数&#xff0c;它们分别用于对象的初始化、清理和拷贝操作。 1.构造函数&#xff08;Constructor&#xff09;&#xff1a;构造函数在对象创建时自动调用&#xff0c;用于初始化对象的成员变量。它的名称与类名相同&a…

Vs Code npm install 报错解决方法

用的人家的前端框架发现是封装过的&#xff0c;要修改人家前端的话还得把前端源码放在Vs Code 上运行&#xff0c;后端放在IDEA上运行&#xff0c;然后前后端并行开发&#xff0c;在配置前端环境时遇到&#xff1a; npm install 这个的原因是我把node下载到D盘了权限不够框框爆…

Linux:服务器硬件及RAID配置

Linux&#xff1a;服务器硬件及RAID配置 服务器 服务器是什么 服务器的英文名称为“ Server”&#xff0c;是指在网络上提供各种服务的高性能计算机。作为网络的节点&#xff0c;存储、处理网络上80&#xff05;的数据、信息&#xff0c;因此也被称为网络的灵魂。 服务器和…

数据挖掘实验(Apriori,fpgrowth)

Apriori&#xff1a;这里做了个小优化&#xff0c;比如abcde和adcef自连接出的新项集abcdef&#xff0c;可以用abcde的位置和f的位置取交集&#xff0c;这样第n项集的计算可以用n-1项集的信息和数字本身的位置信息计算出来&#xff0c;只需要保存第n-1项集的位置信息就可以提速…

怎么通过Javascript脚本实现远程控制一路开关

怎么通过Javascript脚本实现远程控制一路开关呢&#xff1f; 本文描述了使用Javascript脚本调用HTTP接口&#xff0c;实现控制一路开关。一路开关可控制一路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称1智能WiFi…

信息系统项目管理师0062:需求分析(5信息系统工程—5.1软件工程—5.1.2需求分析)

点击查看专栏目录 文章目录 5.1.2需求分析1.需求的层次2.需求过程3.UML4.面向对象分析记忆要点总结5.1.2需求分析 软件需求是指用户对新系统在功能、行为、性能、设计约束等方面的期望。根据IEEE的软件工程标准词汇表,软件需求是指用户解决问题或达到目标所需的条件或能力,是…

入坑 Node.js 1

原文&#xff1a;https://blog.iyatt.com/?p14717 前言 前面刚刚对 Spring Boot 有了个概念&#xff0c;再来学学 Node.js&#xff0c;顺便当学 JavaScript&#xff0c;为后面入前端做准备。 环境 Node.js 20.12.2 官方 API 文档&#xff1a;https://nodejs.org/docs/lat…

iOS OC项目中引入SwiftUI文件

iOS OC项目中引入SwiftUI文件 1、创建SwiftUI文件 2、第一次创建时&#xff0c;Xcode会提示桥接&#xff0c;选择 Creat Bridging Header即可。 3、创建swift管理类 /**在UIKit中使用SwiftUI&#xff0c;需要使用UIHostingController对SwiftUI进行包装&#xff0c;返回的是U…

小游戏:贪吃蛇

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;贪吃蛇 &#x1f337;追光的人&#xff0c;终会万丈光芒 目录 &#x1f3dd;1.头文件&#xff1a; &#x1f3dd;2.实现文件&#xff1a; &#x1f3dd;3.测试文件 &#xff1a; 前言&#…

STM32自动光控窗帘程序+Proteus仿真图 H桥L298驱动电机

目录 1、前言 2、仿真图 3、源程序 资料下载地址&#xff1a;STM32自动光控窗帘程序Proteus仿真图 H桥L298驱动电机 1、前言 基于STM32F103设计的智能光控窗帘&#xff0c;包含STM32芯片、光敏电阻、LCD1602显示屏、电机驱动控制模块等。 备注&#xff1a;通过ARM内部的…

网络安全数字孪生:一种新颖的汽车软件解决方案

摘要 随着汽车行业转变为数据驱动的业务&#xff0c;软件在车辆的开发和维护中发挥了核心作用。随着软件数量的增加&#xff0c;相应的网络安全风险、责任和监管也随之增加&#xff0c;传统方法变得不再适用于这类任务。相应的结果是整车厂和供应商都在努力应对汽车软件日益增加…

CAS和synchronized原理

synchronized与CAS Synchronized 原理加锁工作过程一些优化 CAS实现原子类 小结 Synchronized 原理 synchronized 既可以是乐观锁, 也可以是悲观锁.synchronized 既可以是轻量级锁, 也可以是重量级锁.synchronized 重量级锁是由系统的互斥锁实现的; 轻量级锁是基于自旋锁实现的…