Spring框架-入门(IOC,DI)

文章目录

  • Spring框架
    • 简介
    • 创建Spring项目
    • 理解IOC和DI:
      • IOC控制反转
        • 示例
          • pom.xml
          • Person.java
          • applicationContext.xml
          • PersonTest.java
      • DI依赖注入
        • 传统的方式
          • GreetingService.java
          • GreetingServiceImpl.java
          • GreetingTest.java
        • 使用DI依赖注入
          • GreetingService.java
          • GreetingServiceImpl.java
          • AppConfig.java
          • AppTest.java

Spring框架

spring官网;https://spring.io/

简介

Spring框架是一个开源的Java应用程序框架,它提供了一种全面的编程和配置模型,可用于构建现代化的基于Java的企业级应用程序。

Spring框架提供的核心功能包括控制反转(IoC)、依赖注入(DI)、面向切面编程(AOP)、数据访问、事务管理、Web应用程序开发等方面。它可以与其他技术和框架无缝集成,如Hibernate、MyBatis、Struts、Servlet API,SpringMVC等。

使用Spring框架可以简化Java应用程序的开发过程,减少代码量,提高代码的可重用性和可维护性。它也提供了各种扩展和插件,以满足特定场景下的需求。

Spring框架的设计思想是基于松耦合、可扩展和可重用的原则,使得Java开发者可以更专注于业务逻辑的实现,而不必关注底层技术的细节。它已成为Java企业级应用程序开发中最流行和广泛使用的框架之一。

创建Spring项目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?> <!-- xml声明,指定版本和编码 -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd"><!-- pom文件的根元素 -->

    <!-- 指定pom模型的版本 -->
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目所属组织或公司的唯一标识符 -->
    <groupId>com.sin</groupId>
    <!-- 项目的唯一标识符 -->
    <artifactId>spring_demo</artifactId>
    <!-- 项目的版本号 -->
    <version>1.0-SNAPSHOT</version>

    <!-- 固定项目依赖版本 -->
    <properties>
        <!-- 指定源代码的字符编码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 指定使用的Spring框架版本 -->
        <spring.version>5.3.13</spring.version>
    </properties>

    <dependencies>
        <!-- spring-core库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring-context库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring-beans库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

理解IOC和DI:

在传统的程序

User.java

package com.sin.pojo;

/**
 * @createTime 2023/12/29 16:22
 * @createAuthor SIN
 * @use
 */
public class User {
    private int id;
    private String name;


    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

UserDao.java

package com.sin.Dao;

import com.sin.pojo.User;

/**
 * @createTime 2023/12/29 16:22
 * @createAuthor SIN
 * @use
 */
public class UserDao {
    public User getUser(int userId) {
        // 模拟从数据库中获取用户信息的逻辑
        // 这里假设直接返回一个User对象
        User user = new User();
        user.setId(userId);
        user.setName("张三");
        return user;
    }
}

UserService.java

package com.sin.service;

import com.sin.Dao.UserDao;
import com.sin.pojo.User;

/**
 * @createTime 2023/12/29 16:21
 * @createAuthor SIN
 * @use
 */
public class UserService {

    private UserDao userDao;

    public UserService() {
        userDao = new UserDao();
    }

    /**
     * 该方法允许外部设置UserDao对象,这种方式称之为依赖注入
     *
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUserInfo(int userId) {
        // 通过UserDao获取用户信息
        User user = userDao.getUser(userId);
        // 处理用户信息
        System.out.println("用户ID: " + user.getId());
        System.out.println("用户姓名: " + user.getName());
    }
}

在这里插入图片描述

在编写过程中发现:

  1. 需要获取数据时,需要创建UserSercie对象,每次创建UserService对象都会创建出一新的UserDao对象,这样做会导致内存的浪费,因为我们可能只需要一个UserDao对象,而不是每次都创建一个新的对象。
  2. 这种实现方式还存在对象生命周期的问题。如果UserService对象被销毁了,那么与之关联的UserDao对象也将被销毁,这可能会导致数据丢失或其他意想不到的问题。
  3. 高耦合性:UserServiceUserDao之间的关系非常紧密,UserService需要知道如何创建UserDao对象,并且需要在方法中直接调用UserDao的方法。这样做会使得代码高度耦合,难以维护。
  4. 代码重复:如果有多个类需要使用UserDao对象进行数据访问,那么就需要在每个类中都写出类似的代码,这将导致大量重复的代码,增加了代码的冗余。
  5. 可测试性差:在单元测试时,我们希望能够对UserService进行测试,而不是测试UserDao的实现。但是,由于UserService依赖于UserDao,因此需要在测试中实例化UserDao对象并设置到UserService中,这就使得测试变得困难。
  6. 不易扩展:如果我们需要更改UserDao的实现方式,比如从数据库中获取用户信息改为从Web服务中获取,那么就需要修改UserService的代码,这样做会使得代码更加脆弱,不易扩展。

这些问题可以通过使用IOC容器和DI框架来解决。在Spring框架中,我们可以通过配置文件或注解来告诉Spring容器如何创建对象并管理对象之间的依赖关系。Spring容器会在需要时自动创建对象,并确保每个对象只被创建一次,并且可以在整个应用程序中共享。这样做不仅可以提高应用程序的性能,还可以减少内存消耗和对象生命周期的问题。

在这里插入图片描述

IOC控制反转

控制反转(Inversion of Control,简称IoC)是一种软件设计原则,也是面向对象编程中的一种设计模式。它的核心思想是将对象的创建和依赖关系的管理交给容器来完成,而不是由对象自身来创建和管理其依赖的对象。

传统的程序设计中,对象之间的依赖关系常常通过对象自身来创建和管理。例如,在一个类中直接使用new关键字来创建其他类的实例,这样就导致了类与类之间的紧耦合,使得代码难以维护、扩展和测试。

而采用IoC的方式,对象之间的依赖关系被反转了。具体来说,IoC通过引入一个容在这里插入图片描述
器(如Spring框架的ApplicationContext),容器负责创建对象并管理对象之间的依赖关系。在IoC容器中,我们可以配置对象的创建方式、依赖关系以及其他属性,然后由容器来实例化对象,并将所需的依赖注入到对象中。

IoC的优点包括:

  1. 解耦:IoC可以降低对象之间的耦合度,使得代码更加灵活、可维护和可扩展。

  2. 便于测试:由于依赖关系由容器管理,我们可以很容易地对对象进行单元测试,而不需要真正地创建依赖对象。

  3. 可以更好地支持面向接口编程:通过IoC容器可以轻松地切换不同的实现类,从而支持面向接口编程的设计原则。

  4. 提高了代码的可读性和可维护性:通过配置文件或注解来管理对象的创建和依赖关系,使得代码的逻辑更加清晰、易于理解和维护。

示例
pom.xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.13</version>
</dependency>

spring-context是Spring的核心模块之一,提供了Spring应用程序上下文的基础设施支持,也是Spring框架中最重要的部分之一。它负责管理Spring应用程序中所有bean的声明周期,并提供了依赖注入和面向切面编程等重要的特性。

主要提供的功能:

  1. ApplicationContext接口:这是Spring应用程序上下文的核心接口,定义了获取bean、注册bean、发布事件等操作的API。
  2. BeanFactory接口:定义了Spring IoC容器的基本功能,这是Spring应用程序上下文的基础。
  3. AOP支持:Spring提供了强大的AOP支持,可以在应用程序中轻松实现面向切面编程。
  4. 事件处理:Spring提供了事件机制,允许应用程序中的各个组件之间进行通信和协作。
  5. SpEL表达式语言:Spring提供了一种表达式语言,允许开发者使用类似于EL的语法来处理复杂的表达式和逻辑。
  6. 数据绑定:Spring提供了一种灵活的数据绑定机制,可以将请求参数、属性文件、XML文档等各种数据源与Java对象进行绑定。
Person.java
package com.sin.pojo;

/**
 * @createTime 2024/1/2 8:44
 * @createAuthor SIN
 * @use
 */
public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
applicationContext.xml

注意:文件位置必须在src/main/resources目录下。这是默认的资源目录,Spring会自动将其包含在类路径中。

<?xml version="1.0" encoding="UTF-8"?><!-- XML声明,xml版本和编码格式 -->

<!-- spring配置文件起点  -->
<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">

    <!--
        创建一个bean
            id : bean名称
            class :SpringBean对应的Java对象
    -->
    <bean id="person" class="com.sin.pojo.Person">
        <!-- 对bean的属性进行赋值 -->
        <property name="name" value="张三"/>
        <property name="age" value="18"/>
    </bean>


</beans>

bean : 是指Spring容器管理的Java对象,是Spring框架的核心概念之一。在Spring中Bean是应用程序的基本构建模块,代表着一个可重用的组件,它可以是任何普通的Java对象,也可以是由Spring容易创建和管理的特殊对象。这些对象可以通过Spring容器进行创建,配置和管理,从而实现依赖注入和面向切面编程等功能。

为什么使用Spring配置文件来赋值?

可以将应用程序中各个组件之间的依赖关系和属性值都统一管理,从而实现松耦合的设计和高度可配置性。

PersonTest.java
package com.sin.pojo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @createTime 2024/1/2 8:48
 * @createAuthor SIN
 * @use 通过Spring容器获取并使用一个被管理的Bean
 */
public class PersonTest {

    public static void main(String[] args) {
        /**
         * 创建ApplicationContext对象,
         * ApplicationContext : 是Spring的顶层接口,用于表示整个应用程序的上下文环境
         * ClassPathXmlApplicationContext :通过指定文件来获取spring容器
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        /**
         * 从容器中获取指定bean
         * getBean :返回类型为Object,我们需要将其为具体类型,
         */
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
    }
}

流程图
请添加图片描述

在整个过程中发现不用创建Person对象了,不需要new Person();减少了内存空间的占用。整个过程将对象的创建交给Spring来管理。

DI依赖注入

依赖注入(Dependency Injection,简称DI)是控制反转(IoC)的一个具体实现方式。它是指通过外部将对象的依赖关系注入到对象中,而不是由对象自身来创建和管理依赖的对象。

在传统的程序设计中,对象通常需要自己创建和管理其所依赖的其他对象。这种方式导致了对象之间的紧耦合,使得代码难以测试、扩展和维护。而采用依赖注入,我们将对象的依赖关系交给容器来管理,对象只需声明自己需要哪些依赖,容器则负责将相应的依赖注入到对象中。

依赖注入可以通过以下几种方式实现:

  1. 构造函数注入(Constructor Injection):通过对象的构造函数来传递依赖。在对象创建时,容器会根据构造函数的参数类型来自动注入所需的依赖。

  2. Setter方法注入(Setter Injection):通过对象的setter方法来注入依赖。容器会调用对象的setter方法,并将相应的依赖作为参数传入。

  3. 接口注入(Interface Injection):通过对象实现一个特定的接口,该接口定义了注入依赖的方法。容器会在对象创建后,调用接口方法并注入相应的依赖。

依赖注入的优点包括:

  1. 解耦:通过将对象的依赖关系交给容器管理,实现了对象之间的解耦,使得代码更加灵活、可维护和可扩展。

  2. 可测试性:由于对象的依赖关系由容器注入,我们可以很容易地使用模拟对象来进行单元测试,而不需要真实的依赖对象。

  3. 灵活性:依赖注入使得切换和替换不同的依赖实现变得容易,从而支持面向接口编程和可插拔的架构设计。

传统的方式
GreetingService.java
package com.sin.service;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public interface GreetingService {

    public void sayHello();
}
GreetingServiceImpl.java
package com.sin.service.impl;

import com.sin.service.GreetingService;

import java.awt.*;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public class GreetingServiceImpl implements GreetingService {

    @Override
    public void sayHello() {
        System.out.println("hello,world!");
    }
}
GreetingTest.java
package com.sin.test;

import com.sin.service.impl.GreetingServiceImpl;
import org.junit.Test;

/**
 * @createTime 2024/1/2 10:53
 * @createAuthor SIN
 * @use
 */
public class GreetingTest {

    @Test
    public void testGreeting(){
        GreetingServiceImpl greetingService = new GreetingServiceImpl();

        greetingService.sayHello();
    }
}
使用DI依赖注入
GreetingService.java
package com.sin.service;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public interface GreetingService {

    public void sayHello();
}
GreetingServiceImpl.java
package com.sin.service.impl;

import com.sin.service.GreetingService;

import java.awt.*;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public class GreetingServiceImpl implements GreetingService {

    @Override
    public void sayHello() {
        System.out.println("hello,world!");
    }
}
AppConfig.java
package com.sin.config;

import com.sin.service.GreetingService;
import com.sin.service.impl.GreetingServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @createTime 2024/1/2 10:56
 * @createAuthor SIN
 * @use
 */
@Configuration // 标记为一个配置类,该类将提供Bean的定义和配置,
public class AppConfig {

    /**
     * 定义一个Bean,方法名getGreetingService将作为Bean的名称,默认为方法名(也可以通过name属性指定其他名称)。
     * @return 创建GreetingServiceImpl对象, 该对象将被Spring容器管理,
     */
    @Bean
    public GreetingService getGreetingService() {
        return new GreetingServiceImpl();
    }
}

AppTest.java
package com.sin.test;

import com.sin.config.AppConfig;
import com.sin.service.GreetingService;
import com.sin.service.impl.GreetingServiceImpl;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @createTime 2024/1/2 10:57
 * @createAuthor SIN
 * @use
 */
public class AppTest {

    @Test
    public void test(){
        /**
         * 创建spring容器并加载配置类
         * new AnnotationConfigApplicationContext(AppConfig.class)创建对象时加载配置类
         */
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取依赖注入的Bean
        // 通过bean名称来获取
        GreetingService greetingService1 =(GreetingService) context.getBean("getGreetingService");
        // 通过bean类型来获取
        GreetingService greetingService2 =context.getBean(GreetingService.class);


        // 使用依赖注入的Bean
        greetingService1.sayHello();
        greetingService2.sayHello();

    }
}

AnnotationConfigApplicationContext是一个基于注解配置方式的Spring容器,它负责加载配置类、注册和管理Bean的定义、提供依赖注入功能以及管理Bean的生命周期。

在这里插入图片描述

两种方式都可以用来获取Spring容器中的Bean,如果知道Bean的名称就可以使用Bean的名称作为参数来获取。如果只知道Bean的类型,则使用类型作为参数来获取。

流程图

请添加图片描述

总结:如果不使用Spring框架的依赖注入,需要手动创建和管理对象,这可能会导致代码冗余和可维护性的问题。但对于简单的应用程序,手动创建对象可能是可行的。

使用Spring框架的依赖注入,发现朱需要创建一次GreetingServiceImpl对象,就可以多次使用。通过声明式配置,简化了对象的创建和组装过程,降低了代码复杂度。Spring容器又可以管理依赖对象的生命周期,避免了内存泄漏的问题,大大减轻了JVM的压力。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows平台的网速监控悬浮窗软件Traffic Monitor使用体验

Windows平台的网速监控悬浮窗软件Traffic Monitor使用体验 一、Traffic Monitor介绍1.1 Traffic Monitor简介1.2 Traffic Monitor版本介绍1.3 Traffic Monitor特点 二、下载及安装Traffic Monitor2.1 下载Traffic Monitor2.2 安装Traffic Monitor 三、Traffic Monitor的使用体验…

VSCode上远程调试代码出现的问题

记录一下&#xff1a; 真的是汗流浃背了&#xff0c;师妹叫帮忙如何在VSCode上远程调试代码&#xff0c;一些自己已经经历过的问题&#xff0c;现在已经忘记了。又在网上一顿搜索&#xff0c;这次记录下吧。。。 出现以下问题&#xff1a; 1. 终端界面总是sh-4.4 $ &#xff…

C#基础:字段的初始化、继承

一、字段的初始化 class Test {static int Main(string[] args){var list new List<Calculate>();//1.Calculate中加入abvar calculate new Calculate { a 2, b 3 };//2.Calculate中加入Value列表calculate.Values.Add(new Value { id 1, value 6 });calculate.Va…

杨中科 ASP.NET MVC

ASP.NET Core 入门 什么是ASP.NET CORE 1、ASP.NET Core是.NET中做Web开发的框架 2、ASP.NET Core MVC 传统MVC项目&#xff0c;前后端都做在一起 3、ASP.NET Core Web API: 前后端分离、多端开发。(是属于MVC中的一部分) 4、ASPNET Core MVC其实包含Web API&#xff0c;不过…

openGauss学习笔记-186 openGauss 数据库运维-升级-集群管理组件增量升级

文章目录 openGauss学习笔记-186 openGauss 数据库运维-升级-集群管理组件增量升级186.1 操作步骤186.2 集群管理组件升级前准备与检查186.3 检查安装版本是否支持集群管理组件升级186.4 集群管理组件升级186.5 集群管理组件升级后检查 openGauss学习笔记-186 openGauss 数据库…

GitLab添加SSH key

SSH 为 Secure Shell 的缩写&#xff0c;SSH 为建立在应用层基础上的安全协议。 SSH 是目前较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议。 利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。 ssh-keygen 从客户端来看&#xff0c;SSH提供两种级…

C++八股学习心得.4

1.C 类 & 对象 C 在 C 语言的基础上增加了面向对象编程&#xff0c;C 支持面向对象程序设计。类是 C 的核心特性&#xff0c;通常被称为用户定义的类型。 类用于指定对象的形式&#xff0c;它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在…

系列六、RestTemplate

一、RestTemplate 1.1、概述 RestTemplate是一种便捷的访问RestFul服务的模板类&#xff0c;是Spring提供的用于访问Rest服务的客户端模板工具集&#xff0c;它提供了多种便捷访问远程HTTP服务的方法。 1.2、API https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE…

论文查重降重写成大白话可以吗

大家好&#xff0c;今天来聊聊论文查重降重写成大白话可以吗&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 论文查重降重&#xff1a;用大白话解析 一、引言 写论文是每个…

斯坦福和 Meta学者发现Gemini在常识推理任务中有较强潜力;初学者GPT:Ai和LLM资源

&#x1f989; AI新闻 &#x1f680; 斯坦福和 Meta学者发现Gemini在常识推理任务中有较强潜力 摘要&#xff1a;斯坦福和Meta的学者发表论文为Gemini正名&#xff0c;他们发现之前对Gemini的评估并不能完全捕捉到其真正的常识推理潜力。他们设计了需要跨模态整合常识知识的任…

【自动化测试】转行人员在面试中被问及计算机基础知识该怎么办?????(长文,预计三小时阅读)

看前提示&#xff0c;本文共4W字&#xff0c;76道题&#xff08;附答案&#xff09; 全部看完预计三个小时&#xff0c;如果觉得时间长&#xff0c;可以直接跳转到文末&#xff0c;有本文的word版提供下载 近些年软件测试岗位从转行的来人越来越多&#xff0c;占比高达44% 软件…

普中STM32-PZ6806L开发板(HAL库函数实现-访问多个温度传感器DS18B20)

简介 我们知道多个DS18B20的DQ线是可以被挂在一起的, 也就是一根线上可以访问不同的DS18B20而不会造成数据错乱, 怎么做到的&#xff0c;其实数据手册都有说到&#xff0c; 就是靠64-bit ROM code 进行识别, 也可以理解成Serial Number进行识别, 因为主要差异还是在Serial Numb…

每日好题:acwing:(走迷宫bfs的运用)好久没更新啦

走迷宫&#xff1a; 给定一个 nm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 0 或 1&#xff0c;其中 0 表示可以走的路&#xff0c;1 表示不可通过的墙壁。 最初&#xff0c;有一个人位于左上角 (1,1)处&#xff0c;已知该人每次可以向上、下、左…

修改选择框el-select样式,显示及下拉样式

修改选择框el-select样式,显示及下拉样式 .el-input__inner {background: rgba(25, 126, 195, 0.2);border: none;color: #fff; }.el-select-dropdown {background: rgba(19, 73, 104, 0.79);border: 2px solid #48e3ff;border-radius: 0; }.el-popper .popper__arrow {display…

华硕ASUS RT-AC1200 pandavan老毛子 128M DDR固件

原版硬件只支持64M DDR2&#xff0c;更换了128M内存&#xff0c;结果找不到对应的固件&#xff0c;而且全部都是英文版的 所以自己编译了中文版的pandavan老毛子&#xff0c;下载位置可能资源审核中&#xff1a;

MT9201 1.2MHz,3V~24V输入高效增压白色LED驱动器 丝印B9HB

描述 MT9201是一个升压转换器&#xff0c;设计用于从单电池锂离子电池驱动多达7系列白色led。MT9201使用电流模式&#xff0c;固定频率结构来调节LED电流&#xff0c;它通过外部电流感测电阻器来测量。其低200mV反馈电压降低了功率损耗&#xff0c;提高了效率。MT9201包括欠电压…

富文本BraftEditor引起的bug

1、BraftEditor踩坑1 #基于之前写的一篇BraftEditor的使用# 1. 问题起源&#xff1a; 打开编辑弹窗--> 下面页面所示--> 当进行分类选择时候&#xff0c;就会报错&#xff0c;并且这个报错还不是一直都有&#xff0c;6次选择出现一次报错吧 2. 解决&#xff1a; 2.1 起…

MySQL概述

M y S Q L 概述 \huge{MySQL概述} MySQL概述 MySQL学习笔记 引入 什么是数据库&#xff1f; D \color{red}D Data B \color{red}B Base&#xff08;DB&#xff09;&#xff0c;存储和管理数据的仓库。 使用的各种电子产品的网页&#xff0c;页面中的数据都是动态的&#xf…

python pillow(PIL)库使用介绍

Python 图像库向 Python 解释器添加了图像处理功能。 该库提供了广泛的文件格式支持、高效的内部表示和相当强大的图像处理功能。 核心图像库旨在快速访问以几种基本像素格式存储的数据。它应该为通用图像处理工具提供坚实的基础。 概述 Python 图像库将图像处理功能添加到…

MSE Serverless 正式商用,构建低成本高弹性的微服务架构

作者&#xff1a;问思 微服务架构充分提升了研发效率&#xff0c;解决了复杂业务系统的快速迭代问题。但随着业务及技术演进&#xff0c;各种微服务组件也愈发复杂。如何实现更敏捷的开发&#xff0c;降低微服务开发运维成本&#xff0c;做到全链路的弹性&#xff0c;保障整个…