【Spring】Spring 对 Ioc 的实现

news2024/11/17 14:28:20

一、Ioc 控制反转

  • 控制反转是一种思想

  • 控制反转是为了降低程序耦合度,提高程序扩展力,达到 OCP 原则,达到 DIP 原则

  • 控制反转,反转的是什么?

    • 将对象的创建权利交出去,交给第三方容器负责

    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责

  • 控制反转这种思想如何实现呢?

    • DI(Dependency Injection):依赖注入

 

二、依赖注入 

依赖注入实现了控制反转的思想

Spring通过依赖注入的方式来完成Bean管理的

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)

依赖注入:

  • 依赖指的是对象和对象之间的关联关系

  • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系

依赖注入常见的实现方式包括两种:

  • 第一种:set 注入

  • 第二种:构造注入

 

三、set 注入 

set 注入,基于 set 方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供 set 方法  

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.qiu</groupId>
    <artifactId>spring-003-dependency-injection</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.23</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--log4j2的依赖-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.19.0</version>
        </dependency>
    </dependencies>

</project>
package org.qiu.spring.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.dao
 * @date 2022-10-31-17:46
 * @since 1.0
 */
public class UserDao {
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    public void insert(){
        logger.info("正在保存用户数据......");
    }
}
package org.qiu.spring.service;

import org.qiu.spring.dao.UserDao;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.service
 * @date 2022-10-31-17:53
 * @since 1.0
 */
public class UserService {
    private UserDao userDao;

    // 使用set方式注入,必须提供set方法。
    // 反射机制要调用这个方法给属性赋值的。
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void save(){
        userDao.insert();
    }
}
<?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">

    <bean id="userDaoBean" class="org.qiu.spring.dao.UserDao"></bean>

    <bean id="userServiceBean" class="org.qiu.spring.service.UserService">
        <!--
            想让 Spring 调用对应的 set 方法,需要配置 property 标签
                name:set方法的方法名,去掉 set,剩下的单词首字母变小写
                ref: references,“引用”。指定要注入的 bean 的 id
                一般情况下 name 位置写属性名就行了
        -->
        <property name="userDao" ref="userDaoBean"></property>
    </bean>

</beans>
package org.qiu.spring.test;

import org.junit.Test;
import org.qiu.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.test
 * @date 2022-10-31-17:55
 * @since 1.0
 */
public class DITest {
    @Test
    public void testSetDI(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
        userService.save();
    }
}

运行结果:  

 

原理解析:

通过 property 标签获取到属性名:userDao

通过属性名推断出 set 方法名:setUserDao

通过反射机制调用 setUserDao() 方法给属性赋值

property 标签的 name 是属性名。

property 标签的 ref 是要注入的 bean 对象的 id。(通过ref属性来完成 bean 的装配,这是 bean 最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

可以把 set 方法注释掉,再测试一下

通过测试得知,底层实际上调用了 setUserDao() 方法。所以需要确保这个方法的存在

另外,对于 property 标签来说,ref 属性也可以采用标签的方式,但使用 ref 属性是多数的:

<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
  <property name="userDao">
    <ref bean="userDaoBean"/>
  </property>
</bean>

总结:set 注入的核心实现原理:通过反射机制调用 set 方法来给属性赋值,让两个对象之间产生关系  

 

四、构造注入

核心原理:通过调用构造方法来给属性赋值  

package org.qiu.spring.service;

import org.qiu.spring.dao.UserDao;
import org.qiu.spring.dao.VipDao;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.service
 * @date 2022-11-01-20:25
 * @since 1.0
 */
public class CustomerService {
    private UserDao userDao;
    private VipDao vipDao;

    public CustomerService(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }

    public void save(){
        userDao.insert();
        vipDao.insert();
    }
}
<?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">

    <bean id="userDaoBean" class="org.qiu.spring.dao.UserDao"/>

    <bean id="vipDaoBean" class="org.qiu.spring.dao.VipDao"/>

    <bean id="csBean" class="org.qiu.spring.service.CustomerService">
        <!--
            构造注入
                public CustomerService(UserDao userDao, VipDao vipDao) {
                    this.userDao = userDao;
                    this.vipDao = vipDao;
                }
                指定构造方法的第一个参数,下标是 0
        -->
        <constructor-arg index="0" ref="userDaoBean"/>
        <constructor-arg index="1" ref="vipDaoBean"/>
    </bean>
    
    <!-- 也可以使用 name 注入,若不指定下标,也不指定参数名,Spring自动根据类型匹配注入 -->
    <bean id="csBean2" class="org.qiu.spring.service.CustomerService">
        <constructor-arg name="userDao" ref="userDaoBean"/>
        <constructor-arg name="vipDao" ref="vipDaoBean"/>
    </bean>

</beans>
@Test
public void testConstructDI(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    CustomerService service = applicationContext.getBean("csBean",CustomerService.class);
    service.save();
}

运行结果:  

 

五、set 注入专题 

  • 注入外部 Bean

这种方式比较常用

<!-- 声明/定义 bean -->
<bean id="orderDaoBean" class="org.qiu.spring.dao.OrderDao"/>

<bean id="orderServiceBean" class="org.qiu.spring.service.OrderService">
    <!-- 使用 ref 属性来引入,就是注入外部 bean -->
    <property name="orderDao" ref="orderDaoBean"/>
</bean>
  • 注入内部 Bean

这种方式使用较少,了解即可。

<bean id="orderServiceBean2" class="org.qiu.spring.service.OrderService">
    <property name="orderDao">
        <!-- 内部 bean -->
        <bean class="org.qiu.spring.dao.OrderDao"/>
    </property>
</bean>
  • 注入简单类型

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-07:14
 * @since 1.0
 */
public class User {
    private String username;
    private String password;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
<!-- 注入简单类型 -->
<bean id="userBean" class="org.qiu.spring.bean.User">
    <property name="username" value="张三"/>
    <property name="password" value="123"/>
    <property name="age" value="20"/>
</bean>
 @Test
public void testSimpleTypeSet(){
    ApplicationContext application = new ClassPathXmlApplicationContext("set-di.xml");
    User userBean = application.getBean("userBean", User.class);
    System.out.println(userBean);
}

运行结果:  

 

分析简单类型包括哪些?

Spring 源码:BeanUtils 类

public class BeanUtils{
    
    //.......
    
    /**
	 * Check if the given type represents a "simple" property: a simple value
	 * type or an array of simple value types.
	 * <p>See {@link #isSimpleValueType(Class)} for the definition of <em>simple
	 * value type</em>.
	 * <p>Used to determine properties to check for a "simple" dependency-check.
	 * @param type the type to check
	 * @return whether the given type represents a "simple" property
	 * @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE
	 * @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies
	 * @see #isSimpleValueType(Class)
	 */
	public static boolean isSimpleProperty(Class<?> type) {
		Assert.notNull(type, "'type' must not be null");
		return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
	}

	/**
	 * Check if the given type represents a "simple" value type: a primitive or
	 * primitive wrapper, an enum, a String or other CharSequence, a Number, a
	 * Date, a Temporal, a URI, a URL, a Locale, or a Class.
	 * <p>{@code Void} and {@code void} are not considered simple value types.
	 * @param type the type to check
	 * @return whether the given type represents a "simple" value type
	 * @see #isSimpleProperty(Class)
	 */
	public static boolean isSimpleValueType(Class<?> type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}
    
    //........
}
  • 简单类型:

    • 基本数据类型

    • 基本数据类型对应的包装类

    • String 或 其他的 CharSequence 子类

    • Number 子类

    • Date 子类

    • URI

    • URL

    • Temporal 子类(Java8 新特性,有关于时间时区的类)

    • Locale

    • Class

    • 另外还包括以上简单值类型对应的数组类型  

package org.qiu.spring.bean;

import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-07:37
 * @since 1.0
 */
public class SimpleValueType {

    public static void main(String[] args) {
        System.out.println(new Date());
    }
    private byte b;
    private short s;
    private int i;
    private long l;
    private float f;
    private double d;
    private boolean flag;
    private char c;

    private Byte b1;
    private Short s1;
    private Integer i1;
    private Long l1;
    private Float f1;
    private Double d1;
    private Boolean flag1;
    private Character c1;

    private String str;

    private Date date;

    private Season season;

    private URI uri;

    private URL url;

    private LocalDate localDate;

    private Locale locale;

    private Class clazz;

    // 省略 setter 和 toString
}

enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}
<?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">

    <bean id="simpleValueType" class="org.qiu.spring.bean.SimpleValueType">
        <property name="b" value="1"/>
        <property name="s" value="1"/>
        <property name="i" value="1"/>
        <property name="l" value="1"/>
        <property name="f" value="1"/>
        <property name="d" value="1"/>
        <property name="flag" value="false"/>

        <property name="c" value="a"/>
        <property name="b1" value="2"/>
        <property name="s1" value="2"/>
        <property name="i1" value="2"/>
        <property name="l1" value="2"/>
        <property name="f1" value="2"/>
        <property name="d1" value="2"/>
        <property name="flag1" value="true"/>
        <property name="c1" value="a"/>

        <property name="str" value="zhangsan"/>
        <!--注意:value后面的日期字符串格式不能随便写,必须是Date对象toString()方法执行的结果。-->
        <!--如果想使用其他格式的日期字符串,就需要进行特殊处理了-->
        <!--一般不会把 Date 当作简单类型,而是使用 ref 给 Date 类型属性赋值-->
        <property name="date" value="Sun Nov 06 07:50:46 CST 2022"/>
        <property name="season" value="WINTER"/>
        <property name="uri" value="/save.do"/>
        <!--spring6之后,会自动检查url是否有效,如果无效会报错。-->
        <property name="url" value="http://www.baidu.com"/>
        <!--java.util.Locale 主要在软件的本地化时使用。它本身没有什么功能,更多的是作为一个参数辅助其他方法完成输出的本地化。-->
        <property name="locale" value="CHINESE"/>
        <property name="clazz" value="java.lang.String"/>
    </bean>

</beans>
@Test
public void testAllSimpleType(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-all-simple-type.xml");
    SimpleValueType simpleValueType = applicationContext.getBean("simpleValueType", SimpleValueType.class);
    System.out.println(simpleValueType);
}

运行结果:  

需要注意的是:

  • 如果把 Date 当做简单类型的话,日期字符串格式不能随便写。格式必须符合 Date 的 toString() 方法格式。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给 Date 类型的属性的。

  • Spring6 之后,当注入的是 URL,那么这个 url 字符串是会进行有效性检测的。如果是一个存在的 url,那就没问题。如果不存在则报错。  

  • 级联属性赋值(了解)

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-08:58
 * @since 1.0
 */
public class Clazz {
    private String name;

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

    @Override
    public String toString() {
        return "Clazz{" +
                "name='" + name + '\'' +
                '}';
    }
}
package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-09:01
 * @since 1.0
 */
public class Student {
    private String name;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}
<bean id="studentBean" class="org.qiu.spring.bean.Student">
    <property name="name" value="张三"/>
</bean>

<bean id="clazzBean" class="org.qiu.spring.bean.Clazz">
    <property name="name" value="高三一班"/>
</bean>
@Test
public void testCascade(){
    ApplicationContext application = new ClassPathXmlApplicationContext("cascade.xml");

    Student studentBean = application.getBean("studentBean", Student.class);
    System.out.println(studentBean);

    Clazz clazzBean = application.getBean("clazzBean", Clazz.class);
    System.out.println(clazzBean);
}

运行结果:  

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-09:01
 * @since 1.0
 */
public class Student {
    private String name;

    private Clazz clazz;

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}
<bean id="studentBean" class="org.qiu.spring.bean.Student">
    <property name="name" value="张三"/>
    <property name="clazz" ref="clazzBean"/>
</bean>
@Test
public void testCascade(){
    ApplicationContext application = new ClassPathXmlApplicationContext("cascade.xml");

    Student studentBean = application.getBean("studentBean", Student.class);
    System.out.println(studentBean);

    Clazz clazzBean = application.getBean("clazzBean", Clazz.class);
    System.out.println(clazzBean);
}

运行结果:  

 

<!--
    级联属性赋值
    顺序不能颠倒
    使用级联属性赋值,clazz 属性需要提供对应的 getter 方法
-->
<bean id="studentBean" class="org.qiu.spring.bean.Student">
    <property name="name" value="张三"/>
    <property name="clazz" ref="clazzBean"/>
    <property name="clazz.name" value="高三二班"/>
</bean>

<bean id="clazzBean" class="org.qiu.spring.bean.Clazz"/>
public Clazz getClazz() {
    return clazz;
}

运行结果:  

 

  • 注入数组

数组中的元素是简单类型

package org.qiu.spring.bean;

import java.util.Arrays;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-22:16
 * @since 1.0
 */
public class QianDaYe {
    private String[] aiHaos;

    public void setAiHaos(String[] aiHaos) {
        this.aiHaos = aiHaos;
    }

    @Override
    public String toString() {
        return "QianDaYe{" +
                "aiHaos=" + Arrays.toString(aiHaos) +
                '}';
    }
}
<bean id="yuQian" class="org.qiu.spring.bean.QianDaYe">
    <!-- 数组属性的元素是简单类型 -->
    <property name="aiHaos">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</bean>
@Test
public void testArray(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
    QianDaYe yuQian = applicationContext.getBean("yuQian", QianDaYe.class);
    System.out.println(yuQian);
}

运行结果:

 

数组中元素不是简单类型  

package org.qiu.spring.bean;

import java.util.Arrays;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-22:16
 * @since 1.0
 */
public class QianDaYe {
    private String[] aiHaos;

    private Woman[] women;

    public void setAiHaos(String[] aiHaos) {
        this.aiHaos = aiHaos;
    }

    public void setWomen(Woman[] women) {
        this.women = women;
    }

    @Override
    public String toString() {
        return "QianDaYe{" +
                "aiHaos=" + Arrays.toString(aiHaos) +
                ", women=" + Arrays.toString(women) +
                '}';
    }
}
package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-06-22:24
 * @since 1.0
 */
public class Woman {
    private String name;

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

    @Override
    public String toString() {
        return "Woman{" +
                "name='" + name + '\'' +
                '}';
    }
}
<!-- 数组属性的元素不是简单类型 -->
<property name="women">
    <array>
        <ref bean="w1" />
        <ref bean="w2" />
        <ref bean="w3" />
        <ref bean="w4" />
    </array>
</property>

运行结果:  

 

  • 注入 List 集合、Set 集合

注入集合,集合中存放简单类型元素就用 <value> 标签,存放的是非简单类型元素就用 <ref> 标签

package org.qiu.spring.bean;

import java.util.List;
import java.util.Set;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-07:12
 * @since 1.0
 */
public class Person {
    // 注入 List 集合
    private List<String> names;

    // 注入 Set 集合
    private Set<String> addrs;

    @Override
    public String toString() {
        return "Person{" +
                "names=" + names +
                ", addrs=" + addrs +
                '}';
    }

    public void setNames(List<String> names) {
        this.names = names;
    }

    public void setAddrs(Set<String> addrs) {
        this.addrs = addrs;
    }
}
<bean id="personBean" class="org.qiu.spring.bean.Person">
    <property name="names">
        <!-- List 集合有序可重复-->
        <list>
            <value>张三</value>
            <value>张三</value>
            <value>张三</value>
            <value>李四</value>
            <value>李四</value>
            <value>王五</value>
            <value>王五</value>
        </list>
    </property>

    <property name="addrs">
        <!-- Set 集合无序不可重复-->
        <set>
            <value>北京</value>
            <value>广东</value>
            <value>上海</value>
            <value>上海</value>
            <value>上海</value>
        </set>
    </property>
</bean>
 @Test
public void testCollection(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
    Person person = applicationContext.getBean("personBean", Person.class);
    System.out.println(person);
}

运行结果:  

 

  • 注入 Map 集合

// 注入 Map 集合
private Map<Integer,String> phones;

@Override
public String toString() {
    return "Person{" +
        "names=" + names +
        ", addrs=" + addrs +
        ", phones=" + phones +
        '}';
}
<property name="phones">
    <map>
        <!-- key/value 都是简单类型,使用 key/value -->
        <entry key="1" value="110"/>
        <entry key="3" value="119"/>
        <entry key="5" value="120"/>
        <!-- key/value 不是简单类型,使用 key-ref/value-ref -->
        <!-- <entry key-ref="" value-ref="" /> -->
    </map>
</property>

运行结果:  

 

  • 注入 Properties 属性类对象

/**
 * 注入属性类对象
 * Properties 本质上也是一个 Map 集合
 * Properties 的父类是 HashTable,HashTable 实现了 Map 接口
 * 虽然也是一个 Map 集合,但是注入方式相似,但不同
 * Properties 的 key/value 只能是 String 类型
 */
private Properties properties;

public void setProperties(Properties properties) {
    this.properties = properties;
}

@Override
public String toString() {
    return "Person{" +
        "names=" + names +
        ", addrs=" + addrs +
        ", phones=" + phones +
        ", properties=" + properties +
        '}';
}
<property name="properties">
    <props>
        <prop key="driver">com.nmysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
        <prop key="username">root</prop>
        <prop key="password">123</prop>
    </props>
</property>

运行结果:  

 

  • 注入 null 和 空字符串

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-07:42
 * @since 1.0
 */
public class Cat {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}
<bean id="catBean" class="org.qiu.spring.bean.Cat">
    <!-- <property name="name" value=""></property> -->
    <!-- 手动注入 null -->
    <property name="name">
        <null/>
    </property>
    <property name="age" value="3"></property>
</bean>
@Test
public void testNull(){
    ApplicationContext application = new ClassPathXmlApplicationContext("set-di.xml");
    Cat cat = application.getBean("catBean", Cat.class);
    System.out.println(cat);
}

运行结果:  

不给属性值注入,默认就是 null,也可以手动注入  

<bean id="catBean" class="org.qiu.spring.bean.Cat">
    <!-- 注入 空字符串 -->
    <property name="name" value=""></property>
    <!-- 方式二 -->
    <!--
		<property name="name">
            <value/>
        </property>
	-->
    <property name="age" value="3"></property>
</bean>

运行结果:  

 

  • 注入特殊字符

XML中有5个特殊字符,分别是:<、>、'、"、&

以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。

解决方案包括两种:

  • 第一种:特殊符号使用转义字符代替。

  • 第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在 CDATA 区中的数据不会被 XML 文件解析器解析。

5个特殊字符对应的转义字符分别是:

特殊字符转义字符
>&gt;
<&lt;
'&apos;
"&quot;
&&amp;

 

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-07:58
 * @since 1.0
 */
public class Math {
    private String result;

    public void setResult(String result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "Math{" +
                "result='" + result + '\'' +
                '}';
    }
}
<!-- 方式一 -->
<bean id="mathBean" class="org.qiu.spring.bean.Math">
    <property name="result" value="2 &lt; 3"/>
</bean>
@Test
public void testSpecial(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
    Math mathBean = applicationContext.getBean("mathBean", Math.class);
    System.out.println(mathBean);
}

运行结果:  

 

使用 CDATA 方式:  

<bean id="mathBean" class="com.powernode.spring6.beans.Math">
    <property name="result">
        <!--只能使用 value 标签-->
        <value><![CDATA[2 < 3]]></value>
    </property>
</bean>

注意:使用CDATA时,不能使用value属性,只能使用value标签。

运行结果:

 

六、p 命名空间注入

目的:简化配置

使用 p 命名空间注入的前提条件包括两个:

  • 第一:在 XML 头部信息中添加 p 命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"

  • 第二:p 命名空间注入是基于 setter 方法的,所以需要对应的属性提供 setter 方法

package org.qiu.spring.bean;

import java.util.Date;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-08:10
 * @since 1.0
 */
public class Dog {
    private String name;
    private int age;
    private Date birth;

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birth=" + birth +
                '}';
    }

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

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

    public void setBirth(Date birth) {
        this.birth = birth;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        第一步:在 Spring 配置文件头部添加 p 命名空间
            xmlns:p="http://www.springframework.org/schema/p"
        第二步:使用
            p:属性名 = "属性值"(简单类型)
            p:属性名-ref = "属性值"(非简单类型)
    -->
    <bean id="dogBean" class="org.qiu.spring.bean.Dog" p:name="小花" p:age="3" p:birth-ref="birthBean"/>
    <!-- 获取当前系统时间 -->
    <bean id="birthBean" class="java.util.Date"/>

</beans>
@Test
public void testP(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
    Dog dog = applicationContext.getBean("dogBean", Dog.class);
    System.out.println(dog);
}

运行结果:  

 

七、C 命名空间注入 

c 命名空间是简化构造方法注入的

使用 c 命名空间的两个前提条件:

第一:需要在 xml 配置文件头部添加信息:xmlns:c="http://www.springframework.org/schema/c"

第二:需要提供构造方法

package org.qiu.spring.bean;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-21:34
 * @since 1.0
 */
public class People {
    private String name;
    private int age;
    private boolean sex;

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }

    public People(String name, int age, boolean sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        第一步:在 Spring 配置文件头部添加 xmlns:c="http://www.springframework.org/schema/c"
        第二步:使用
            可以使用属性名字或下标注入
    -->
    <bean id="peopleBean" class="org.qiu.spring.bean.People" c:_0="张三" c:age="18" c:sex="true"></bean>

</beans>
@Test
public void testC(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
    People people = applicationContext.getBean("peopleBean", People.class);
    System.out.println(people);
}

运行结果:  

 

八、util 命名空间 

util 命名空间让配置复用

使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:

package org.qiu.spring.bean;

import java.util.Properties;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-21:34
 * @since 1.0
 */
public class MyDataSource1 {
    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "MyDataSource1{" +
                "properties=" + properties +
                '}';
    }
}
package org.qiu.spring.bean;

import java.util.Properties;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-07-21:34
 * @since 1.0
 */
public class MyDataSource2 {
    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "MyDataSource2{" +
                "properties=" + properties +
                '}';
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 				
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util 
                           http://www.springframework.org/schema/util/spring-util.xsd">

    <util:properties id="prop">
        <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </util:properties>

    <bean id="dataSource1" class="org.qiu.spring.bean.MyDataSource1">
        <property name="properties" ref="prop"/>
    </bean>

    <bean id="dataSource2" class="org.qiu.spring.bean.MyDataSource2">
        <property name="properties" ref="prop"/>
    </bean>
</beans>
@Test
public void testUtil(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");

    MyDataSource1 dataSource1 = applicationContext.getBean("dataSource1", MyDataSource1.class);
    System.out.println(dataSource1);

    MyDataSource2 dataSource2 = applicationContext.getBean("dataSource2", MyDataSource2.class);
    System.out.println(dataSource2);
}

运行结果:  

 

九、基于 XML 自动装配 

Spring 还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配

  • 根据名称自动装配

package org.qiu.spring.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.dao
 * @date 2022-11-05-20:40
 * @since 1.0
 */
public class OrderDao {
    private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);

    public void generate(){
        logger.info("订单正在生成......");
    }
}
package org.qiu.spring.service;

import org.qiu.spring.dao.OrderDao;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.service
 * @date 2022-11-05-20:42
 * @since 1.0
 */
public class OrderService {

    private OrderDao orderDao;

    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    /**
     * 生成订单的业务方法
     */
    public void generate(){
        orderDao.generate();
    }
}
<!--
    id一般也叫做 bean 的名称
    根据名称自动装配,这个 id 需要是 setter 方法的名字,去掉 set,再将首字母改为小写
-->
<bean id="orderDao" class="org.qiu.spring.dao.OrderDao"/>

<!--
    根据名字进行自动装配
    自动装配也是基于 set 注入实现的
-->
<bean id="orderService" class="org.qiu.spring.service.OrderService" autowire="byName"></bean>
@Test
public void testAutowire(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
    OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
    orderService.generate();
}

运行结果:  

 

  • 根据类型自动装配

package org.qiu.spring.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.dao
 * @date 2022-10-31-20:27
 * @since 1.0
 */
public class VipDao {
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    public void insert(){
        logger.info("正在保存VIP信息......");
    }
}
package org.qiu.spring.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.dao
 * @date 2022-10-31-17:46
 * @since 1.0
 */
public class UserDao {
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    public void insert(){
        logger.info("正在保存用户数据......");
    }
}
package org.qiu.spring.service;

import org.qiu.spring.dao.UserDao;
import org.qiu.spring.dao.VipDao;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.service
 * @date 2022-11-01-20:25
 * @since 1.0
 */
public class CustomerService {
    private UserDao userDao;
    private VipDao vipDao;

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

    public void setVipDao(VipDao vipDao) {
        this.vipDao = vipDao;
    }

    /*
    public CustomerService(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }
    */

    public void save(){
        userDao.insert();
        vipDao.insert();
    }
}
<!--
    根据类型注入
    自动装配是基于 setter 方法的,必须提供 setter 方法
    根据类型进行自动装配的时候,在有效的配置文件当中,某种类型的实例只能有一个
-->
<bean class="org.qiu.spring.dao.VipDao"/>
<bean class="org.qiu.spring.dao.UserDao"/>
<bean id="cs" class="org.qiu.spring.service.CustomerService" autowire="byType"/>
@Test
public void testAutowireByType(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
    CustomerService customerService = applicationContext.getBean("cs", CustomerService.class);
    customerService.save();
}

运行结果:  

 

十、Spring 引入外部属性配置文件

我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。这些信息可以单独写到一个属性配置文件中,这样用户修改起来会更加的方便

第一步:写一个数据源类,提供相关属性:

package org.qiu.spring.bean;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * @author 秋玄
 * @version 1.0
 * @email qiu_2022@aliyun.com
 * @project Spring
 * @package org.qiu.spring.bean
 * @date 2022-11-09-11:01
 * @since 1.0
 */
public class MyDataSource implements DataSource {
    private String driver;
    private String url;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // 省略实现 DataSource 接口中的方法
}

第二步:在类路径下新建 jdbc.properties 文件,并配置信息:  

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=root

第三步:在 spring 配置文件中引入 context 命名空间  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

第四步:在 spring 中配置使用 jdbc.properties 文件  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="jdbc.properties"/>

    <bean id="dataSource" class="org.qiu.spring.bean.MyDataSource">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>

</beans>

测试程序:  

@Test
public void testProperties(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
    MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);
    System.out.println(dataSource);
}

运行结果:  

 

一  叶  知  秋,奥  妙  玄  心

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

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

相关文章

高速接口PCB布局指南(五)高速差分信号布线(三)

高速接口PCB布局指南&#xff08;五&#xff09;高速差分信号布线&#xff08;三&#xff09; 1.表面贴装器件焊盘不连续性缓解2.信号线弯曲3.高速信号建议的 PCB 叠层设计4.ESD/EMI 注意事项5.ESD/EMI 布局规则 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 …

SQL如何实现数据表行转列、列转行?

SQL行转列、列转行可以帮助我们更方便地处理数据&#xff0c;生成需要的报表和结果集。本文将介绍在SQL中如何实现数据表地行转列、列转行操作&#xff0c;以及实际应用示例。 这里通过表下面三张表进行举例 SQL创建数据库和数据表 数据表示例数据分别如下&#xff1a; data_…

算法提升——LeetCode123场双周赛总结

周赛题目 三角形类型 II 给你一个下标从0开始长度为3的整数数组nums&#xff0c;需要用它们来构造三角形。 如果一个三角形的所有边长度相等&#xff0c;那么这个三角形称为equilateral。 如果一个三角形恰好有两条边长度相等&#xff0c;那么这个三角形称为isosceles。 如…

反射相关知识

1. Class类 1&#xff09;除了基本数据类型外&#xff0c;其他类型都是class&#xff08;包括interface&#xff09;&#xff0c;class的本质也是数据类型&#xff08;Type&#xff09;。 2&#xff09;JVM每次动态加载时&#xff0c;会创建一个Class类型的实例…

CentOS7如何安装宝塔面板并实现固定公网地址远程访问

文章目录 一、使用官网一键安装命令安装宝塔二、简单配置宝塔&#xff0c;内网穿透三、使用固定公网地址访问宝塔 宝塔面板作为建站运维工具&#xff0c;适合新手&#xff0c;简单好用。当我们在家里/公司搭建了宝塔&#xff0c;没有公网IP&#xff0c;但是想要在外也可以访问内…

Linux---线程

线程概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列” 一切进程至少都有一个执行线程 线程在进程内部运行&#xff0c;本质是在进程地址空间内运行 在Linux系统中&#xff0c;在CPU眼中…

python介绍,安装Cpython解释器,IDE工具pycharm的使用

python介绍 官方的Python解释器本质是基于C语言开发的一个软件&#xff0c;该软件的功能就是读取以py.结尾的文件内容&#xff0c;然后按照Guido定义好的语法和规则去翻译并执行相应的代码。这种C实现的解释器被称为Cpython。 python解释器的种类&#xff1a;Jython IPyth…

Leetcode—134. 加油站【中等】

2024每日刷题&#xff08;113&#xff09; Leetcode—134. 加油站 实现代码 class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int gasSum accumulate(gas.begin(), gas.end(), 0);int costSum accumulate(cost…

信号系统之滤波详解

1 过滤的基础 通常希望使用信号的幅度&#xff0c;而不是它的功率。例如&#xff0c;假设一个增益为20dB的放大器。根据定义&#xff0c;这意味着信号中的功率增加了 100 倍。由于幅度与功率的平方根成正比&#xff0c;因此输出幅度是输入幅度的 10 倍。虽然 20dB 意味着功率的…

【C#】.net core 6.0 创建默认Web应用,以及默认结构讲解,适合初学者

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

航芯ACM32G103开发板评测 04 GC9A01 SPI-LCD 1.28圆形屏幕

航芯ACM32G103开发板评测 03 GC9A01 SPI-LCD 1.28圆形屏幕 硬件平台 航芯ACM32G103开发板1.28寸圆形彩色TFT显示屏高清IPS 模块240X240 SPI接口GC9A01 产品介绍 推荐一个屏幕资料参考网站 http://www.lcdwiki.com/1.28inch_IPS_Module 1.28寸圆形IPS彩屏&#xff0c;支持 R…

JAVA SpringBoot中使用redis的事务

目录 一、Java语言介绍 二、SpringBoot框架介绍 三、Redis缓存介绍 四、什么是redis的事务 一、Java语言介绍 Java是一种广泛使用的高级编程语言,由Sun Microsystems公司于1995年推出。它的设计目标是要求“一次编写,到处运行”&#xff08;Write Once, Run Anywhere, WOR…

orin nx 安装paddlespeech记录

nx配置&#xff1a; 模块 版本说明 CPU 8核 内存 16G Cuda版本 11.4 Opencv版本 4.5.4 Tensorrt版本 5.1 Cudnn版本 8.6.0.166 Deepstream版本 6.2 Python版本 3.8 算力 100T 安装paddlepaddle&#xff1a; 去飞桨官网下载jetpack版本的&#xff1a;下…

Leetcode第383场周赛

Leetcode第383场周赛 本人水平有限&#xff0c;只做前3道。 一、边界上的蚂蚁 边界上有一只蚂蚁&#xff0c;它有时向 左 走&#xff0c;有时向 右 走。 给你一个 非零 整数数组 nums 。蚂蚁会按顺序读取 nums 中的元素&#xff0c;从第一个元素开始直到结束。每一步&#…

控价新规要及时了解

控价工作的开展&#xff0c;除了依托品牌本身的规则&#xff0c;还要依赖一些外部能力的赋能&#xff0c;如对数据的监测&#xff0c;这个可以依靠人工实现&#xff0c;也可以利用数据监测系统去完成&#xff0c;或者是对破价链接的治理&#xff0c;虽然品牌多利用知识产权进行…

视频上传 - 断点续传那点事

在上一篇文章中&#xff0c;我们讲解了分片上传的实现方式。在讲解断点续传之前&#xff0c;我要把上篇文章中留下的问题讲解一下。读过上一篇文章的小伙伴们都知道&#xff0c;对于分片上传来说&#xff0c;它的传输方式分为2种&#xff0c;一种是按顺序传输&#xff0c;一种是…

工业级加固平板丨亿道三防平板电脑丨安卓工业平板丨改善车队管理

在现代物流和运输行业中&#xff0c;车队管理是一个复杂而重要的任务。为了更好地管理车队&#xff0c;提高工作效率和减少成本&#xff0c;许多企业正在采用新技术和工具。其中&#xff0c;三防平板电脑作为一种功能强大且适应恶劣环境的设备&#xff0c;已经在车队管理中得到…

ShardingSphere实现openGauss分布式架构

本文档采用openGauss结合ShardingSphere中间件的架构&#xff0c;实现openGauss数据库分布式OLAP场景的环境部署。 术语说明&#xff1a; 开源数据库引擎&#xff1a;openGauss shardingsphere Proxy&#xff1a;定位为透明化的数据库代理端&#xff0c;提供封装了数据库二进…

飞天使-k8s知识点16-kubernetes实操1-pod

文章目录 深入Pod 创建Pod&#xff1a;配置文件详解写个pod的yaml 文件深入Pod 探针&#xff1a;探针技术详解 深入Pod 创建Pod&#xff1a;配置文件详解 资源清单参考链接&#xff1a;https://juejin.cn/post/6844904078909128712写个pod的yaml 文件 apiVersion: v1 kind: P…

UE4运用C++和框架开发坦克大战教程笔记(十八)(第55~57集)

UE4运用C和框架开发坦克大战教程笔记&#xff08;十八&#xff09;&#xff08;第55~57集&#xff09; 55. UI 进入退出动画HideOther 面板出现时隐藏其他面板添加面板出现和收起的动画效果编写遮罩管理器前的准备 56. 弹窗进入界面57. UI 显示隐藏与遮罩转移完善遮罩管理器 55…