Spring之IOC容器从入门都手写源码

news2024/11/29 14:54:25

文章目录

  • 一、IOC容器
    • 1、控制反转(ioc)
    • 2、依赖注入
    • 3、IoC容器在Spring的实现
  • 二、基于XML管理Bean
    • 1、获取bean
      • 方式一、根据id获取
      • 方式二、根据类型获取
      • 方式三、根据id和类型获取bean
    • 2、依赖注入之setter注入
    • 3、依赖注入之构造器注入
    • 4、特殊值处理
    • 5、为对象类型属性赋值
      • 方式一:引用外部bean
      • 方式二:内部bean
      • 方式三:级联属性赋值
    • 6、为数组类型属性赋值
    • 7、为集合类型属性赋值
    • 8、基于xml自动装配
  • 三、基于注解管理Bean(
    • 1、配置类替换bean.xml
    • 2、@Autowired注入
      • 方式一:属性注入(`最常用`)
      • 方式二、set注入
      • 方式三、构造方法注入
      • 方式四、形参注入
      • 方式五、只有一个构造函数,通过构造器注入不需要注解
      • 方式六、@Autowired注解和@Qualifier注解联合
    • 3、@Resource注入
      • 方式一、根据name注入
      • 方式二、name未知注入
      • 方式三、name找不到的情况
  • 四、原理-手写IoC

Spring Core(核心容器)

在这里插入图片描述
spring core提供了IOC,DI,Bean配置装载创建的核心实现
核心概念: Beans、BeanFactory、BeanDefinitions、ApplicationContext

  • spring-core :IOC和DI的基本实现
  • spring-beans:BeanFactory和Bean的装配管理(BeanFactory)
  • spring-context:Spring context上下文,即IOC容器(AppliactionContext)
  • spring-expression:spring表达式语言

一、IOC容器

1、控制反转(ioc)

  • 控制反转是一种思想
  • 控制反转是为了降低程序耦合度,提高程序扩展力
  • 控制反转,反转的是什么?
    • 对象的创建权利交出去,交给第三方容器负责
    • 对象和对象之间关系的维护权交出去,交给第三方容器负责
  • 控制反转这种思想如何实现呢?
    • DI(Dependency Injection):依赖注入

2、依赖注入

DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想

  • 指Spring创建对象的过程中,将对象依赖属性通过配置进行注入
  • 依赖注入常见的实现方式包括两种:
    • set注入
    • 构造注入
  • Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)

所以结论是:IOC 就是一种控制反转的思想, 而 DI 是对IoC的一种具体实现

3、IoC容器在Spring的实现

  • Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现
  • IoC容器中管理的组件也叫做 bean
  • 在创建 bean 之前,首先需要创建IoC 容器
  • Spring 提供了IoC 容器的两种实现方式:
    • BeanFactory
      • 这是 IoC 容器的基本实现
      • 是 Spring 内部使用的接口
      • 面向 Spring 本身,不提供给开发人员使用
    • ApplicationContext
      • BeanFactory 的子接口,提供了更多高级特性
      • 面向 Spring 的使用者
      • 几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory

ApplicationContext的主要实现类

在这里插入图片描述

类型名简介
ClassPathXmlApplicationContext通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
ConfigurableApplicationContextApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力
WebApplicationContext专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中

二、基于XML管理Bean

搭建项目

  • 添加依赖
<!--spring context依赖-->
<!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.0.3</version>
</dependency>
  • 引入java类
public class User {
}
  • beans.xml
<?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">

    <!--1 获取bean演示,user对象创建-->
    <bean id="user" class="com.xc.spring6.iocxml.bean.User"></bean>
</beans>

1、获取bean

方式一、根据id获取

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        // 根据id获取bean
        User user = (User) context.getBean("user");
    }
}

方式二、根据类型获取

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean(User.class);
    }
}

方式三、根据id和类型获取bean

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user",User.class);
    }
}

注意

  • 当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个
  • 当IOC容器中一共配置了两个
<bean id="user" class="com.xc.spring6.iocxml.bean.User"></bean>
<bean id="user1" class="com.xc.spring6.iocxml.bean.User"></bean>

根据类型获取时会抛出异常:NoUniqueBeanDefinitionException(没有唯一Bean定义异常)

扩展

  • 如果组件类实现了接口,根据接口类型可以获取 bean 吗?(可以,前提是bean唯一)
  • 如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?(不行,因为bean不唯一)

2、依赖注入之setter注入

  • 创建学生类Student
@Data
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
}
  • 配置bean时为属性赋值
<bean id="studentOne" class="com.xc.spring6.bean.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="23"></property>
    <property name="sex" value=""></property>
</bean>
  • 测试
@Test
public void testDIBySet(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
    Student studentOne = ac.getBean("studentOne", Student.class);
    System.out.println(studentOne);
}

3、依赖注入之构造器注入

  • 在Student类中添加有参构造
public Student(Integer id, String name, Integer age, String sex) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.sex = sex;
}
  • 配置bean
<bean id="studentTwo" class="com.xc.spring6.bean.Student">
    <constructor-arg value="1002"></constructor-arg>
    <constructor-arg value="李四"></constructor-arg>
    <constructor-arg value="33"></constructor-arg>
    <constructor-arg value="女"></constructor-arg>
</bean>

注意:
constructor-arg标签还有两个属性可以进一步描述构造器参数

  • index属性:指定参数所在位置的索引(从0开始)
  • name属性:指定参数名
  • 测试
@Test
public void testDIByConstructor(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
    Student studentOne = ac.getBean("studentTwo", Student.class);
    System.out.println(studentOne);
}

4、特殊值处理

字面量赋值

<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

null值

<property name="name">
    <null />
</property>

xml实体

<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>

CDATA节

<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>

5、为对象类型属性赋值

  • 员工类和部门类
// 部门累
@Data
public class Dept {
    private String dname;
}
// 员工类
@Data
public class Emp {
    //对象类型属性:员工属于某个部门
    private Dept dept;
    //员工名称
    private String ename;
    //员工年龄
    private Integer age;
}

方式一:引用外部bean

<bean id="dept" class="com.xc.spring6.iocxml.ditest.Dept">
    <property name="dname" value="安保部"></property>
</bean>
  • 使用ref属性给Emp类的部门属性赋值对象
<bean id="emp" class="com.xc.spring6.iocxml.ditest.Emp">
    <!--注入对象类型属性
        private Dept dept;
    -->
    <property name="dept" ref="dept"></property>
    <!--普通属性注入-->
    <property name="ename" value="lucy"></property>
    <property name="age" value="50"></property>
</bean>

方式二:内部bean

<bean id="emp2" class="com.xc.spring6.iocxml.ditest.Emp">
    <!--普通属性注入-->
    <property name="ename" value="mary"></property>
    <property name="age" value="20"></property>
    <!--内部bean-->
    <property name="dept">
        <bean id="dept2" class="com.xc.spring6.iocxml.ditest.Dept">
            <property name="dname" value="财务部"></property>
        </bean>
    </property>
</bean>

方式三:级联属性赋值

  • name属性 = 对象.属性名
<bean id="dept3" class="com.xc.spring6.iocxml.ditest.Dept">
    <property name="dname" value="技术研发部"></property>
</bean>

<bean id="emp3" class="com.xc.spring6.iocxml.ditest.Emp">
    <property name="ename" value="tom"></property>
    <property name="age" value="30"></property>
    
    <property name="dept" ref="dept3"></property>
    <property name="dept.dname" value="测试部"></property>
</bean>

6、为数组类型属性赋值

  • Emp员工类添加爱好属性数组
//爱好
private String[] loves;
<bean id="emp" class="com.xc.spring6.iocxml.ditest.Emp">
    <!--普通属性-->
    <property name="ename" value="lucy"></property>
    <property name="age" value="20"></property>
    <!--对象类型属性-->
    <property name="dept" ref="dept"></property>
    <!--数组类型属性-->
    <property name="loves">
        <array>
            <value>吃饭</value>
            <value>睡觉</value>
            <value>敲代码</value>
        </array>
    </property>
</bean>

7、为集合类型属性赋值

  • Dept部门类添加员工集合
//一个部门有很多员工
private List<Emp> empList;
<bean id="empone" class="com.xc.spring6.iocxml.ditest.Emp">
    <property name="ename" value="lucy"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="emptwo" class="com.xc.spring6.iocxml.ditest.Emp">
    <property name="ename" value="mary"></property>
    <property name="age" value="30"></property>
</bean>

<bean id="dept" class="com.xc.spring6.iocxml.ditest.Dept">
  <property name="dname" value="技术部"></property>
  <property name="empList">
        <list>
            <ref bean="empone"></ref>
            <ref bean="emptwo"></ref>
        </list>
  </property>
</bean>

若为Set集合类型属性赋值,只需要将其中的list标签改为set标签即可

8、基于xml自动装配

  • 根据指定的策略,在IOC容器中匹配某一个bean
  • 自动为指定的bean中所依赖的类类型或接口类型属性赋值
  • 基于XML自动装配,底层使用set注入

bean类

public class UserServiceImpl  implements UserService{

    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUserService() {
        userDao.addUserDao();
    }
}

配置bean.xml

  • 自动装配方式:byType
  • byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
    • 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
    • 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
<bean id="userService" class="com.xc.spring6.autowire.service.impl.UserServiceImpl" 
autowire="byType"></bean>

<bean id="userDao" class="com.xc.spring6.autowire.dao.impl.UserDaoImpl"></bean>
  • 自动装配方式:byName
  • byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值

三、基于注解管理Bean(

1、配置类替换bean.xml

@Configuration
//@ComponentScan({"com.xc.spring6.controller", "com.xc.spring6.service","com.xc.spring6.dao"})
@ComponentScan("com.xc.spring6")
public class Spring6Config {
}

2、@Autowired注入

  • 单独使用@Autowired注解,默认根据类型装配
  • 查看注解源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, 
ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}
  • 注解可以标注的位置
    • 构造方法上
    • 方法上
    • 形参上
    • 属性上
    • 注解上
  • 该注解有一个required属性
    • 默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错
    • 如果required属性设置为false,表示注入的Bean存在或者不存在都没关系

方式一:属性注入(最常用

  • 基于注解自动装配,底层使用反射注入,故不需要set方法
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
}

方式二、set注入

@Service
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

方式三、构造方法注入

@Service
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}

方式四、形参注入

@Service
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }
}

方式五、只有一个构造函数,通过构造器注入不需要注解

  • 当有参数的构造方法只有一个时,@Autowired注解可以省略
@Service
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}

方式六、@Autowired注解和@Qualifier注解联合

  • 如果UserDao接口有两个实现类
  • 通过@Autowired注入会抛异常(expected single matching bean but found 2:xx1,xx2)
  • 此时可以通过@Qualifier注解指定具体bean的名称
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

}

3、@Resource注入

@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?

  • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分
    • 所以该注解是标准注解,更加具有通用性
    • JSR-250标准中制定的注解类型。JSR是Java规范提案
  • @Autowired注解是Spring框架自己的
  • @Resource注解默认根据名称装配byName,通过name找不到的话会自动启动通过类型byType装配
  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用
  • @Resource注解用在属性上、setter方法上
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上

@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖
如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

方式一、根据name注入

@Service
public class UserServiceImpl implements UserService {

    @Resource(name = "userDao")
    private UserDao myUserDao;

}

方式二、name未知注入

  • 当@Resource注解使用时没有指定name的时候,还是根据name进行查找,这个name是属性名
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;
}

方式三、name找不到的情况

  • 显然当通过name找不到的时候,自然会启动byType进行注入
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDaoNotFound ;

}

四、原理-手写IoC

定义标记bean的@Bean注解和依赖注入的@Di注解

  • @Bean相当于@Component
  • @Di相当于@Autowired
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}

定义bean容器接口

public interface ApplicationContext {
    Object getBean(Class<?> clazz);
}

注解bean容器接口和依赖注入的实现

public class AnnotationApplicationContext implements ApplicationContext {
    //创建map集合,放bean对象
    private final Map<Class<?>, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    //返回对象
    @Override
    public Object getBean(Class<?> clazz) {
        return beanFactory.get(clazz);
    }

    //创建有参数构造,传递包路径,设置包扫描规则
    //当前包及其子包,哪个类有@Bean注解,把这个类通过反射实例化
    public AnnotationApplicationContext(String basePackage) {
        // com.xc
        try {
            //1 把.替换成\
            String packagePath = basePackage.replaceAll("\\.", "/");
            //2 获取包绝对路径
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
                //获取包前面路径部分,字符串截取
                rootPath = filePath.substring(0, filePath.length() - packagePath.length());
                //包扫描
                loadBean(new File(filePath));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //属性注入
        loadDi();
    }

    //包扫描过程,实例化
    private void loadBean(File file) throws Exception {
        //1 判断当前是否文件夹
        if (file.isDirectory()) {
            //2 获取文件夹里面所有内容
            File[] childrenFiles = file.listFiles();
            //3 判断文件夹里面为空,直接返回
            if (childrenFiles == null || childrenFiles.length == 0) {
                return;
            }
            //4 如果文件夹里面不为空,遍历文件夹所有内容
            for (File child : childrenFiles) {
                //4.1 遍历得到每个File对象,继续判断,如果还是文件夹,递归
                if (child.isDirectory()) {
                    //递归
                    loadBean(child);
                } else {
                    //4.2 遍历得到File对象不是文件夹,是文件,
                    //4.3 得到包路径+类名称部分-字符串截取
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length());
                    //4.4 判断当前文件类型是否.class
                    if (pathWithClass.contains(".class")) {
                        //4.5 如果是.class类型,把路径\替换成.  把.class去掉
                        // com.xc.service.UserServiceImpl
                        String allName = pathWithClass.replaceAll("/", ".").replace(".class", "");
                        //4.6 判断类上面是否有注解 @Bean,如果有实例化过程
                        //4.6.1 获取类的Class
                        Class<?> clazz = Class.forName(allName);
                        //4.6.2 判断不是接口
                        if (!clazz.isInterface()) {
                            //4.6.3 判断类上面是否有注解 @Bean
                            if (clazz.isAnnotationPresent(Bean.class)) {
                                //4.6.4 实例化
                                Object instance = clazz.getConstructor().newInstance();
                                //4.7 把对象实例化之后,放到map集合beanFactory
                                //4.7.1 判断当前类如果有接口,让接口class作为map的key
                                if (clazz.getInterfaces().length > 0) {
                                    beanFactory.put(clazz.getInterfaces()[0], instance);
                                } else {
                                    beanFactory.put(clazz, instance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    //属性注入
    private void loadDi() {
        //实例化对象在beanFactory的map集合里面
        //1 遍历beanFactory的map集合
        Set<Map.Entry<Class<?>, Object>> entries = beanFactory.entrySet();
        for (Map.Entry<Class<?>, Object> entry : entries) {
            //2 获取map集合每个对象(value),每个对象属性获取到
            Object obj = entry.getValue();
            //获取对象Class
            Class<?> clazz = obj.getClass();
            //获取每个对象属性获取到
            Field[] declaredFields = clazz.getDeclaredFields();
            //3 遍历得到每个对象属性数组,得到每个属性
            for (Field field : declaredFields) {
                //4 判断属性上面是否有@Di注解
                if (field.isAnnotationPresent(Di.class)) {
                    //如果私有属性,设置可以设置值
                    field.setAccessible(true);
                    //5 如果有@Di注解,把对象进行设置(注入)
                    try {
                        field.set(obj, beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

测试类

@Bean
public class UserDaoImpl  implements UserDao {
    @Override
    public void add() {
        System.out.println("dao.......");
    }
}
@Bean
public class UserServiceImpl implements UserService {

    @Di
    private UserDao userDao;

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}
public class SpringIocTest {
    @Test
    public void testIoc() {
        ApplicationContext applicationContext = new AnnotationApplicationContext("com.xc");
        UserService userService = (UserService)applicationContext.getBean(UserService.class);
        userService.add();
        System.out.println("run success");
    }
}

输出结果

service.......
dao.......
run success

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

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

相关文章

基于llama模型进行增量预训练

目录 1、llama模型转换(pytorch格式转换为HuggingFace格式) 1.1、拉取Chinese-LLaMA-Alpaca项目 1.2、准备文件夹 1.3、下载llama官方原始模型 1.4、移动文件到指定位置 1.5、执行转换脚本 2、合并模型 2.1、下载Chinese-LLaMA-Plus-7B模型 2.2、下载chinese_alpaca_p…

【Leetcode60天带刷】day16二叉树—— 104.二叉树的最大深度 , 111.二叉树的最小深度,222.完全二叉树的节点个数

题目&#xff1a; 104. 二叉树的最大深度 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c; 3/ \9 20/ …

数字电路基础---寄存器

目录 数字电路基础---寄存器 1、寄存器简介 1.1、寄存器是如何工作的 2、实验任务 3、程序设计 3.1、模块设计 3.2、绘制波形图 4、编写代码 5、仿真验证 5.1、编写 TB 文件 5.2、仿真验证 6、总结 7、拓展训练 数字电路基础---寄存器 寄存器是构成时序逻辑最重要…

理解安卓的视图体系结构

原文链接 理解安卓的视图体系结构 当我们想要写一个页面的时候&#xff0c;通过一个Activity&#xff0c;然后调用其setContentView方法&#xff0c;把一个布局文件当作一个参数传递过去&#xff0c;然后一个页面就好了&#xff0c;但是除此之外&#xff0c;我们还需要与一些组…

【MySql】MySql索引的作用索引的理解

【MySql】MySql索引的作用&&索引的理解 文章目录 索引的作用认识磁盘MySql 与磁盘交互基本单位Page共识索引的理解主键有序问题理解单个Page理解多个Page页目录单页情况多页情况 索引的作用 索引是与效率挂钩的&#xff0c;所以没有索引&#xff0c;可能会存在问题 索…

从0到1搭建属于自己的Gitlab CI/CD平台

文章目录 持续集成(CI)持续交付(CD)Gitlab CI/CD功能和架构本地搭建GitLab CI/CD平台 MCNU云原生&#xff0c;文章首发地&#xff0c;欢迎微信搜索关注&#xff0c;更多干货&#xff0c;第一时间掌握&#xff01; CI和CD是软件开发中常用的缩写&#xff0c;分别代表持续集成&am…

【Unity】 HTFramework框架(四十五)【进阶篇】指令系统-自定义指令

更新日期&#xff1a;2023年6月19日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 指令系统1.使用指令系统2.自定义指令1.新建类 MyInstruction2.标记 CustomInstruction 特性3.编写指令的逻辑4.执行自定义指令5.自定义指令的参数6.结尾 …

C进阶 - 数组和指针

Declare an array manually VS malloc or calloc an array 用英文是因为有些东西得用他们的语言才能表达不失真 栈和堆 In C, a heap is a region of memory that is dynamically allocated during runtime. It is used to store variables and data structures that have a …

学习HCIP的day.14

目录 STP生成树协议 生成树协议 一、802.1D 1、根网桥 2、根端口 3、指定端口 4、非指定端口 5、接口状态 802.1D的收敛时间 802.1D算法的缺点 以上cost值的解释 二、PVST 三、PVST 四、快速生成树 五、MSTP/MST/802.1S STP生成树协议 网络三层架构…

南京企业所得税高怎么办?

南京企业所得税高怎么办&#xff1f; 《税筹顾问》专注于园区招商&#xff0c;您的贴身节税小能手&#xff0c;合理合规节税&#xff01; 众所周知&#xff0c;企业所得税是按利润来计算的&#xff0c;按照不同的利润阶梯计算适用的税率也会有所不同&#xff0c;那么当企业利润…

launch文件的编写及ROS配置文件的详细介绍

launch文件的编写及ROS配置文件的详细介绍 1 launch文件介绍及简单应用1.1 launch文件介绍1.2 launch文件简单应用 2 package.xml文件介绍及配置3 CMakeLists.txt文件介绍及配置 1 launch文件介绍及简单应用 1.1 launch文件介绍 根据ROS的架构和通信机制来看&#xff0c;ROS的…

讯飞星火大模型详细内测体验:它能否应对这些挑战?

名人说&#xff1a;一花独放不是春&#xff0c;百花齐放花满园。——《增广贤文》 作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、简要介绍二、分类问题测试0️⃣自我介绍1️⃣语言理解2️⃣知识问答3️⃣逻辑推…

Vue中如何进行文件转换与格式转换

Vue中如何进行文件转换与格式转换 在Web应用程序中&#xff0c;经常需要进行文件转换和格式转换。例如&#xff0c;将PDF文件转换为图像文件、将音频文件转换为不同的格式或将视频文件转换为不同的分辨率和编解码格式。Vue作为一种流行的前端框架&#xff0c;提供了许多实用工…

网络管理与维护(二)网络用户设置管理

网络用户设置管理 2.1 用户帐户安全管理 用户账户的分类 管理员帐户。拥有管理本台计算机的所有权限和权利。系统内置的Administrator用户帐户 和Administrators组帐户的成员就属于管理员帐户 标准帐户。通常分配给最终用户使用&#xff0c;适用于日常工作&#xff0c;对操作…

GeoServer中地图可视化提升利器之SLD知识简介

目录 前言 一、SLD简介 1、介绍 2、SLD的版本 3、SLD的Schema说明 二、SLD中相关知识解析 1、Scheme简要说明 2、一个SLD实例 总结 前言 在互联网上有很多精美的地图&#xff0c;在地图从shp或者gdb等矢量文件&#xff0c;经过设计人员的加工&#xff0c;配色&#xff0…

【论文阅读】Graph-less Collaborative Filtering

【论文阅读】Graph-less Collaborative Filtering 文章目录 【论文阅读】Graph-less Collaborative Filtering1. 来源2. 介绍3. 模型解读3.1 协同过滤3.2 模型3.2.1 对比知识精馏 3.2.2 自适应对比正则化3.2.3 SimRec的参数学习 4. 实验5. 总结 1. 来源 2023WWW CCFA原文地址co…

【Linux】linux | 服务响应慢、问题排查 | 带宽问题导致 | 网速

一、说明 1、项目使用云服务器&#xff0c;服务器配置&#xff1a;5M带宽、4核、32G&#xff0c;1T&#xff0c;CentOS7 2、CPU、内存、磁盘IO都没有达到瓶颈&#xff0c;猜测是带宽问题 3、应用比较多&#xff0c;应用中间件&#xff0c;十几个差不多 4、同时在线人数30 5、已…

“暗网议会”如今已成为现实

图片来源:Marcin Balcerzak 最近&#xff0c;“暗网议会”已经成为了网络犯罪分子试图证明自己影响力的最新流行语&#xff0c;安全内部人士对这个词也很感兴趣。 上周五&#xff0c;臭名昭著的亲俄黑客组织Killnet在其电报威胁帖子中使用了这个词语。随后&#xff0c;twitte…

d2l_第五章学习_Multilayer Perceptrons多层感知机

x.1 Hidden Layers 线性模型的基本假设是单调&#xff0c;即任何特征的增大都会导致模型的输出增大&#xff08;权重正时&#xff0c;负值时亦&#xff09;。但是现实中很多的关系并不仅仅是简单的线性关系&#xff0c;这个时候就需要引入非线性关系&#xff0c;而非线性关系由…

Verilog基础之七、译码器实现

目录 一、前言 二、工程实现 2.1 工程代码 2.2 仿真结果 2.3 参考 一、前言 ​译码器的实现为编码器的逆过程&#xff0c;以3-8译码器为例&#xff0c;真值表如下。 二、工程实现 ​实现同时使用for循环和case两种方式。 2.1 工程代码 module Decoder(in,out,out_case )…