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

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.mfbz.cn/a/38187.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(16)燃油流量和液位传感器

文章目录 前言 16.1 燃油流量传感器 16.1.1 连接到自动驾驶仪 16.2 燃油液位传感器 16.2.1 PWM油位传感器 16.2.2 模拟油位传感器 前言 在 4.0 及以后的固件版本中&#xff0c;ArduPilot 提供了使用燃油流量和液位传感器的能力&#xff0c;此外还有电池监控器。支持脉冲输…

安装Ceph集群

安装Ceph集群 环境准备 CentOS 7.6 主机名IPRoleadmin192.168.182.128adminnode1192.168.182.129mon/mgr/osdnode2192.168.182.130osdnode3192.168.182.131osdclient192.168.182.132 所有节点修改主机名相互解析三台node节点添加大小5G以上硬盘关闭所有节点防火墙与SeLinux所…

jenkins 关闭关闭CSRF Protection(跨站请求伪造保护)

jenkins版本 我的jenkins版本是&#xff1a;2.332.4 背景 Jenkins版本自2.204.6以来的重大变更有&#xff1a;删除禁用 CSRF 保护的功能。 从较旧版本的 Jenkins 升级的实例将启用 CSRF 保护和设置默认的发行者&#xff0c;如果之前被禁用。 解决方法 老版本Jenkins的CSRF…

亚马逊云科技,迈向十年新进阶

编辑&#xff1a;阿冒 设计&#xff1a;沐由 自2013年进入国内至今&#xff0c;亚马逊云科技见证了中国数字经济开启量质齐升的十年。在这十年里&#xff0c;亚马逊云科技持续不断地帮助广大中国企业实现上云重塑和云上创新。 从一间公司的时间节点而言&#xff0c;无论是中文的…

mac批量修改文件名为不同名字

mac批量修改文件名为不同名字怎么弄&#xff1f;很多小伙伴通过私信向我求助&#xff0c;用什么方法可以在mac电脑上批量修改文件名称&#xff0c;将大量文件修改成不同的名称。这可能是一项比较麻烦的操作&#xff0c;在电脑上进行过批量重命名的小伙伴都知道&#xff0c;一般…

达梦sql执行计划、HINT、索引简单应用

目录 收集统计信息. 3 1. 通过DBMS_STATS包中的方法. 3 2、删除指定表的统计信息. 3 执行计划. 3 常用执行计划操作符. 4 统计指定sql执行号的所有操作符的执行时间. 5 HINT 5 并行操作&#xff1a;. 6 查询计划重用、结果集重用. 7 示例. 8 1、收集统计信息&#x…

上手vue2的学习笔记5之在vue2项目中调用elment-ui

前言 上手vue2的学习笔记4之搭建vue环境 参考链接&#xff1a;vue2.0项目引入element-ui 一、安装elment-ui 进入搭建的vue项目中 cd vue_bing_test 安装 element npm i element-ui二、引入elment-ui elment官方教程 将main.js改成如下内容&#xff1a; import Vue fro…

Proxy代理前后,Httpheader 的变化

Vite.config 配置Proxy服务器, 解决Rest API 访问SpringBoot接口时&#xff0c;跨域的Session一致性。 import { defineConfig, loadEnv } from viteexport default defineConfig({server: {proxy: {/rest: {target: loadEnv(, process.cwd()).VITE_API_URL,changeOrigin: tru…

argparse 模块参数

官方文档&#xff1a;https://docs.python.org/3.7/library/argparse.html 示例 def parse_config():parser argparse.ArgumentParser(descriptionarg parser) # 创建一个 ​​ArgumentParser​​ 对象(parser)parser.add_argument(--cfg_file, typestr, defaultNone, hel…

[相遇 Bug] - ImportError: numpy.core.multiarray failed to import

背景: 因为最近在看点云模型, 在自己的环境上部署该项目: https://github.com/open-mmlab/OpenPCDet/tree/master 执行命令: 这里执行github项目给的demo.py文件, 命令格式如下: python demo.py --cfg_file cfgs/kitti_models/pointpillar.yaml --ckpt xxx/pointpillar_772…

WPF Prims框架详解

文章目录 前言Prism基本使用Prism选择&#xff0c;DryIoc还是UnityPrism基本框架搭建Prism动态更新View和ViewModel对应关系参数动态更新函数动态绑定 prism新建项目模板region使用事例测试是否限制空间 消息订阅如何使用消息订阅使用建议 路由导航对话框/弹窗功能实现代码 前言…

Element分页组件自定义样式

样式效果 页面代码 <el-paginationsize-change"handleSizeChange"current-change"handleCurrentChange":current-page"page.page":page-sizes"[10, 20, 30, 40]":page-size"page.size"layout"total, sizes, prev, …

HTML <map> 标签

实例 带有可点击区域的图像映射: <img src="planets.jpg" border="0" usemap="#planetmap" alt="Planets" /><map name="planetmap" id="planetmap"><area shape="circle" coords=&q…

Spring Boot 中的 @Field 注解详解

Spring Boot 中的 Field 注解详解 引言 Spring Boot 是目前 Java 生态圈中最受欢迎的 Web 应用开发框架之一&#xff0c;它提供了很多优秀的功能和工具&#xff0c;可以帮助开发者快速构建高效、可靠的 Web 应用程序。其中一个重要的功能就是数据绑定和验证&#xff0c;Sprin…

(阿里云)STM32L+BC20+MQTT协议传输温湿度,ADC,电压,GPS数据到阿里云物联网平台

1、材料准备 准备以下材料 2、设备连接 2.1 插入物联网卡 首先把BC20核心板从开发板上拆下来 然后将物联卡放置在BC20核心板内 物联卡放置完成将BC20核心板重新插入到开发板内&#xff08;注意不要弄错方向&#xff09; 同时接入天线 2.2 连接ST-Link仿真器 用3条杜邦线接…

DP485替代MAX485 RS485/RS422 收发器芯片

DP485E 是一款 5V 供电、半双工、低功耗、低摆率&#xff0c;完全满足 TIA/EIA-485 标准要求的 RS-485收发器。DP485E 工作电压范围为 4.75~5.25V&#xff0c;具备失效安全&#xff08;fail-safe&#xff09;、过温保护、限流保护、过压保护&#xff0c;控制端口热插拔输入等功…

飞行动力学 - 第10节-空间机动性、稳定性与操纵性概述 之 基础点摘要

飞行动力学 - 第10节-空间机动性、稳定性与操纵性概述 之 基础点摘要 1. 协调盘旋性能计算流程2. 一般盘旋2.1 动力学方程2.2 角点速度2.3 典型战斗机盘旋曲线 3. 空间机动能力4. 飞行动力学&#xff1a;飞行性能稳定性与操纵性5. 稳定性定义6. 飞行品质6.1 品质等级6.2 品质评…

从字节出来的测试总监,让我们用这份《测试用例规范》,再也没加班过。

经常看到无论是刚入职场的新人&#xff0c;还是工作了一段时间的老人&#xff0c;都会对编写测试用例感到困扰&#xff1f;例如&#xff1a; 固然&#xff0c;编写一份好的测试用例需要&#xff1a;充分的需求分析能力 理论及经验加持&#xff0c;作为测试职场摸爬打滚的老人&…

数据科学分析全流程步骤

知识图谱以结构化的“知识”来存储与表示海量数据&#xff0c;作为承载底层海量知识并支持上层智能应用的重要载体&#xff0c;它在智能时代中扮演了极其重要的角色。然而&#xff0c;由于知识图谱高度结构化的特点&#xff0c;我们常常需要构建结构化查询语句&#xff08;SPAR…

使用 jmeter 进行审批类接口并发测试

目录 前言&#xff1a; 背景&#xff1a; 难点&#xff1a; 场景 a&#xff1a; 场景 b&#xff1a; 前言&#xff1a; 使用JMeter进行审批类接口的并发测试是一种有效的方法&#xff0c;可以模拟多个用户同时对接口进行审批操作&#xff0c;以评估系统在高负载情况下的性…
最新文章