一起学SF框架系列5.7-模块Beans-BeanDefinition使用

news2024/11/24 2:36:43

SF如何使用BeanDefinition达成其目标IoC,我们通过跟踪BeanDefinition使用来了解。

使用起点

跟踪SF初始化过程,第一个点在:DefaultListableBeanFactory.preInstantiateSingletons。如下图:
在这里插入图片描述
RootBeanDefinition是运行时Spring BeanFactory使用的bean定义,可能是由多个相互继承的原始BeanDefinition(从配置元数据中解析生成的)合并创建而来。本质上可RootBeanDefinition当做运行时的“统一”bean定义视图。
注:此处生成bd(RootBeanDefinition)并没有传入到方法getBean(beanName),是因为第一次生成后就缓存在beanFactory,下次直接从缓存获得即可。

类-RootBeanDefinition

RootBeanDefinition继承于AbstractBeanDefinition,主要增强或限制:
1、不能有继承(都被合并):setParentName总是null;
2、确定bean解析器,包括注解、反射类型、class、工厂方法和supplier;
3、管理外部管理器:Member、初始化方法和销毁方法等;

@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
	//省略属性及11种构建函数

	/* ParentName操作:ParentName必须为空(所有的继承类都合并成一个bean,这是RootBeanDefinition 的本质) */
	@Override
	public String getParentName() {
		return null;
	}
	@Override
	public void setParentName(@Nullable String parentName) {
		if (parentName != null) {
			throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
		}
	}

	/* BeanDefinitionHolder(bean id、alias与BeanDefinition对应关系)操作*/
	public void setDecoratedDefinition(@Nullable BeanDefinitionHolder decoratedDefinition) {
		this.decoratedDefinition = decoratedDefinition;
	}
	@Nullable
	public BeanDefinitionHolder getDecoratedDefinition() {
		return this.decoratedDefinition;
	}

	/* bean的注解元素(含bean的所有注解)操作 */
	public void setQualifiedElement(@Nullable AnnotatedElement qualifiedElement) {
		this.qualifiedElement = qualifiedElement;
	}
	@Nullable
	public AnnotatedElement getQualifiedElement() {
		return this.qualifiedElement;
	}

	/** bean对应的解析类操作 
	解析类可以是ResolvableType 或者Class
	ResolvableType:是Java.lang.reflect.Type的封装,最终将beanDefinition解析到对应Class的能力
	Class:bean直接对应的Class
	*/
	public void setTargetType(@Nullable ResolvableType targetType) {
		this.targetType = targetType;
	}
	public void setTargetType(@Nullable Class<?> targetType) {
		this.targetType = (targetType != null ? ResolvableType.forClass(targetType) : null);
	}
	@Nullable
	public Class<?> getTargetType() {
		if (this.resolvedTargetType != null) {
			return this.resolvedTargetType;
		}
		ResolvableType targetType = this.targetType;
		return (targetType != null ? targetType.resolve() : null);
	}
	@Override
	public ResolvableType getResolvableType() {
		ResolvableType targetType = this.targetType;
		if (targetType != null) {
			return targetType;
		}
		ResolvableType returnType = this.factoryMethodReturnType;
		if (returnType != null) {
			return returnType;
		}
		Method factoryMethod = this.factoryMethodToIntrospect;
		if (factoryMethod != null) {
			return ResolvableType.forMethodReturnType(factoryMethod);
		}
		return super.getResolvableType();
	}

	/* 获得用于默认构造的首选构造函数(可以是多个)。如有必要,构造函数参数可以自动注入 */
	@Nullable
	public Constructor<?>[] getPreferredConstructors() {
		return null;
	}

	/* 设置非重载方法工厂方法名称*/
	public void setUniqueFactoryMethodName(String name) {
		Assert.hasText(name, "Factory method name must not be empty");
		setFactoryMethodName(name);
		this.isFactoryMethodUnique = true;
	}
	/* 设置重载方法工厂方法名称 */
	public void setNonUniqueFactoryMethodName(String name) {
		Assert.hasText(name, "Factory method name must not be empty");
		setFactoryMethodName(name);
		this.isFactoryMethodUnique = false;
	}
	/* 判定是否是工厂方法 */
	public boolean isFactoryMethod(Method candidate) {
		return candidate.getName().equals(getFactoryMethodName());
	}
	/* 设置工厂方法的解析方法器(Java Method)  */
	public void setResolvedFactoryMethod(@Nullable Method method) {
		this.factoryMethodToIntrospect = method;
		if (method != null) {
			setUniqueFactoryMethodName(method.getName());
		}
	}
	/* 获取工厂方法的解析方法器(Java Method)  */
	@Nullable
	public Method getResolvedFactoryMethod() {
		return this.factoryMethodToIntrospect;
	}

	/* 设置bean的实例生产者 */
	@Override
	public void setInstanceSupplier(@Nullable Supplier<?> supplier) {
		super.setInstanceSupplier(supplier);
		Method factoryMethod = (supplier instanceof InstanceSupplier<?> instanceSupplier ?
				instanceSupplier.getFactoryMethod() : null);
		if (factoryMethod != null) {
			setResolvedFactoryMethod(factoryMethod);
		}
	}

	// 标识BeanDefinition是否已被MergedBeanDefinitionPostProcessor处理过
	public void markAsPostProcessed() {
		synchronized (this.postProcessingLock) {
			this.postProcessed = true;
		}
	}

	// 注册外部管理的Member(Member代表a field or a method or a constructor)
	public void registerExternallyManagedConfigMember(Member configMember) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedConfigMembers == null) {
				this.externallyManagedConfigMembers = new LinkedHashSet<>(1);
			}
			this.externallyManagedConfigMembers.add(configMember);
		}
	}
	// 判断是否外部管理Member
	public boolean isExternallyManagedConfigMember(Member configMember) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedConfigMembers != null &&
					this.externallyManagedConfigMembers.contains(configMember));
		}
	}
	// 获得外部管理Set<Member>
	public Set<Member> getExternallyManagedConfigMembers() {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedConfigMembers != null ?
					Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedConfigMembers)) :
					Collections.emptySet());
		}
	}

	// 注册外部管理的初始化方法(例如,用JSR-250的注解是用jakarta.annotation.PostConstruct初始化)
	public void registerExternallyManagedInitMethod(String initMethod) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedInitMethods == null) {
				this.externallyManagedInitMethods = new LinkedHashSet<>(1);
			}
			this.externallyManagedInitMethods.add(initMethod);
		}
	}
	// 判断是否是外部管理的初始化方法
	public boolean isExternallyManagedInitMethod(String initMethod) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedInitMethods != null &&
					this.externallyManagedInitMethods.contains(initMethod));
		}
	}
	// 判断是否是外部管理的初始化方法(忽略方法的可见性)
	boolean hasAnyExternallyManagedInitMethod(String initMethod) {
		synchronized (this.postProcessingLock) {
			if (isExternallyManagedInitMethod(initMethod)) {
				return true;
			}
			if (this.externallyManagedInitMethods != null) {
				for (String candidate : this.externallyManagedInitMethods) {
					int indexOfDot = candidate.lastIndexOf('.');
					if (indexOfDot >= 0) {
						String methodName = candidate.substring(indexOfDot + 1);
						if (methodName.equals(initMethod)) {
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	// 获得外部管理的初始化方法
	public Set<String> getExternallyManagedInitMethods() {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedInitMethods != null ?
					Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedInitMethods)) :
					Collections.emptySet());
		}
	}

	// 解析可推测的bean销毁方法
	public void resolveDestroyMethodIfNecessary() {
		setDestroyMethodNames(DisposableBeanAdapter
				.inferDestroyMethodsIfNecessary(getResolvableType().toClass(), this));
	}
	// 注册外部管理的销毁方法
	public void registerExternallyManagedDestroyMethod(String destroyMethod) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedDestroyMethods == null) {
				this.externallyManagedDestroyMethods = new LinkedHashSet<>(1);
			}
			this.externallyManagedDestroyMethods.add(destroyMethod);
		}
	}
	// 判断是否是外部管理的销毁方法
	public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedDestroyMethods != null &&
					this.externallyManagedDestroyMethods.contains(destroyMethod));
		}
	}
	// 判断是否是外部管理的销毁方法(忽略方法的可见性)
	boolean hasAnyExternallyManagedDestroyMethod(String destroyMethod) {
		synchronized (this.postProcessingLock) {
			if (isExternallyManagedDestroyMethod(destroyMethod)) {
				return true;
			}
			if (this.externallyManagedDestroyMethods != null) {
				for (String candidate : this.externallyManagedDestroyMethods) {
					int indexOfDot = candidate.lastIndexOf('.');
					if (indexOfDot >= 0) {
						String methodName = candidate.substring(indexOfDot + 1);
						if (methodName.equals(destroyMethod)) {
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	// 获得外部管理的销毁方法
	public Set<String> getExternallyManagedDestroyMethods() {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedDestroyMethods != null ?
					Collections.unmodifiableSet(new LinkedHashSet<>(this.externallyManagedDestroyMethods)) :
					Collections.emptySet());
		}
	}

	//克隆一个新的RootBeanDefinition 
	@Override
	public RootBeanDefinition cloneBeanDefinition() {
		return new RootBeanDefinition(this);
	}

	//类相等判断
	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof RootBeanDefinition && super.equals(other)));
	}

	//类串化判断
	@Override
	public String toString() {
		return "Root bean: " + super.toString();
	}
}

方法-getMergedLocalBeanDefinition(String beanName)

	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// 从缓存获取
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {
			return mbd;
		}
		// 新建RootBeanDefinition 
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

	/* 过渡类 */
	protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
	}

	/** 真正实现合并BeanDefinition(主要合并继承关系) 
	 * @param beanName:要合并的beanName
	 * @param bd:bean定义解析生成的BeanDefinition
	 * @param containingBd:对于内部类情况,包容该bean的BeanDefinition
	*/
	protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
		//同步执行
		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			// 不是内部类bean,从缓存获取一次(两次检测)
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			/* 合并处理 mbd.stale-需要合并标志 */
			if (mbd == null || mbd.stale) {
				// 处理前的mbd
				previous = mbd;
				if (bd.getParentName() == null) {
				// bd没有父级
					// Use copy of given root bean definition.
					if (bd instanceof RootBeanDefinition rootBeanDef) {
						// 如果bd已经是RootBeanDefinition,直接克隆一份
						mbd = rootBeanDef.cloneBeanDefinition();
					}
					else {
						// 用bd生成RootBeanDefinition
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
				// bd还有父级
					// Child bean definition: needs to be merged with parent.
					BeanDefinition pbd;
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
							// 有真正的父级bean,合并方式生成父级BeanDefinition (此处是递归调用,因此可以合并所有继承关系)
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							// 父级beanName同本身beanName相同,可能来自父级BeanFactory,从父级BeanFactory合并方式生成BeanDefinition 
							if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
								pbd = parent.getMergedBeanDefinition(parentBeanName);
							}
							else {
								throw new NoSuchBeanDefinitionException(parentBeanName,
										"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
												"': cannot be resolved without a ConfigurableBeanFactory parent");
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					// 以父级bean生成新RootBeanDefinition,然后用孩子bd的重写(子类有的就覆盖父类),这样就把父子合并了(因为是递归调用,因此可以合并所有继承关系)
					mbd = new RootBeanDefinition(pbd);
					mbd.overrideFrom(bd);
				}

				// Set default singleton scope, if not configured before.
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(SCOPE_SINGLETON);
				}

				// 如果是内部类,scope同包容bean的scope
				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// 非内部类进行缓存 (isCacheBeanMetadata()代表来自缓存的元数据)
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
				//处理前的mbd进行相关性处理(主要同bean解析器和工厂方法相关)
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			return mbd;
		}
	}
	private void copyRelevantMergedBeanDefinitionCaches(RootBeanDefinition previous, RootBeanDefinition mbd) {
		if (ObjectUtils.nullSafeEquals(mbd.getBeanClassName(), previous.getBeanClassName()) &&
				ObjectUtils.nullSafeEquals(mbd.getFactoryBeanName(), previous.getFactoryBeanName()) &&
				ObjectUtils.nullSafeEquals(mbd.getFactoryMethodName(), previous.getFactoryMethodName())) {
			ResolvableType targetType = mbd.targetType;
			ResolvableType previousTargetType = previous.targetType;
			if (targetType == null || targetType.equals(previousTargetType)) {
				mbd.targetType = previousTargetType;
				mbd.isFactoryBean = previous.isFactoryBean;
				mbd.resolvedTargetType = previous.resolvedTargetType;
				mbd.factoryMethodReturnType = previous.factoryMethodReturnType;
				mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect;
			}
		}
	}

创建bean实例使用

这是BeanDefinition真正作用的地方,入口在AbstractAutowireCapableBeanFactory.createBean。

创建入口

/* 创建bean实例 */
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		//获取bean定义对应的Class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			//如果mbd还没有解析Class,写回
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		try {
			// 对override方法做覆盖处理
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 实例化前处理
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 创建实例  注1
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

注1:doCreateBean创建实例方法路径:doCreateBean->createBeanInstance->instantiateBean。中间方法是针对各种情况处理,最终实际在instantiateBean中生成bean实例

AbstractAutowireCapableBeanFactory.resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>… typesToMatch)

解析RootBeanDefinition对应的Class

	// 过渡类
	@Nullable
	protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {
		try {
			if (mbd.hasBeanClass()) {
				return mbd.getBeanClass();
			}
			return doResolveBeanClass(mbd, typesToMatch);
		}
		catch (ClassNotFoundException ex) {
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
		}
		catch (LinkageError err) {
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
		}
	}
	// 解析bean的Class
	@Nullable
	private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
			throws ClassNotFoundException {

		ClassLoader beanClassLoader = getBeanClassLoader();
		ClassLoader dynamicLoader = beanClassLoader;
		boolean freshResolve = false;

		if (!ObjectUtils.isEmpty(typesToMatch)) {
			// 如果仅做类型检查(不生成bean实例),用临时ClassLoader检查处理。
			ClassLoader tempClassLoader = getTempClassLoader();
			if (tempClassLoader != null) {
				dynamicLoader = tempClassLoader;
				// freshResolve 为true,后续会进行Class解析
				freshResolve = true;
				if (tempClassLoader instanceof DecoratingClassLoader dcl) {
					for (Class<?> typeToMatch : typesToMatch) {
						dcl.excludeClass(typeToMatch.getName());
					}
				}
			}
		}

		String className = mbd.getBeanClassName();
		if (className != null) {
			//className用表达式方式进行解析,解析出同mbd相关的class
			Object evaluated = evaluateBeanDefinitionString(className, mbd);
			if (!className.equals(evaluated)) {
				/* 解析结果同className不一样 */
				if (evaluated instanceof Class<?> clazz) {
					// 解析出的是Class
					return clazz;
				}
				else if (evaluated instanceof String name) {
					// 解析出的是String
					className = name;
					freshResolve = true;
				}
				else {
					throw new IllegalStateException("Invalid class name expression result: " + evaluated);
				}
			}
			if (freshResolve) {
				if (dynamicLoader != null) {
					try {
						//用动态加载器加载className对应的Class
						return dynamicLoader.loadClass(className);
					}
					catch (ClassNotFoundException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
						}
					}
				}
				//用spring的ClassUtils加载className对应的Class
				return ClassUtils.forName(className, dynamicLoader);
			}
		}

		// 返回null (className不为空,前面处理了;为空,该方法实际也返回null
		return mbd.resolveBeanClass(beanClassLoader);
	}

真正创建

doCreateBean创建实例方法路径:doCreateBean->createBeanInstance->instantiateBean。中间方法是针对各种情况处理,最终在instantiateBean中生成bean实例

	/** SF中,BeanWrapper是JavaBean的封装器,可提供分析和操作标准JavaBeans的操作:
	1、能够获取和设置属性值(单独或批量)
	2、获取属性描述符以及查询属性的可读性/可写性
	*/
	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			// 初始化一个bean实例 注1
			Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			// 封装bean实例
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
		}
	}

注1:SF的bean实例初始化器是CglibSubclassingInstantiationStrategy,具体如何初始化参见:一起学SF框架系列5.8-模块Beans-bean实例化跟踪

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

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

相关文章

前端白屏检测方案

早期因为浏览器、技术、兼容性等诸多问题&#xff0c;导致网页的显示效果非常的单一&#xff0c;基本都是静态页&#xff0c;后续随着Angular、React、Vue等前端框架的出现&#xff0c;采用SPA单页面应用的方案越来越多。 用户和企业对于页面的稳定性、性能有了更高的诉求&…

openssl为什么从1.1跳跃到3.0,为什么没有2.0版本?

OpenSSL在版本号上从1.1跳跃到3.0是因为在其发展过程中发生了一些特定的情况和变化&#xff0c;导致开发团队做出了这样的决定。以下是一些可能的原因&#xff1a; 历史背景&#xff1a;OpenSSL的版本号体系并不是连续递增的&#xff0c;而是根据项目的发展和变化进行调整。在过…

UFS 15 - UFS RPMB操作

UFS 15 - UFS RPMB操作 1 Request Type Message Delivery&#xff08;请求类型消息传递&#xff09;2 Response Type Message Delivery&#xff08;响应类型消息传递&#xff09;3 Authentication Key Programming3.1 Authentication Key Programming3.2 报文示例3.2.1 Authent…

【工具使用】使用J-link离线下载芯唐MCU固件

一&#xff0c;简介 本文主要介绍如何使用J-link工具&#xff0c;离线下载M483的程序。 二&#xff0c;操作步骤 主要分为以下三个步骤&#xff1a; 1&#xff0c;使用SWD接口连接硬件&#xff1b; 2&#xff0c;配置上位机工程&#xff1b; 3&#xff0c;下载程序到芯片&am…

LiveGBS流媒体平台GB/T28181功能-作为上级平台对接海康大华华为宇视等下级平台监控摄像机NVR硬件执法仪等GB28181设备

LiveGBS作为上级平台对接海康大华华为宇视等下级平台监控摄像机NVR硬件执法仪等GB28181设备 1、背景说明2、部署国标平台2.1、安装使用说明2.2、服务器网络环境2.3、信令服务配置 3、监控摄像头设备接入3.1、海康GB28181接入示例3.2、大华GB28181接入示例3.3、华为IPC GB28181接…

图像处理之比特平面分层和重构

一、比特平面分层 像素是由比特组成的数字。例如在256级灰度图像中&#xff0c;每个像素的灰度是由8比特&#xff08;一个字节&#xff09;组成。如下图所示&#xff0c;一幅8比特图像由8个1比特平面组成&#xff0c;其中平面1包含图像中所有像素的最低阶比特&#xff0c;而平…

Linux开发工具gdb篇

文章目录 &#x1f3bb;0.前言&#x1f3bc;debug版本&#x1f3bc;release版本 &#x1fa95;1. gcc/g的默认版本&#x1f3b8;2. gdb使用&#x1f3b5;进入 & 退出&#x1f3b5;查看代码&#x1f3b5;断点 & 跳断点&#x1f3b5;逐过程 & 逐语句&#x1f3b5;监视…

Spring Boot 核心运行原理介绍

Spring Boot 核心运行原理介绍 引言整体介绍1. 核心运行原理图2. 自动配置的整体流程3. 各核心功能和组件初步介绍 总结 引言 还记得&#xff0c;笔者在前面的博文《Spring Boot 项目介绍》中提到了&#xff0c;Spring Boot 最核心的功能就是自动配置&#xff0c;该功能的实现…

编辑距离算法(Levenshtein Distance Algorithm)的概念理解及其应用

概念&#xff1a; 编辑距离&#xff0c;由俄罗斯科学家Vladimir Levenshtein于1965年提出&#xff0c;因此又称为Levenshtein Distance&#xff0c;简称LD&#xff0c;是指两个字串之间&#xff0c;由一个转成另一个所需的最少编辑操作次数。 可用的编辑操作包括&#xff1a;…

使用docker的常见bug

BUG1&#xff1a;磁盘被占满导致docker无法使用 docker ps 【查看docker能否正常使用】 正常的话会打印下图信息: 不正常的话打印如下图信息&#xff1a; journalctl -u docker 【查看docker无法正常使用的原因】&#xff0c;本次测试中遇到下图bug&#xff0c;意思是/var/l…

短视频抖音seo矩阵源码saas--技术开发部署分享

抖音seo源码开发&#xff0c;抖音矩阵源码&#xff0c;短视频seo源码&#xff0c;短视频矩阵源码技术开发部署&#xff0c;模式采用SaaS形式&#xff0c;用户角色分为&#xff1a;总后台&#xff0c;加盟商&#xff0c;企业用户&#xff0c;角色权限划分清楚&#xff0c;多模式…

简单认识MySQL基础部分

文章目录 一、数据库概述1、简介2、数据库类型和常用数据库1.关系型数据库2.非关系型数据库 3、mysql数据库日志1、作用&#xff1a;2、 mysql与 oracle 日志有所区别3、 Mysql 存储引擎 二、数据库基础操作1、SQL 语句2、实际操作1、DDL&#xff1a;数据定义语言&#xff0c;用…

机器学习技术(五)——特征工程与模型评估

机器学习技术&#xff08;五&#xff09;——特征工程与模型评估(2️⃣) 文章目录 机器学习技术&#xff08;五&#xff09;——特征工程与模型评估(:two:)二、模型评估1、Accuracy score2、Confusion matrix混淆矩阵1、多值2、二值 3、Hamming loss4、Precision, recall and F…

石英灯和石墨加热器结构热试验装置中的低气压控制解决方案

摘要&#xff1a;为解决结构热试验和热真空试验中的低气压真空压力精密控制问题&#xff0c;本文基于动态平衡法和上下游控制模式&#xff0c;提供了相应的解决方案。解决方案中的低气压真空压力控制系统主要是采用电控针阀、电控球阀和双通道真空压力控制器组成上下游两个闭环…

从源码角度看 Golang 的调度

1.简单概念 1.1 调度器的三个抽象概念&#xff1a;G、M、P G&#xff1a;代表一个 goroutine&#xff0c;每个 goroutine 都有自己独立的栈存放当前的运行内存及状态。可以把一个 G 当做一个任务。M: 代表内核线程(Pthread)&#xff0c;它本身就与一个内核线程进行绑定&#…

echarts条形图动态显示

1、实现效果 每次展示5个&#xff0c;轮流展示 2、实现思路 使用datazoom,一次展示5项数据&#xff0c;轮流展示每2s刷新一次。 条形图有两个柱子&#xff0c;一个蓝色柱子&#xff0c;一个灰色柱子&#xff0c;两个柱子重合&#xff0c;且蓝柱子在上面。 为了使左侧的类目和柱…

【ubuntu重装系统后的软件配置_memo】

重装系统后系统环境恢复 备份安装系统常用的一些debvscode 更改sourcespip加速爬长城的家伙式儿安装ROS安装cmake安装git安装zsh顺便开个ssh提升幸福感的映射配置neovimplugins字体插件遇到的问题 锁键盘/鼠标小玩意儿 备份 实验时不起眼的图顺手写的脚本忘记从哪儿下载的资源…

华为云命令行工具服务KooCLI助力一键管理云资源

对于CLI即命令行工具&#xff0c;运维同学可能并不陌生&#xff0c;它摒弃了对图形化界面的需求&#xff0c;不再拘泥于可视化的页面切换、按钮点击等操作&#xff0c;反而为用户提供了一个便捷且高控制的解决方案&#xff0c;使用户在日常的运维工作中&#xff0c;用一行命令即…

【深度学习】目标检测的全面回顾

一、说明 随着自动驾驶汽车、智能视频监控、面部检测和各种人数统计应用的兴起&#xff0c;对快速准确的物体检测系统的需求也在不断增长。这些系统不仅涉及识别和分类图像中的每个对象&#xff0c;还涉及通过在图像周围绘制适当的边界框来定位每个对象。这使得对象检测比其传统…

凸包检测、直线检测、点集拟合、二维码检测

目录 1、凸包检测 2、直线检测 3、点集拟合 4、二维码检测 1、凸包检测 //凸包检测 int test1() {Mat img imread("F:/testMap/hand.png");if (img.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}// 二值化Mat gray,…