【JavaEE进阶】——一万字带你深刻理解Spring IoCDI

目录

🚩Spring是什么

🎈什么是容器?

🎈什么是 IoC?

📝传统开发思路

📝IOC思想

📝IoC 优势

🎈DI 介绍

🚩IoC 详解

🎈Bean的存储

🔴五大类注解

📝@Controller(控制器存储)

👩🏻‍💻获取bean对象的方式

📝@Service(服务存储)

📝@Repository(仓库存储)

📝@Component(组件存储)

📝@Configuration(配置存储)

🍭类注解之间的关系

🔴⽅法注解 @Bean

🔴Bean传递参数

🎈SpringBoot特点

🚩DI 详解

🎈属性注⼊

🎈构造方法注入

🎈Setter注入

🔴@Autowired存在问题

📝解决方法一 属性名和bean名称相同

📝解决方法二 @Primary

📝解决方法三 @Qualifier

📝解决方法四 @Resource

🔴五大注解修改名以及Bean修改名

📝Bean修改名

📝类注解修改


我们学习了springBoot和spring mvc的开发,完成了基本的功能开发了,但是真正的spring,spring mvc以及spring boot之间又有什么关系呢?


🚩Spring是什么

spring是一个开源框架,让我们的开发更加的简单,支持广泛的应用场景,有着活跃而庞大的社区,这可能就是spring一直存在的原因吧。

我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的 IoC 容器
什么是容器?IOC是什么?

🎈什么是容器?

容器是⽤来容纳某种物品的(基本)装置。⸺来⾃:百度百科
⽣活中的⽔杯, 垃圾桶, 冰箱等等这些都是容器.
我们想想,之前课程我们接触的容器有哪些?
List/Map -> 数据存储容器
Tomcat -> Web 容器

🎈什么是 IoC?

IOC是Spring的核心思想,什么是IOC呢?IOC是一种思想,之前我们在学习spring MVC 中,我们在类上添加@RestController 和 @Controller 注解,就是把这个类对象交给spring管理,spring框架启动时就会加载该类,把对象交给spring管理,就是IOC思想。

IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器
  • 什么是控制反转?——控制权反转
  • 控制权反转具体是体现在哪里呢?

获得依赖对象的过程中被反转了,也就是说,当需要某个对象时 ,传统开发模式都是自己new创建对象,现在不需要自己去创建对象了,把创建的对象的任务交给容器(也就是spring容器),程序中只需要注入(Dependency Injection,DI)就可以了.

  • spring是根据什么创建对象的呢?

之前我们在学习spring MVC 中,我们在类上添加@RestController 和 @Controller 注解,就是把这个类对象交给spring管理。——通过注解


IOC思想(在我的理解):通过注解对该对象进行了控制,将其存入到spring容器中,让spring对这个对象进行管理和创建。

相信大家看完上述的描述,对IOC思想了解了很多。下面我们通过一个案例进行加深理解。


📝传统开发思路

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

我们首先在newCarExample中创建car,然后在car类中创建Framework,然后根据车身创建底盘,然后进而创建轮胎。

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);
 }
 }
}
设计问题:
这样的设计看起来没问题,但是可维护性却很低.
接下来需求有了变更: 随着对的⻋的需求量越来越⼤, 个性化需求也会越来越多,我们需要加⼯多种尺⼨的轮胎.
那这个时候就要对上⾯的程序进⾏修改了,修改后的代码如下所⽰:
我们要加上轮胎大小属性,我们要给size传到底盘,然后底盘传到车身,最后传到车子。size这个属性增加了程序的耦合度,让每个对象都要对size进行添加。
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.
程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)

📝IOC思想

解决方案:
在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改。
我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝, ⻋⾝依赖汽⻋。
我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改. 此时, 我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式) ,因为我们不 需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修 改任何代码,这样就完成了程序的解耦.
我们把创建子类的方式,改成注入传递的方式。
public class newCarExample {
    public static void main(String[] args) {
        Tire tire=new Tire(20);
       Bottom bottom=new Bottom(tire);
       Framwork framwork=new Framwork(bottom);
       Car car=new Car(framwork);
       car.run();
    }
}


public class Tire {
    private int size;
    public Tire(int size){
        System.out.println("轮胎的尺寸:"+size);
    }
}


//轮胎依赖底盘
public class Bottom {
    private Tire tire;
    public Bottom(Tire tire){
        this.tire=tire;
        System.out.println("bottom init ..........");
    }
}


//底盘依赖机身
public class Framwork {
    private  Bottom bottom;
    public Framwork(Bottom bottom){
        this.bottom=bottom;
        System.out.println("framwork init....");
    }
}


//机身依赖车子
public class Car {
    private Framwork framwork;
    public Car(Framwork framwork){
        this.framwork=framwork;
        System.out.println("car init....");
    }
    public void run(){
        System.out.println("car run....");
    }
}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了

📝IoC 优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再 是使⽤⽅对象创建并控制依赖对象了,⽽是把 依赖对象注⼊将当前对象中,依赖对象的控制权不再由 当前类控制了。而是由newCarExample总体进行创建(也就是Spring容器)
传统上我们都在当前类进行new对象,现在我们只需要将属性注入,创建对象交给容器管理创建,这就是IOC思想。


🎈DI 介绍

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。
程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过 引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
上述代码中, 是通过构造函数的⽅式, 把依赖对象注⼊到需要使⽤的对象中的.。
IoC 是⼀种思想,也是"⽬标", ⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现.
我们不用自己创建该依赖对象,我们只需要将依赖对象注入到所需要的对象中,创建对象的事情交给spring来管理。
⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和⽬标(是
IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是 DI。

对IOC和DI有了初步的了解,我们接下来就要学习spring IOC和DI。

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

🚩IoC 详解

通过上⾯的案例, 我们已经知道了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(控制器存储)
使⽤ @Controller 存储 bean 的代码如下所⽰:
@Controller
public class TestController {
   public void doController(){
       System.out.println("do controller....");
   }
}
如何观察这个对象已经存在Spring容器当中了呢? 接下来我们学习如何从Spring容器中获取对象
ApplicationContext 翻译过来就是: Spring 上下⽂
因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下⽂。
观察运⾏结果, 发现成功从Spring中获取到Controller对象, 并执⾏Controller的doController⽅法

为什么TestController对象存入到spring中呢?@Controller注解的作用是什么呢?

NoSuchBeanDefinitionException表示没有注解,那么spring就获取不了该对象bean。所以我们知道了@Controller这个注解就是为了让我们获得该Bean对象存储到spring中,后续我们在主程序中getBean就获取到该对象了,所以我们上面也说了,注解的作用就是让程序运行时,控制这个注解对应的类对象。后续对这个对象进行创建和获取。


👩🏻‍💻获取bean对象的方式

⽐如
  • 类名: UserController, Bean的名称为: userController
  • 类名: AccountManager, Bean的名称为: accountManager
  • 类名: AccountService, Bean的名称为: accountService
也有⼀些特殊情况, 当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写. 这些规则 与java.beans.Introspector.decapitalize (Spring在这⾥使⽤的)定义的规则相同.
⽐如
  • 类名: UController, Bean的名称为: UController
  • 类名: AManager, Bean的名称为: AManage
根据这个命名规则, 我们来获取Bean

1》根据类型来获取

2》根据名称来获取

根据名称获取的时候,首字母小写,我们看到类名时TestController,不是前两个字母大写,那么就将大写字母转成小写字母即可。并且类型要转换。

2》根据类型和名称来获取


📝@Service(服务存储)
@Service
public class TestService {
    public void doService(){
        System.out.println("do service.....");
    }
}
public class IocDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context=SpringApplication.run(IocDemoApplication.class);
        TestService testService=context.getBean(TestService.class);
        testService.doService();
    }
}


📝@Repository(仓库存储)
📝@Component(组件存储)
📝@Configuration(配置存储)

代码形式都是和上述的两个方式相同


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

🍭类注解之间的关系
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:
其实这些注解⾥⾯都有⼀个注解 @Component ,说明 它们本⾝就是属于 @Component 的"⼦类". @Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service , @Repository 等. 这些注解被称为 @Component 的衍⽣注解。
@Controller , @Service @Repository ⽤于更具体的⽤例(分别在控制层, 业务逻辑层, 持
久化层), 在开发过程中, 如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择。
⽐如杯⼦有喝⽔杯, 刷⽛杯等, 但是我们更倾向于在⽇常喝⽔时使⽤⽔杯, 洗漱时使⽤刷⽛杯。不同的场景运用不同的功能,我们在实际开发中,我们实现业务的时候,我们会更倾向于用@Service。

🔴⽅法注解 @Bean

为什么需要方法注解呢?如何我们使用内部包的其他类或者外部包的其他类,我们就无法添加类注解的,还有一种是一个类中需要多个对象,这些场景,都是需要使用方法注解@Bean.
类注解是添加到某个类上的, 但是存在两个问题:
  • 1. 使⽤外部包⾥的类, 没办法添加类注解
@Data
public class UserInfo {
    private Integer age;
    private String name;
    private Integer id;
}
@Configuration
public class BeanConfigTest {
    @Bean
    public UserInfo userInfo(){
        UserInfo userInfo=new UserInfo();
        userInfo.setName("张老师");
        userInfo.setAge(20);
        userInfo.setId(1);
        return userInfo;
    }
}

在 Spring 框架的设计中, ⽅法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中

  • 2. ⼀个类, 需要多个对象, ⽐如多个数据源
@Configuration
public class BeanConfigTest {
    @Bean
    public UserInfo userInfo(){
        UserInfo userInfo=new UserInfo();
        userInfo.setName("张老师");
        userInfo.setAge(20);
        userInfo.setId(1);
        return userInfo;
    }
    
    @Bean
    public UserInfo userInfo2(){
        UserInfo userInfo=new UserInfo();
        userInfo.setName("chlorine");
        userInfo.setAge(19);
        userInfo.setId(2);
        return userInfo;
    }
}

我们观察上述代码,是同一个类型,存在多个Bean,我们此时是无法通过类型来获取bean。程序会启动失败。

同一个类型,存在多个Bean,我们此时可以通过名称或者(名称+类型)来获取Bean


🔴Bean传递参数

定义了一个叫name2的String类型的对象,定义了一个叫name的String类型的对象。

我们根据名称去拿,如果对应的对象只有一个时,就直接赋值,如果有多个时,通过名称去匹配,如果名称都不匹配,按照内部逻辑来匹配。


🎈SpringBoot特点

Q: 使⽤前⾯学习的四个注解声明的bean,⼀定会⽣效吗?
A: 不⼀定(原因:bean想要⽣效,还需要被Spring扫描)

约定大于配置

比如我们上课,教务处在开学前都会给给定的课表都约定好,等到开学后学生按照课程就直接去哪个教室上课就行了,而配置就是临时老师说调课,就需要老师临时通知,但是肯定是学校提前弄好的课程进行更多,而少数是进行老师进行调课。

springboot也有一个自己的约定,其中之一体现就是:扫描路径。默认的扫描路径是:启动类所在的目录及其子孙目录。

我们创建下项目默认的启动类都是在最大的包中,如果我们调动启动类的位置。将其移到controller包下,我们现在执行Configuration包下的程序,看是否成功。

报错,显示无法找到UserInfo,我们上面说Springboot约定大于配置,约定默认扫描路径是启动类所在的目录及其子孙目录。此时所在的目录和子孙目录,并没有user'Info而在自己的同级目录里,此时报错。

我们就相当于老师突然调课,我们需要给springboot增加配置。添加注解@Component,这个注解可以指定扫描路径,如果没有指定,默认就是该注解所在类的目录及其子孙目录。

我们增加注解,让启动类进行扫描到Configuration包下的类。执行成功。


推荐做法:
把启动类放在我们希望扫描的包的路径下, 这样我们定义的bean就都可以被扫描到

🚩DI 详解

上⾯我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注⼊DI的细节。
依赖注⼊是⼀个过程,是指IoC容器在创建Bean时, 去提供运⾏时所依赖的资源,⽽资源指的就是对象.在上⾯程序案例中,我们使⽤了 @Autowired 这个注解,完成了依赖注⼊的操作.简单来说, 就是把对象取出来放到某个类的属性中.
关于依赖注⼊, Spring也给我们提供了三种⽅式:
  • 1. 属性注⼊(Field Injection)
  • 2. 构造⽅法注⼊(Constructor Injection)
  • 3. Setter 注⼊(Setter Injection)
下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中

🎈属性注⼊

属性注⼊是使⽤ @Autowired 实现的,将UserInfo类注⼊到 Controller 类中
@Controller
public class UserController {
    @Autowired
    private  UserInfo userInfo2;
    public void doController(){
        System.out.println(userInfo2);
        System.out.println("do Controller.........");
    }
@SpringBootApplication
public class IocDemoApplication {
    public static void main(String[] args) {
//1.属性注入
        ApplicationContext context=SpringApplication.run(IocDemoApplication.class);
        TestController testController=(TestController)context.getBean("testController") ;
       testController.doControl();
    }
}

属性注入以类型进行匹配,与注入的属性名称无关。但是如果一个类型存在多个对象时,有优先名称匹配,如果名称都匹配不上,那就会报错。

我们看到同一个类型出现了两个对象userInfo和userInfo2,那么此时我们要名称匹配,我定义的时候用的是us,此时匹配匹配不上,报错。


🎈构造方法注入


    //二、构造方法注入
    private TestService testService;
    public TestController(){};

    public TestController(UserInfo userInfo){
        this.userInfo=userInfo;
    }
    @Autowired
    public TestController(TestService testService){
        this.testService=testService;
    }
    public TestController(UserInfo userInfo,TestService testService){
        this.userInfo=userInfo;
        this.testService=testService;
    }
    public void doControl2(){
        testService.doService();
        System.out.println("do Controller.........");
    }

注意:

  • 1.如果存在多个构造函数时,需要加@AutoWired注明使用哪个构造函数
  • 2.再添加了有参的构造方法中,最好加上无参的构造方式,防止报错
  • 3.如果只有一个构造函数,@AutoWired可以省略掉
  • 4.明确注入哪个构造函数,否则会造成空指针异常


🎈Setter注入

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解。
    //三、setter注入
    private TestService testService2;

    @Autowired
    public void setTestService2(TestService testService2) {
        this.testService2 = testService2;
    }
        public void doController3(){
        testService2.doService();
        System.out.println("do Controller.........");
    }


🔴@Autowired存在问题

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

程序启动失败,发现类型UserInfo存在多个Bean。


📝解决方法一

属性名和你需要使用的对象名保持一致。


📝解决方法二

使用@Primary注解标识默认的对象


📝解决方法三

使用@Qualifier指定哪个对象


📝解决方法四

使用@Resource注解指定ben


上述四个方法,使用率最高的是@Qualifier和@Resource注解

解决方法思路:给bean重命名或者指定名称


🔴五大注解修改名以及Bean修改名

📝Bean修改名

  @Bean({"u1","uu"})
  @Bean("u1")

一个Bean可以有多个名称,但是一个名称只能对应一个Bean。


📝类注解修改


人生小满胜万全。

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

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

相关文章

Zoho Campaigns邮件营销怎么发邮件?

Zoho Campaigns,作为业界领先的邮件营销平台,以其强大的功能、用户友好的界面以及深度的分析能力,为企业提供了一站式的邮件营销解决方案,助力企业高效地触达目标受众,构建并巩固庞大的客户基础。云衔科技为企业提供Zo…

羊毛纤维直径检测 — C++

羊毛纤维检测 系统是 Ubuntu20.04 。 需要用到 OpenCV 的库,库具体该怎么编译配置,可以参考网上的教程。 自己码的一小段函数,用纯 CV 的方式处理羊毛纤维图像,如图所示: 在 wool 下面,创建 build 文件…

Redis 实战 - 缓存异常及解决方案

文章目录 概述一、缓存穿透1.1 缓存穿透是什么1.2 解决方案 二、缓存击穿2.1 缓存击穿是什么2.2 解决方案 三、缓存雪崩3.1 缓存雪崩是什么3.2 解决方案 四、拓展4.1 缓存预热4.2 缓存降级 五、结语 把今天最好的表现当作明天最新的起点…….~ 概述 在实…

常见web安全漏洞

一、信息泄露 概念 信息泄露是由于Web服务器或应用程序没有正确处理一些特殊请求,泄露Web服务器的一些敏感信 息,如用户名、密码、源代码、服务器信息、配置信息等。 造成信息泄露主要的三个原因: ①Web服务器配置存在问题,导致一些系统…

mac 安装java jjdk8 jdk11 jdk17 等

oracle官网 https://www.oracle.com/java/technologies/downloads/ 查看当前电脑是英特尔的x86 还是arm uname -m 选择指定版本,指定平台的安装包: JDK8 JDK11的,需要当前页面往下拉: 下载到的安装包,双击安装&#x…

扭蛋机小程序开发,数字化发展对行业带来的优势

随着科技的不断进步和大众对娱乐消费需求的提高,线上扭蛋机得到了快速发展,市场规模不断扩大。线上扭蛋机是基于淘宝的小程序,它以电商的模式让消费者进行虚拟扭蛋,获得各类商品,扭蛋机小程序中的商品包括玩具、IP周边…

【百度智能体】零代码创建你的 AI 宠物助手

前言 今天给大家介绍一下百度的 AI 产品 – 百度智能体,在文心智能体平台你可以0代码就可以创建出属于自己的 AI 机器人,几乎可以选择任何你想要的领域或者行业机器人,进行无代码打造自己的对话助手,本文将介绍文心智能体&#x…

3D技术的应用领域

3D技术在现代科技和工业中有广泛的应用,其涵盖的领域非常广泛,从娱乐到医学,再到制造业和建筑,3D技术正在改变我们理解和互动的方式。以下是一些主要的应用领域。北京木奇移动技术有限公司,专业的软件外包开发公司&…

单点登录与JWT

JWT:JSON Web Token JWT的作用是用户授权(Authorization),而不是用户的身份认证(Authentication) 授权(Authorization)vs认证(Authentication) 用户认证指的是使用用户名、密码来…

RedHat9 | 配置与管理DNS服务器

一、 知识预备 1、DNS服务器的分类 主DNS服务器 主DNS服务器复制维护所管辖域的域名服务信息,它从域管理员构造的本地磁盘文件中的加载域信息。该文件包含服务器具有管理权的的一部分域结构的精确信息,配置主域服务器需要一整套配置文件: …

瑜伽馆约课会员管理系统小程序的作用是什么

瑜伽馆有着众多学员,如瘦身、改变气质、减脂塑形等往往属于长期多次跟随教练学习,或是自己在家里学习等,对商家来说,品牌宣传、吸引客户到店以及长期经营、提高自身服务效率是重中之重。 客户多次进店享受服务的同时还需要悦己&a…

关于单元测试

关于单元测试的一些总结:

紧固件松动的危害及原因——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 紧固件松动,这一看似微小的机械问题,实际上可能引发一系列严重的后果。在机械设备中,紧固件扮演着至关重要的角色,它们通过紧固作用将各个部件紧密连接在一起,…

学浪视频怎么下载保存到本地

你是否曾经因为想要保存一份珍贵的学浪视频却苦于无法下载而感到烦恼?现在,我将向你揭示一个简单易行的方法,让你轻松地将学浪视频保存到本地,随时随地享受学习的乐趣。你是否曾经因为想要保存一份珍贵的学浪视频却苦于无法下载而…

vue-3d-loader 加载多个模型

需求 1、在使用three.js进行开发的过程中,需要列表加载多个模型,并根据需要多模型进行加载。 2、当鼠标移动到图片上去的时候,开始加载模型, 模型进行加载和展示。 3、在制作3d沉浸式商城时,需要根据需求&#xff0…

vscode+conda,选择虚拟环境下的python解释器提示解释器无效?

问题描述 在开发一个python脚本过程中,试用conda管理虚拟环境,用vscode进行开发,遇到的问题是激活虚拟环境后,在vscode中选择对应环境下的python解释器,提示“选择的解释器无效”。 使用的是Miniconda,虚拟环境下python版本为2.7,vscode的python插件为2023.14.0。 解…

存储方式 - 前端学习

1. cookie是什么?你了解cookie吗? 在计算机领域中,特指一种由服务器发送到用户浏览器并保存在用户计算机上的小型文本文件。这个文件可以被服务器用来识别用户身份、跟踪用户活动、保存用户设置等。它通常由名称、值、域名、路径、过期时间等…

液氢产业化进程提速 液氢装备检测市场需求空间广阔

液氢产业化进程提速 液氢装备检测市场需求空间广阔 液氢装备检测试验项目涉及到火烧试验、置换试验、振动试验、燃烧实验、高压氢循环试验、预冷试验、液氢阀门检测试验等。检测试验是推动氢能技术自主化、高质量发展的重要步骤,近年来,随着液氢应用场景…

C++之std::is_trivially_copyable(平凡可复制类型检测)

目录 1.C基础回顾 1.1.平凡类型 1.2.平凡可复制类型 1.3.标准布局类型 2.std::is_trivially_copyable 2.1.定义 2.2.使用 2.3.总结 1.C基础回顾 在C11中,平凡类型(Trivial Type)、平凡可复制类型(TrivialCopyable&#x…

mysql中单表查询方法

大家好。我们知道,mysql有一个查询优化器的模块。当我们用sql语句查询表中记录时,会对这条查询语句进行语法解析,然后就会交给查询优化器来进行优化,优化后生成一个执行计划,这个执行计划表明了应该使用哪些索引进行查…