Spring IoC 深度学习
Io回顾
IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。
Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。
IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。
基础知识可以参考:
IoC基础
IoC引用外部属性文件
引入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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"></beans>
引入jdbc的依赖:
<!-- MySQL驱动 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version>
</dependency><!-- 数据源 -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.15</version>
</dependency>
在resources中创建jdbc的配置文件。(写一些测试数据)
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
创建bean-jdbc.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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入外部的数据源配置文件--><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 通过数据源的文件将数据注入bean中-->
<!-- 通过${}在数据源的配置文件中进行取值--><bean id="jdbcDriver" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.user}"></property><property name="password" value="${jdbc.password}"></property><property name="driverClassName" value="${jdbc.driver}"></property></bean>
</beans>
创建测试类进行测试。
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;@Testvoid test7() throws SQLException {ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");DataSource bean = context.getBean(DataSource.class);Connection connection = bean.getConnection();System.out.println(connection);}
测试结果:
bean的作用域
单例&多例
在bean中使用scope属性设置单例和多例,使用singleton/prototype。(默认使用单例)
生命周期
-
bean对象创建(调用无参构造器)
-
给bean对象设置属性
-
bean的后置处理器(初始化之前)
-
bean对象初始化(需在配置bean时指定初始化方法)
-
bean的后置处理器(初始化之后)
-
bean对象就绪可以使用
-
bean对象销毁(需在配置bean时指定销毁方法)
-
IOC容器关闭
进行测试 :
创建一个life类
public class Life {String name;//创建无参构造public Life() {System.out.println("1.创建一个空的实体类");}//初始化方法public void initMethod() {System.out.println("4.使用了初始化函数");}//销毁方法public void destroyMethod() {System.out.println("7.使用了摧毁函数");}public String getName() {return name;}public void setName(String name) {System.out.println("2.给属性进行赋值");this.name = name;}}
创建Spring的配置文件bean-life.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"><bean id="life" class="com.huang.Life" init-method="initMethod" destroy-method="destroyMethod" scope="singleton"><property name="name" value="hfw"></property></bean>
</beans>
编写测试代码
@Testvoid test1() {//ApplicationContext接口没有close方法,要使用ClassPathXmlApplicationContext实现类进行CLose操作ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");Life life = (Life) context.getBean("life");System.out.println("6.获取到了完整的实体类");context.close();}
测试结果
编写后置处理器
bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行。(默认使用BeanPostProcessor)
在BeanPostProcessor接口中存在俩个方法,就是对应初始化前后的方法。
所以我们创建自己的后置处理器时就是去实现这两个方法。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("3.在初始化之前的后置处理器");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("5.在初始化之后的后置处理器");return bean;}
}
将MyBeanprocessor在bean-life.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"><bean id="life" class="com.huang.Life" init-method="initMethod" destroy-method="destroyMethod" scope="singleton"><property name="name" value="hfw"></property></bean><bean id="myBeanProcessor" class="com.huang.MyBeanProcessor"></bean>
</beans>
进行测试,结果为下
FactoryBean(不是BeanFactory)
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
配置factoryBean类
package com.huang.factoryBean;import org.springframework.beans.factory.FactoryBean;public class factoryBean implements FactoryBean<User> {@Overridepublic User getObject() throws Exception {
//可以在这类中完成实体类的操作,将具体的操作封装在该方法中User user = new User();user.setName("hfw");return user;}@Overridepublic Class<?> getObjectType() {return User.class;}
}
将该类在bean-factoryBean.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"><bean id="factoryBean" class="com.huang.factoryBean.factoryBean"></bean>
</beans>
进行测试,最终我们会发现在获取该bean时会返回User对象,完成封装。
Spring 开启自动扫描的方法
在bean.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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--开启组件扫描功能-->
<!-- base-package对应的就是要扫描注解的包路径--><context:component-scan base-package="com.huang"><!-- 要排除的扫描注解的如路径-->
<!-- <context:exclude-filter type="annotation" expression="xxx.xxx.xxx"/>-->
<!--要排除扫描注解的类--><!--<context:exclude-filter type="assignable" expression="xxx.xxx.xxx"/>--><!-- 仅扫描的包路径-->
<!-- <context:include-filter type="annotation" expression="xxx.xxx.xxx"/>--><!-- 仅扫描的类--><!--<context:include-filter type="assignable" expression="xxx.xxx.xxx"/>--></context:component-scan>
</beans
spring中的@Autowired可以使用在 属性上,set方法上,构造方法上,构造方法的形参上,注解上。
如果类中只存在一个构造方法时,可以省略@Autowired。
如果在使用@Autowired的属性是接口且存在多个实现类的话,我们就需要使用@Qualifier(value="bean中对应的id"),我们可以将@Autowired当作ByType,@Resource当作ByName,如果Autowired要达到ByNam的效果就要配合@Qualifier使用 。
实现全注解开发
创建配置类
import org.springframework.context.annotation.ComponentScan;@org.springframework.context.annotation.Configuration
@ComponentScan
public class Configuration {
}
使用ApplicationContext的实现类AnnotationConfigApplicationContext
@org.junit.jupiter.api.Testvoid test2() {ApplicationContext context = new AnnotationConfigApplicationContext(Configuration.class);}
手写IoC
Java反射回顾测试例子
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class reflectTest {@Testpublic void Test1() throws Exception {//直接通过.class获取该类的classClass clazz1 = User.class;//通过new出来的对象调用getClass方法Class clazz2 = new User().getClass();//通过class.forName获取Class对象Class clazz3 = Class.forName("com.huang.User");//创建一个实体类后续需要使用User user = new User();System.out.println("############通过反射获取构造器############");//通过反射获取公共的构造器Constructor[] constructors = clazz1.getConstructors();for (Constructor item : constructors) {System.out.println(item.getName());//使用构造器的newInstance()创建实例}
// System.out.println("############=############");System.out.println("############获取所有的构造器############");//通过反射获取私有和公有的构造器Constructor[] declaredConstructors = clazz1.getDeclaredConstructors();for (Constructor item : declaredConstructors) {System.out.println(item.getName());}System.out.println("############获取类的属性############");Field[] fields = clazz1.getFields();System.out.println("因为属性全部为私有,所以打印为空");for (Field item : fields) {System.out.println(item.getName());}System.out.println("############获取类的私有和公共的属性############");Field[] declaredFields = clazz1.getDeclaredFields();for (Field item : declaredFields) {System.out.println(item.getName());if(item.getName().equals("name")) {//设置访问权限为true,这样我们才可以设置对应的属性item.setAccessible(true);item.set(user, "秃狼");System.out.println("设置的新值为:" + user.getName());}if(item.getName().equals("age")) {//设置访问权限为true,这样我们才可以设置对应的属性item.setAccessible(true);item.set(user, 21);System.out.println("设置的新值为:" + user.getAge());}}System.out.println("############获取类的方法############");Method[] methods = clazz1.getMethods();for (Method item : methods) {System.out.println(item);}System.out.println("############获取类的私有和公共的方法############");Method[] declaredMethods = clazz1.getDeclaredMethods();for (Method item : declaredMethods) {System.out.println(item.getName());if(item.getName().equals("tostring")) {//因为该方法是私有类型的,所以需要设置权限//这里使用了私有方法item.setAccessible(true);System.out.println("============");item.invoke(user);System.out.println("=============");}}System.out.println("############=############");}
}
这里的User为简单的类,可以自行创建
public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public User() {}private User(String name) {this.name = name;}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;}private void tostring() {System.out.println("Name:" + this.name + ";" + "age:" + this.age);}
}
测试结果为下
开始手写IoC
手写例子
这里设置的情况为每个类最多只有可以实现的接口,IoC为单例的情况。
创建两个注释:
Bean(转载注释)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//设置作用域:作用在类上
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
rush(注入注释)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//设置作用域:设置为作用在属性上
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface rush {
}
在包中创建三层架构:Dao,Service,Controller,分别创建一个接口和对应的Impl实现类。
这里的ApplicationContext就是包含一个getBean的接口,就是模仿Spring中ApplicationContext。
import com.huang.Annotation.Bean;
import com.huang.Annotation.rush;import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class AnnotationApplicationContext implements ApplicationContext{//bean的本质就是将对应的class和实例对象存放在map中,放和取就是通过对应的注解完成private Map<Class, Object> beanFactory = new HashMap<>();
//绝对路径的头路径private String rootPath;@Overridepublic Object getBean(Class clazz) {return beanFactory.get(clazz);}public AnnotationApplicationContext(String basePackage) {/*basePackage中的路径为指定类的当前路径,并且要进行格式转换后获取绝对路径*/String packageDirName = basePackage.replaceAll("\\.", "\\\\");try {//通过当前线程获取对应的绝对路径Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url = dirs.nextElement();/*因为获取的绝对路径中的"\"会被打印成"%",需要通过Decoder将绝对路径转为UTF-8的格式*/String filePath = URLDecoder.decode(url.getFile(), "utf-8");/*获取绝对路径头路径,方便后续的拆分,filePath.length() - packageDirName.length() - 1,正好就取到头路径部分*/rootPath = filePath.substring(0, filePath.length() - packageDirName.length() - 1);//装载beanthis.loadBean(new File(filePath));//注入属性this.loadRush();}} catch (Exception e) {e.printStackTrace();}}private void loadBean(File file) throws ClassNotFoundException, IllegalAccessException, InstantiationException {//进行判断插入的文件是否为文件夹if(file.isDirectory()) {//获取去子文件,如果没有就说明文件夹为空,直接返回空值File[] files = file.listFiles();if(files.length == 0 || files == null) {return ;}for (File child : files) {if(child.isDirectory()) {//如果子文件还是文件夹的话,就直接使用递归调用loadBean函数loadBean(child);} else {//将子文件的绝对路径设置截取为类路径String pathWithClass = child.getAbsolutePath().substring(rootPath.length());//获取类的路径后,需要判断是否为.class文件再进行操作if(pathWithClass.endsWith(".class")) {//如果是,就再将类路径进行格式转化String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");//通过类路径获取反射Class<?> aClass = Class.forName(fullName);//判断该反射是否为接口的反射类,如果不是我们才进行判断类上是否有指定的注解if(!aClass.isInterface()) {//获取类上的注解,判断这些注解是否有指定的注解Bean annotation = aClass.getAnnotation(Bean.class);if(annotation != null) {//instance作为beanFactory的值Object instance = aClass.newInstance();//如果该类存在实现的接口就用接口作为键,这里就不考虑存在多个接口了if(aClass.getInterfaces().length > 0) {Class<?>[] interfaces = aClass.getInterfaces();//这里就考虑存在一个接口beanFactory.put(aClass.getInterfaces()[0], instance);} else {//如果不存在就之家用本类beanFactory.put(aClass, instance);}}}}}}} else {System.out.println("不是文件夹,输入有误");return ;}}private void loadRush() throws IllegalAccessException {//遍历mapSet<Map.Entry<Class, Object>> entries = beanFactory.entrySet();for (Map.Entry<Class, Object> entry : entries) {//获取实体类(这里就只考虑单例)Object obj = entry.getValue();Class key = obj.getClass();//获取所有的属性Field[] declaredFields = key.getDeclaredFields();for (Field field : declaredFields) {//设置访问权限field.setAccessible(true);//判断该属性是否有对应的注解rush annotation = field.getAnnotation(rush.class);if(annotation != null) {//就对实体类的属性进行赋值field.set(obj, beanFactory.get(field.getType()));//完成注入}}}}
}
在代码中 String filePath = URLDecoder.decode(url.getFile(), "utf-8")的作用是格式化路径,如果不加将会出现下面的情况。(/被%替代)
测试代码
//要到对自己写的包
import com.huang.ApplicationContext.AnnotationApplicationContext;
import com.huang.ApplicationContext.ApplicationContext;
import com.huang.Controller.UserController;public class TestUser {public static void main(String[] args) {ApplicationContext context = new AnnotationApplicationContext("com.huang");UserController userController = (UserController) context.getBean(UserController.class);userController.run();}
}
测试结果为下:
最终完成手写IoC。
相关文章:
Spring IoC 深度学习
Io回顾 IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。 Spring 通过 IoC 容器来管理所有 Jav…...
C语言从入门到精通第17天(指针和数组联用)
指针和数组联用 不同类型指针变量之间的区别数组的指针指针数组 不同类型指针变量之间的区别 在了解数组和指针联用之前,我们先对指针变量进行补充。我们对比一下int *p1和char *p2的区别? 相同点: 都是指针变量都是用来保存一个内存地址编…...
Android9.0 原生系统SystemUI下拉状态栏和通知栏视图之锁屏通知布局
1.前言 在9.0的系统rom定制化开发中,对于系统原生systemui的锁屏界面的功能也是非常重要的,所以在锁屏页面布局中,也是有通知栏布局的,所以接下来对于息屏亮屏 通知栏布局的相关流程分析,看下亮屏后锁屏页面做了哪些功能 2.原生系统SystemUI下拉状态栏和通知栏视图之锁…...
音视频八股文(10)-- mp4结构
介绍 mp4⽂件格式⼜被称为MPEG-4 Part 14,出⾃MPEG-4标准第14部分 。它是⼀种多媒体格式容器,⼴泛⽤于包装视频和⾳频数据流、海报、字幕和元数据等。(顺便⼀提,⽬前流⾏的视频编码格式AVC/H264 定义在MPEG-4 Part 10)…...
python算法中的深度学习算法之深度信念网络(详解)
目录 学习目标: 学习内容: 深度信念网络 Ⅰ. 预训练 Ⅱ. 微调 学习目标: 一分钟掌握 python算法中的深度学习算法之深度信念网络 入门知识...
SPSS如何绘制常用统计图之案例实训?
文章目录 0.引言1.绘制简单条形图2.绘制分类条形图3.绘制分段条形图4.绘制简单线图5.绘制多重线图6.绘制垂直线图7.绘制简单面积图8.绘制堆积面积图9.绘制饼图10.绘制直方图11.绘制简单散点图12.绘制重叠散点图13.绘制矩阵散点图14.绘制三维散点图15.绘制简单箱图16.绘制分类箱…...
打动人心的故事 | 如何利用文案在Facebook上塑造品牌形象
在当今的数字营销时代,文案已经成为各大平台上不可或缺的元素之一。在Facebook上,一个好的文案能够为品牌带来巨大的曝光率和用户黏性,甚至可以改变用户对品牌的看法。那么,如何利用文案在Facebook上打动人心,塑造品牌…...
什么是模糊控制?
模糊控制设计原理 1、传统控制系统和模糊控制系统 传统控制系统结构: 控制目的:通过控制器调节控制信号u,使输出信号y达到要求 模糊控制系统结构: 与传统控制系统的差异:用模糊控制器FC(Fuzzy Controller&…...
仿抖音开发需要注意的问题
一、版权问题 仿抖音开发需要注意版权问题,包括内容的版权和软件的版权。在开发的过程中,不要直接抄袭他人的作品,应该注重保护知识产权。 二、安全性问题 仿抖音开发需要重视应用的安全性问题,避免应用在使用过程中发生安全漏…...
如何根据期刊缩写查找期刊?
英文论文写作中,经常会插入参考文献。参考文献中的期刊名称,时常需要使用缩写。或者是手头有期刊缩写后的名称,但是有时候,查了半天也查不到期刊期刊全称,费时费力让人崩溃。今天就给各位学者老师总结一些查询期刊缩写…...
数据发送流程
在发送模式下,UART 的串行数据发送电路主要包括一个发送移位寄存器(TSR),TSR 功能是将数据 逐个移位送出。待发数据必须先写到发送缓冲区中。 TXIFx 是发送中断标志位,可配置为发送缓冲区空或TSR 空。 数据的发送支持7bit 、8bit 或9bit 数据…...
堆及其应用
堆是一种基于树结构的数据结构,通常用于实现优先队列。堆分为最大堆和最小堆两种类型,最大堆的每个节点的值都大于等于其子节点的值,最小堆则相反,每个节点的值都小于等于其子节点的值。 基础算法操作包括: 1. 插入元…...
MySQL数据库备份脚本
PS:此脚本简单易懂,根据实际情况修改个别参数测试后即可使用,如有错误请指出! 1.MySQL数据库备份脚本 #!/bin/bashuser pw ip dateYdate "%Y" date2date "%Y%m%d" date3date "%Y%m%d %H:%M" date…...
【2023 · CANN训练营第一季】应用开发深入讲解——第三章应用调试
学习资源 日志参考文档 应用开发FAQ 日志主要用于记录系统的运行过程及异常信息,帮助快速定位系统运行过程中出现的问题以及开发过程中的程序调试问题。 日志分为如下两大类: 系统类日志:系统运行产生的日志。主要包括: Contro…...
黎曼几何与黎曼流形
目录 0.黎曼几何 1. 欧几里得几何与黎曼几何的区别 2.黎曼流形 3.黎曼距离 4.切空间 5.黎曼均值 6. SPD矩阵如何形成黎曼流型 7.切线空间映射 8.同余变换和同余不变 9.黎曼对齐 科普性笔记,做了解,不深入。 0.黎曼几何 黎曼几何是一种基于欧几…...
lua | 运算符与字符串
目录 一、运算符 算数运算符 关系运算符 逻辑运算符 其他运算符 运算符优先级 二、字符串 转义字符 方法与用途 字符串截取 字符串大小转换 字符串查找与反转 字符串格式化 字符与整数的转换 匹配模式 本文章为笔者学习分享 学习网站:Lua 基本语法 | …...
NetBackup 10.2 新功能介绍:PostgreSQL 和 MySQL 自动化恢复达成
NetBackup 10.2 新功能介绍:PostgreSQL 和 MySQL 自动化恢复达成 原文来自:VERITAS 中文社区 2023-04-27 在执行恢复任务时,手动提取、更新数据库和实例并将其附加到 PostgreSQL 和 MySQL 是常规操作。而在最新的 NetBackup 10.2 版本中&am…...
ADRV9002官方例程开发过程中遇到的问题
开发环境:Vivado2021.2 HDL版本:hdl_2021_r2 GitHub - analogdevicesinc/hdl at hdl_2021_r2 no-OS版本:no_OS-2021_R2 GitHub - analogdevicesinc/no-OS at 2021_R2 (PS:也可以用Vivado2019.1开发,…...
Figma转换为sketch,分享这3款工具
在我们的设计工作中,我们经常会遇到各种各样的设计文件相互转换的问题。 你经常为此头疼吗?当你遇到Figma转换Sketch文件的问题时,你是如何解决的?Figma转换Sketch文件有工具吗? 根据众多设计师的经验,本…...
淘宝天猫1688京东商品详情API接口,封装接口可高并发
要提供商品详情数据需要知道具体的商品信息,但通常商品详情数据应包括以下内容: 商品名称:商品的名称,以方便顾客对其进行识别和区分。 商品描述:一段让顾客能够全面认识商品的描述。应能够有效地展示商品的特性、功能…...
虹科荣誉 | 虹科工业物联网产品荣获中国自动化产业年会用户信赖产品奖!
2023 虹科荣获2021年度中国自动化产业年会用户信赖产品奖 近日,2023中国自动化产业年会于北京隆重举行。虹科工业物联网的产品“OPC UA Tunneller软件”凭借其产品优势和市场美誉度,通过层层选拔,在本次大会中荣获2021年度用户信赖产品奖。…...
SwiftUI 如何让文本自动支持查找和替换功能?
概览 有些情况下,我们需要为文本编辑器实现文本的查找和替换功能(find & replace),如果完全靠自已撸码还是比较棘手的。 所幸的是,从 SwiftUI 4.0 (iOS 16)开始,Apple 已经将查…...
SpringCloud全面学习笔记之初尝美妙篇
目录 前言初识微服务单体架构分布式架构微服务架构初见SpringCloud微服务治理分布式服务架构案例 微服务组件及使用Eureka注册中心提供者和消费者Eureka的结构和作用搭建Eureka服务注册服务服务发现Eureka注册服务总结 Ribbon负载均衡原理负载均衡原理负载均衡策略懒加载 Nacos…...
Spring MVC框架
Spring MVC框架 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spri…...
Illustrator如何使用图层与蒙版之实例演示?
文章目录 0.引言1.绘制可爱冰淇淋图标2.霓虹渐变立体文字海报3.炫彩花纹背景 0.引言 因科研等多场景需要进行绘图处理,笔者对Illustrator进行了学习,本文通过《Illustrator CC2018基础与实战》及其配套素材结合网上相关资料进行学习笔记总结,…...
Office Tool Plus的使用
是否为安装,卸载,激活Office而烦恼? 下载 地址:Office Tool Plus 官方网站 - 一键部署 Office 安装office 先安装Office,Office_Pro_Plus_2021_LTSCProjectVisio_x64_zh_CN_VL_2022-02 注意,要安装批量…...
射频PCB 设计的六大条技巧
即使是最自信的设计人员,对于射频电路也往往望而却步,因为它会带来巨大的设计挑战,并且需要专业的设计和分析工具。这里将为您介绍六条技巧,来帮助您简化任何射频PCB 设计任务和减轻工作压力! 1、保持完好、精确的射频…...
优化了成本和安装难度后,UWB信标能否取代蓝牙信标?
1 我们做安U3号是要解决什么问题? (1)信标式设计,解决传统UWB基站安装过程繁琐复杂的问题 传统UWB基站在安装过程中遇上的难题: l 安装位置选取问题:UWB基站的准确度与其安装位置有很大关系,…...
深入理解Java虚拟机——垃圾回收算法
1.前言 垃圾回收需要完成的三件事 首先我们需要明白垃圾回收需要完成的三件事: 哪些内存需要回收 堆内存中的对象所使用的内存方法区中的废弃的常量以及不再使用的类型 什么时候回收 当对象死亡方法区中某些内容(常量和类型)不再被使用 如…...
git-rebase和merge
A-----B----C----D master E----F-----G feature 为了把main分支里新增的代码应用在你的feature分支,你有两种方法:merge 和 rebase。 merge git checkout feature git merge main A-----B----C----D master E----F-----G -----* feature (合并master…...
变态版手游/龙岩seo
最近因为脚本用到python的文件复制操作,而且又涉及网络目录,网上比较缺少这块的知识的实例,特此贡献也为自己更好的学习。 对文件的复制操作一般要引入shutil模块: import shutil shutil.copyfile("old","new&qu…...
网站 建设ppt模板/关键词搜索排名工具
最近的工作我在做一个有关于消息发送和接受封装工作。大概流程是这样的,消息中间件是采用rabbitmq,为了保证消息的绝对无丢失,我们需要在发送和接受前对消息进行DB落地。在发送前我会先进行DB的插入,单表插入,所以在性…...
证书兼职的正规平台哪里有/seo模拟点击软件源码
采用Mysqldump备份 相当于读出数据然后导出,这个过程禁止非读操作,因此,加锁读取。 1. 刷新数据库并加锁 FLUSH TABLES WITH READ LOCK; 2. 新开一个会话,执行导出 mysqldump -u root -p sakila > sakila-backup.sql 3. 原会…...
xp系统做网站服务器吗/廊坊seo网站管理
转载于:https://www.cnblogs.com/liying123/p/5291669.html...
文网站建设/中国舆情观察网
http://www.bubuko.com/infodetail-648898.html转载于:https://www.cnblogs.com/beijingstruggle/p/5518269.html...
公务员 做网站 违法/关键词优化上海
转载...在使用VS2005和SQL Server 2005,将原来在VS03下的工程和SQL Server 2000 的数据库,出现以下错误:错误 1 EXTERNAL 附近有语法错误。您可能需要将当前数据库的兼容级别设置为更高的值,以启用此功能。有关存储过程 sp_dbcmptlevel 的信息,请参见帮助…...