实现Spring底层机制(三)

文章目录

  • 阶段4—实现BeanPostProcessor机制
    • 1.文件目录
    • 2.初始化方法实现
        • 1.编写初始化接口InitializingBean.java
        • 2.MonsterService.java实现初始化接口
        • 3.容器中的createBean方法增加初始化逻辑,判断对象类型是否是InitializingBean的子类型,如果是,则转换成初始化接口类型执行初始化方法
    • 3.后置处理器实现
        • 1.编写后置处理器接口BeanPostProcessor.java
        • 2.在组件文件夹下编写后置处理器实现类SunBeanPostProcessor.java会被容器扫描
        • 3.容器类完整代码SunSpringApplicationContext.java
        • 4.结果展示
    • 4.该阶段完成的任务
  • 阶段5—实现AOP机制&Spring底层机制总结
    • 1.实现AOP机制
        • 1.原理分析
        • 2.代码实现
          • 1.文件目录
          • 2.编写接口SmartAnimalable.java
          • 2.编写实现类SmartDog.java
          • 3.编写切面类SmartAnimalAspect.java
          • 4.修改SunBeanPostProcessor.java对SmartDog的getSum方法进行动态代理
          • 5.启动类
          • 6.结果展示
        • 3.该阶段完成的任务
    • 2.Spring底层机制总结
        • 1.bean的生命周期
        • 2.Spring容器的执行流程
        • 3.动态代理和AOP的区别
        • 4.关于后置处理器 + 动态代理的理解
        • 5.AOP的使用方式

阶段4—实现BeanPostProcessor机制

1.文件目录

image-20240222142242669

2.初始化方法实现

1.编写初始化接口InitializingBean.java
package com.sun.spring.processor;/*** 该接口有一个方法afterPropertiesSet是在依赖注入之后调用,即初始化方法* @author 孙显圣* @version 1.0*/
public interface InitializingBean {void afterPropertiesSet() throws Exception;
}
2.MonsterService.java实现初始化接口
package com.sun.spring.component;import com.sun.spring.annotation.Autowired;
import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.Scope;
import com.sun.spring.processor.InitializingBean;/*** @author 孙显圣* @version 1.0*/@Scope(value = "prototype") //指定是多例的
@Component(value = "monsterService")//自定义注解,自动反射创建bean对象,如果指定了value则id为value否则为首字母小写
public class MonsterService implements InitializingBean{//自定义注解,按照名字进行依赖注入@Autowiredprivate MonsterDao monsterDao;public void m1() {monsterDao.hi();}//初始化方法@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("MonsterService 的初始化方法被调用!");}
}
3.容器中的createBean方法增加初始化逻辑,判断对象类型是否是InitializingBean的子类型,如果是,则转换成初始化接口类型执行初始化方法

3.后置处理器实现

1.编写后置处理器接口BeanPostProcessor.java
package com.sun.spring.processor;/*** @author 孙显圣* @version 1.0*/
public interface BeanPostProcessor {//这两个方法会对Spring容器的所有bean生效,切面编程//bean初始化方法前调用default Object postProcessBeforeInitialization(Object bean, String beanName){return bean;}//bean初始化方法后调用default Object postProcessAfterInitialization(Object bean, String beanName){return bean;}
}
2.在组件文件夹下编写后置处理器实现类SunBeanPostProcessor.java会被容器扫描
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.BeanPostProcessor;/*** 后置处理器,实现了自定义的后置处理器的接口** @author 孙显圣* @version 1.0*/
//反射创建bean对象
@Component
public class SunBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("\n后置处理器postProcessBeforeInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);if (bean instanceof Car) {System.out.println("后置处理器发现这个类型是Car类型");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("后置处理器postProcessAfterInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);return bean;}
}
3.容器类完整代码SunSpringApplicationContext.java
package com.sun.spring.ioc;import com.sun.spring.annotation.Autowired;
import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.ComponentScan;
import com.sun.spring.annotation.Scope;
import com.sun.spring.processor.BeanPostProcessor;
import com.sun.spring.processor.InitializingBean;
import org.apache.commons.lang.StringUtils;import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** 类似于Spring原生的ioc容器** @author 孙显圣* @version 1.0*/
public class SunSpringApplicationContext {//传进来一个配置类的Class对象private Class configClass;//bean定义字段private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();//bean对象字段private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();//定义一个属性ArrayList来存放后置处理器private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();//构造器,接收配置类的class对象public SunSpringApplicationContext(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {//bean定义扫描,并将信息封装到beanDefinitionMap中this.beanDefinitionScan(configClass);//初始化单例池//1.获取所有bean的名字Enumeration<String> keys = beanDefinitionMap.keys();//2.遍历名字while (keys.hasMoreElements()) {String beanName = keys.nextElement();//3.是单例类型的就创建bean对象并放到单例池中BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")) {Object bean = createBean(beanDefinition, beanName);//4.放到单例池singletonObjects.put(beanName, bean);}}}public void beanDefinitionScan(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {this.configClass = configClass;//一、获取要扫描的包//1.首先反射获取类的注解信息ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);//2.通过注解来获取要扫描的包的路径String path = componentScan.value();System.out.println("要扫描的包=" + path);//二、得到要扫描包的.class文件对象,从而得到全路径进行反射//1.获取类加载器ClassLoader classLoader = SunSpringApplicationContext.class.getClassLoader();//2.获取要扫描包的真实路径,默认刚开始在根目录下path = path.replace(".", "/");URL resource = classLoader.getResource(path);//3.由该路径创建一个文件对象,可使用resource.getFile()将URL类型转化为String类型File file = new File(resource.getFile());//4.遍历该文件夹下的所有.class文件对象if (file.isDirectory()) {File[] files = file.listFiles();System.out.println("==================================扫描所有组件==================================");for (File f : files) {//反射注入容器//1.获取所有文件的绝对路径String absolutePath = f.getAbsolutePath();//只处理class文件if (absolutePath.endsWith(".class")) {//2.分割出类名String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1,absolutePath.indexOf("."));//3.得到全路径String fullPath = path.replace("/", ".") + "." + className;//4.判断是否需要注入容器,查看有没有自定义的注解ComponentClass<?> aClass = classLoader.loadClass(fullPath);//如果该类使用了注解Component则说明是一个spring beanif (aClass.isAnnotationPresent(Component.class)) {//后置处理器逻辑//为了方便,将后置处理器放到ArrayList,原生的Spring容器中,对后置处理器还是放到的singletonObjects//判断当前的class对象是否实现了后置处理器的接口if (BeanPostProcessor.class.isAssignableFrom(aClass)) {//如果实现了后置处理器的接口则转换成后置处理器类型BeanPostProcessor beanPostProcessor = (BeanPostProcessor) aClass.newInstance();//添加到ArrayList中beanPostProcessors.add(beanPostProcessor);//后面我们并没有用到单例池中的后置处理器,所以不需要将这个bean定义的信息放到mapcontinue;}System.out.println("这是一个Spring bean=" + aClass);//将Bean的信息封装到BeanDefinition对象中并放入到beanDefinitionMapBeanDefinition beanDefinition = new BeanDefinition();//获取scope注解信息Scope scopeAnnotation = aClass.getDeclaredAnnotation(Scope.class);//只要scopeAnnotation是空的或者他不是空的但是值是空串,则返回singleon,否则就返回valueString scope = scopeAnnotation == null || scopeAnnotation.value().equals("") ?"singleton" : scopeAnnotation.value();//封装信息到bean定义字段中beanDefinition.setScope(scope);beanDefinition.setClazz(aClass);//获取Component注解的value值作为beanNameComponent componentAnnotation = aClass.getDeclaredAnnotation(Component.class);//只要component注解的值是空串就返回类名首字母小写,否则返回这个注解的值String beanName = componentAnnotation.value().equals("") ?StringUtils.uncapitalize(className) : componentAnnotation.value();//封装到beanDefinitionMap中beanDefinitionMap.put(beanName, beanDefinition);} else {System.out.println("这不是一个Spring bean=" + aClass);}}}}}//根据bean定义对象来创建bean对象private Object createBean(BeanDefinition beanDefinition, String beanName) {//获取Class对象,反射创建实例Class clazz = beanDefinition.getClazz();try {Object instance = clazz.getDeclaredConstructor().newInstance();//进行依赖注入//1.遍历所有字段for (Field field : clazz.getDeclaredFields()) {//2.判断字段中是否有autowired注解if (field.isAnnotationPresent(Autowired.class)) {//3.依赖注入String name = field.getName();Object bean = getBean(name);//反射爆破field.setAccessible(true);field.set(instance, bean);System.out.println(instance + "依赖注入完毕!");}}//初始化方法逻辑//判断是否要执行Bean的初始化方法//存储instanceObject result = instance;//查看这个对象是否实现了InitializingBean接口,instanceof判断是否是某个类型或者某个类型的子类型if (instance instanceof InitializingBean) {//在初始化方法之前调用后置处理器的before方法,可以对容器的bean进行修改for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}//向上转型为接口类型并调用初始化方法((InitializingBean) instance).afterPropertiesSet();//在初始化方法之后调用后置处理器的before方法,可以对容器的bean进行修改for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}}//如果返回的instence是null,则返回之前存贮的结果if (instance == null) {return result;}//如果成功则返回这个对象return instance;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (Exception e) {throw new RuntimeException(e);}}//返回容器中的对象public Object getBean(String name) {//如果是单例的,则从单例池中获取,如果是多例的则直接创建一个实例返回,名字没在bean定义中则抛出异常if (beanDefinitionMap.containsKey(name)) {BeanDefinition beanDefinition = beanDefinitionMap.get(name);//判断是否是单例if ("singleton".equals(beanDefinition.getScope())) {//从单例池中获取对象return singletonObjects.get(name);} else {//直接创建对象(多例)return createBean(beanDefinition, name);}} else {//name不在bean定义中则抛出异常throw new NullPointerException("没有该bean");}}}
4.结果展示

image-20240222143316755

4.该阶段完成的任务

  • 实现初始化方法
    • 编写初始化接口,里面有一个default的初始化方法
    • 编写初始化实现类,重写这个初始化方法
    • 在容器的依赖注入后添加初始化逻辑,当这个对象的类型是初始化接口的子类型的时候,就将其转换成接口类型并且调用初始化方法
  • 后置处理器实现
    • 编写一个后置处理器接口,里面有两个方法一个在初始化前调用,一个在初始化后调用
    • 在组件文件夹下编写后置处理器实现类
    • 在容器中beanDefinitionScan方法的扫描组件时添加后置处理器逻辑,如果该组件实现了后置处理器接口,则转换成后置处理器类型,并且放到ArrayList中方便查找
    • 在容器中的createBean方法增加后置处理器逻辑,在初始化方法之前和之后遍历存储后置处理器的ArrayList并分别执行方法

阶段5—实现AOP机制&Spring底层机制总结

1.实现AOP机制

1.原理分析

image-20240222151512245

2.代码实现
1.文件目录

image-20240222164154334

2.编写接口SmartAnimalable.java
package com.sun.spring.component;/*** @author 孙显圣* @version 1.0*/
public interface SmartAnimalable {float getSum(float i, float j);float getSub(float i, float j);
}
2.编写实现类SmartDog.java
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.InitializingBean;/*** @author 孙显圣* @version 1.0*/
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable, InitializingBean {public float getSum(float i, float j) {float res = i + j;System.out.println("SmartDog-getSum=" + res);return res;}public float getSub(float i, float j) {float res = i - j;System.out.println("SmartDog-getSub=" + res);return res;}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("smartDog 被初始化!");}
}
3.编写切面类SmartAnimalAspect.java
package com.sun.spring.component;/*** @author 孙显圣* @version 1.0*/
public class SmartAnimalAspect {public static void showBeginLog() {System.out.println("前置通知");}public static void showSuccessLog() {System.out.println("返回通知");}
}
4.修改SunBeanPostProcessor.java对SmartDog的getSum方法进行动态代理
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.BeanPostProcessor;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 后置处理器,实现了自定义的后置处理器的接口** @author 孙显圣* @version 1.0*/
//反射创建bean对象
@Component
public class SunBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("\n后置处理器postProcessBeforeInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);if (bean instanceof Car) {System.out.println("后置处理器发现这个类型是Car类型");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("后置处理器postProcessAfterInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);//实现AOP,返回代理对象if ("smartDog".equals(beanName)) {//使用jdk的动态代理返回代理对象/*** ClassLoader loader,* Class<?>[] interfaces,* InvocationHandler h*///1.要代理的对象的类加载器ClassLoader classLoader = bean.getClass().getClassLoader();//2.要代理对象的接口信息Class<?>[] interfaces = bean.getClass().getInterfaces();//3.代理对象执行的方法,在代理对象执行所有的方法时都会调用InvocationHandler invocationHandler = new InvocationHandler() {/*** 代理对象执行的方法,在代理对象执行所有的方法时都会调用** @param proxy 动态代理对象** @param method 动态代理对象调用的方法** @param args 方法的参数** @return 返回method返回的结果* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//判断是不是getSum方法,如果是,则进行AOP处理Object result = null;if ("getSum".equals(method.getName())) {//前置通知SmartAnimalAspect.showBeginLog();result = method.invoke(bean, args);//返回通知SmartAnimalAspect.showSuccessLog();} else {//如果不是getSum方法则正常执行原来的方法result = method.invoke(bean, args);}return result;}};//返回针对接口的代理对象(可以使用接口类型接收)return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);}return bean;}
}
5.启动类
package com.sun.spring;import com.sun.spring.component.MonsterService;
import com.sun.spring.component.SmartAnimalable;
import com.sun.spring.ioc.SunSpringApplicationContext;
import com.sun.spring.ioc.SunSpringConfig;/*** @author 孙显圣* @version 1.0*/
public class AppMain {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {SunSpringApplicationContext ioc = new SunSpringApplicationContext(SunSpringConfig.class);//单例对象Object bean01 = ioc.getBean("monsterDao");//测试依赖注入MonsterService bean = (MonsterService) ioc.getBean("monsterService");System.out.println("==================================测试依赖注入调用方法==================================");bean.m1();//演示AOPSystem.out.println("==================================测试AOP==================================");SmartAnimalable proxy = (SmartAnimalable) ioc.getBean("smartDog");proxy.getSub(4,1);proxy.getSum(2,4);}
}
6.结果展示

image-20240222164835898

3.该阶段完成的任务
  • 编写接口,编写实现类并将实例交给Spring容器管理,编写切面类
  • 后置处理器中进行动态代理操作,这里是对SmartDog类型的getSum方法进行动态代理
    • 首先判断beanName是不是smartDog
    • 如果是则进行动态代理,invoke方法中先判断当前执行的方法是不是getSum
    • 如果是getSum则插入前置通知和返回通知,如果不是则正常执行这个方法

2.Spring底层机制总结

1.bean的生命周期
  • 反射创建bean对象
  • 依赖注入
  • 初始化bean
  • getBean
  • 销毁bean
2.Spring容器的执行流程
  • 获取容器对象
  • 读取配置文件,得到要扫描的包
  • 扫描包下的组件,将bean定义信息放到Map中
  • 如果是单例
    • 反射创建bean对象,放到单例池中
    • 依赖注入(调用getBean)
    • 初始化bean
      • 初始化容器前调用后置处理器的before方法
      • 初始化容器之后调用后置处理器的after方法
  • 如果是多例
    • 在这个阶段什么都不做
  • getBean阶段
    • 如果是单例
      • 从单例池中获取bean对象
    • 如果是多例
      • 反射创建bean对象
      • 依赖注入(调用getBean)
      • 初始化bean
        • 初始化容器前调用后置处理器的before方法
        • 初始化容器之后调用后置处理器的after方法
      • 得到bean对象
  • 销毁bean
3.动态代理和AOP的区别
  • 动态代理:针对的是某个对象所有方法
  • AOP:针对的是某些类型所有对象具体方法
4.关于后置处理器 + 动态代理的理解
  • 后置处理器作用于Spring容器中所有类型,所有对象的初始化方法
  • getBean得到的就是后置处理器返回的bean
  • 当进入到后置处理器的时候
    • 获取切面类的所有信息
    • 将切入表达式与当前bean对象进行对比,只要类型匹配就进行动态代理
    • 使用动态代理进一步筛选要代理的方法,并根据不同的通知执行不同的操作,返回动态代理对象
    • 如果是不需要代理的方法,就不进行额外操作
5.AOP的使用方式
  • 编写接口,接口对象(注解)(用于展示AOP的效果,因为没有对象)
  • 编写切面类(注解),切面对象(注解)
  • 通知 + 切点
  • 配置beans.xnl
    • 普通注解扫描
    • 开启AOP注解
  • 具体使用
    • 获取针对接口类型的代理对象(通过id或者接口类型获取)
    • 使用代理对象调用接口的方法
  • 四种通知
    • 前置通知
    • 返回通知
    • 异常通知
    • 后置通知

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

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

相关文章

FRP远程连接

前言 通过frp和跳板机完成局域网服务器访问。工具地址&#xff1a;https://github.com/fatedier/frp 配置frp过程 下载frp工具&#xff0c;下载地址如下&#xff1a; https://github.com/fatedier/frp/releases 这里我选择了v0.57.0 解压到本地路径 tar -zxvf xxxxxx.tar.gz配…

python爬虫学习第二十八天-------了解scrapy(二十八天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

接口测试和Mock学习路线(中)

1.什么是 swagger Swagger 是一个用于生成、描述和调用 RESTful 接口的 WEB 服务。 通俗的来讲&#xff0c;Swagger 就是将项目中所有想要暴露的接口展现在页面上&#xff0c;并且可以进行接口调用和测试的服务。 现在大部分的项目都使用了 swagger&#xff0c;因为这样后端…

fakak详解(2)

Kafka和Flume整合 Kafka与flume整合流程 Kafka整合flume流程图 flume主要是做日志数据(离线或实时)地采集。 图-21 数据处理 图-21显示的是flume采集完毕数据之后&#xff0c;进行的离线处理和实时处理两条业务线&#xff0c;现在再来学习flume和kafka的整合处理。 配置fl…

微信小程序开发工具的使用,各个配置文件详解,小程序开发快速入门

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

redis单线程模型

工作原理 在Redis中&#xff0c;当两个客户端同时发送相同的请求时&#xff0c;Redis采用单线程模型来处理所有的客户端请求&#xff0c;会依次处理这些请求&#xff0c;每个请求都会按照先后顺序被执行&#xff0c;不会同时处理多个请求。使得Redis能够避免多线程并发访问数据…

大语言模型应用指南:以ChatGPT为起点,从入门到精通的AI实践教程

目录 前言ChatGPT问世和发展展望未来大语言模型应用指南 特点大语言模型应用指南 主要内容 前言 在20世纪末和21世纪初&#xff0c;人类经历了两次信息革命的浪潮。 第一次是互联网时代的兴起&#xff0c;将世界各地连接在一起&#xff0c;改变了人们获取信息和交流的方式。 …

函数式接口及Stream流式计算

一、什么是函数式接口 只有一个方法的接口&#xff0c;例如 FunctionalInterface public interface Runnable { public abstract void run(); }二、Function函数式接口&#xff1a;有一个输入参数&#xff0c;有一个输出 三、断定型接口&#xff1a;有一个输入参数&#xf…

《ElementPlus 与 ElementUI 差异集合》el-select 显示下拉列表在 Cesium 场景中无法监听关闭

前言 仅在 Element UI 时有此问题&#xff0c;Element Plus 由于内部结构差异较大&#xff0c;不存在此问题。详见《el-select 差异点&#xff0c;如&#xff1a;高、宽、body插入等》&#xff1b; 问题 点击空白处&#xff0c;下拉列表可监听并关闭&#xff1b;但在 Cesium…

【js】解决自动生成颜色时相邻颜色视觉相似问题的技术方案

解决自动生成颜色时相邻颜色视觉相似问题的技术方案 在进行大规模颜色生成时&#xff0c;特别是在数据可视化、用户界面设计等应用领域&#xff0c;一个常见的挑战是确保相邻颜色在视觉上具有足够的区分度。本文介绍的方法通过结合黄金分割比与饱和度、亮度的周期性变化&#…

数据分析_时间维度对比及变化可视化分析(Pandas和Matplotlib)

数据分析_时间维度对比及变化可视化分析(Pandas和Matplotlib) 分析维度包括: 各年度合计销量 各年度合计销售额 各年度平均每公斤销售额 各月度销量对比 各月度销售额变化 构建测试数据 这里你可以了解到: 如何生成时间相关的数据。 如何从列表&#xff08;可迭代对象…

Linux多进程(二)进程通信方式一 管道

管道的是进程间通信&#xff08;IPC - InterProcess Communication&#xff09;的一种方式&#xff0c;管道的本质其实就是内核中的一块内存(或者叫内核缓冲区)&#xff0c;这块缓冲区中的数据存储在一个环形队列中&#xff0c;因为管道在内核里边&#xff0c;因此我们不能直接…

Vue 双向绑定、diff和nextTick原理

前言 什么是虚拟dom virtual DOM 虚拟DOM&#xff0c;用普通js对象来描述DOM结构&#xff0c;因为不是真实DOM&#xff0c;所以称之为虚拟DOM。 虚拟 dom 是相对于浏览器所渲染出来的真实 dom而言的&#xff0c;在react&#xff0c;vue等技术出现之前&#xff0c;我们要改变页面…

LabVIEW专栏八、类

该章目的是可以开发仪器类。 一、类的概述 一般来说类有三大特性&#xff0c;封装&#xff0c;继承和多态。 在实际项目中&#xff0c;最主要是继承和多态&#xff0c;要搞清楚这两者的概念和在LabVIEW中是怎样应用的。在LabVIEW中&#xff0c;面向对象编程用到的就是LabVIE…

SAM在低阶自适应航空土地覆盖分类中的应用2024.01

GEOSCIENCE AND REMOTE SENSING LETTERS 2024.01 提出了一种新的语义分割模型&#xff0c;该模型结合了SAM的图像编码器和低秩自适应方法(LoRA)&#xff0c;用于航空图像的特征提取和微调。我们还使用了一个辅助CNN编码器来促进下游适应&#xff0c;并补充ViT编码器在密集视觉…

机器学习模型效果不好及其解决办法

当训练出来的机器学习模型效果不佳时&#xff0c;可能涉及多个方面的原因。为了改善模型的效果&#xff0c;需要系统地检查和分析问题的根源&#xff0c;并采取相应的措施进行优化。 一、数据问题 数据质量 检查数据是否干净、完整&#xff0c;是否存在噪声、异常值或缺失值。…

【MySQL】A01、性能优化-语句分析

1、数据库优化方向 A、SQL及索引优化 根据需求写出良好的SQL&#xff0c;并创建有效的索引&#xff0c;实现某一种需求可以多种写法&#xff0c;这时候我们就要选择一种效率最高的写法。这个时候就要了解sql优化 B、数据库表结构优化 根据数据库的范式&#xff0c;设计表结构&…

从C向C++14——STL初识及函数对象

一.STL初识 1.STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西C的面向对象和泛型编程思想&#xff0c;目的就是复用性的提升多情况下&#xff0c;数据结构和算法都未能有一套标准,导致被迫从事大量重复工作为了建立数据结构和算法的一套标准,诞生了ST…

详解汽车充电桩主板的硬件设计与软件系统

随着电动汽车时代的到来&#xff0c;充电桩逐渐成为城市新地标。而在每一个充电桩的核心&#xff0c;隐藏着一颗强大的“心脏”——充电桩主板。 充电桩主板是充电桩的核心部件&#xff0c;决定着充电桩的充电效率、安全和用户体验。今天&#xff0c;我们将深入探索汽车充电桩主…

分布式版本控制工具 Git 的使用方式

文章目录 Git简介下载安装基本使用起始配置Git 的三个区域基本操作流程查看仓库状态删除&#xff08;撤销暂存区&#xff09;差异对比查看版本日志版本回退修改提交日志分支概念&#xff1a;创建分支与切换分支合并分支&#xff08;快速合并&#xff09;合并分支&#xff08;提…