【Spring - beans】 BeanDefinition 源码

news2024/10/5 15:30:44

目录

1. BeanDefinition

1.1 AbstractBeanDefinition

1.2 RootBeanDefinition

1.3 ChildBeanDefinition

1.4 GenericBeanDefinition

2. BeanDefinitionReader

2.1 AbstractBeanDefinitionReader

2.2 XmlBeanDefinitionReader

2.3 GroovyBeanDefinitionReader

2.4 PropertiesBeanDefinitionReader

3. BeanDefinitionRegistry

3.1 SimpleBeanDefinitionRegistry 

3.2 DefaultListableBeanFactory

3.3 GenericApplicationContext


1. BeanDefinition

BeanDefinition 描述了一个 bean 的相关信息,比如 作用域、是否懒加载、依赖 bean 等。

BeanDefinition 告诉 Spring 如何创建 Bean。

类图

1.1 AbstractBeanDefinition

顶层接口的抽象实现类,完成了大部分基本功能。

1.2 RootBeanDefinition

RootBeanDefinition 表示一个 根 bean definition ,可作为其他 bean definition 的父类。

1.3 ChildBeanDefinition

不可以单独存在,在构造的时候就得传一个父 bean definition。

1.4 GenericBeanDefinition

通用 bean definition,可作为 子 bean definiton,也可作为 父 bean definition。

为什么 bean definition 存在父子关系?

主要用于合并功能:将父 bean definition 中的信息 和 子 bean definition 的信息 合在一起给 子 bean definition。

主要实现原理是:先拷贝父类全部属性,然后将子类的值设置上去。

2. BeanDefinitionReader

BeanDefinition 从哪里来呢,就由 BeanDefinitionReader 来读出来。

以下是该接口定义的方法,主要方法就是 loadBeanDefinition ,用来加载、读取 beanDefinition

public interface BeanDefinitionReader {

	/**
	 * 返回用于注册 beanDefinition 的 BeanDefinitionRegistry
	 */
	BeanDefinitionRegistry getRegistry();

	/**
	 * 返回资源加载器
	 */
	ResourceLoader getResourceLoader();

	/**
	 * 返回 bean 类加载器
	 */
	ClassLoader getBeanClassLoader();

	/**
	 * 返回 bean name 生成器
	 */
	BeanNameGenerator getBeanNameGenerator();

	/**
	 * 从指定的资源 加载 bean definitions
	 */
	int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

	/**
	 * 从指定的资源 加载 bean definitions
	 */
	int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

	/**
	 * 从指定的资源路径 加载 bean definitions
	 */
	int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

	/**
	 * 从指定的资源路径 加载 bean definitions
	 */
	int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}

类图

2.1 AbstractBeanDefinitionReader

实现通用的基本功能

2.2 XmlBeanDefinitionReader

读取 xml 配置的 bean defintion。

现在查看关键方法 loadBeanDefinitions 的源码。 

首先做了些资源的前置准备操作,然后调用到了 doLoadBeanDefinitions 来处理。

/**
 * 实际的从指定的 XML file 加载 bean definition
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
            
        // 省略部分代码
	
        // 1. 加载文档
        Document doc = doLoadDocument(inputSource, resource);

        // 2. 注册 bean definition
    	int count = registerBeanDefinitions(doc, resource);
		
	    return count;

    }    
}
 

1. doLoadDocument加载文档  doLoadDocument

// 简化代码

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
	return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
			getValidationModeForResource(resource), isNamespaceAware());
}


public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
		ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
	DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);

	DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
	return builder.parse(inputSource);
}

2. registerBeanDefinitions 注册 bean definition

上一步得到了 Document 对象,下来开始对 Document 进行读取、解析、注册 bean definition

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}


public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	doRegisterBeanDefinitions(doc.getDocumentElement());
}



protected void doRegisterBeanDefinitions(Element root) {
	// 简化代码
	parseBeanDefinitions(root, this.delegate);
}


protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 简化代码
    delegate.parseCustomElement(root);
}

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	// 简化代码
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}



public final BeanDefinition parse(Element element, ParserContext parserContext) {
	AbstractBeanDefinition definition = parseInternal(element, parserContext);
	if (definition != null && !parserContext.isNested()) {
		try {
			String id = resolveId(element, definition, parserContext);
			if (!StringUtils.hasText(id)) {
			String[] aliases = null;
			if (shouldParseNameAsAliases()) {
				String name = element.getAttribute(NAME_ATTRIBUTE);
				if (StringUtils.hasLength(name)) {
					aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
				}
			}
			BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);

            // 注册 bean definition
			registerBeanDefinition(holder, parserContext.getRegistry());


			if (shouldFireEvents()) {
				BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
				postProcessComponentDefinition(componentDefinition);
				parserContext.registerComponent(componentDefinition);
			}
		}
		catch (BeanDefinitionStoreException ex) {
			String msg = ex.getMessage();
			parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
			return null;
		}
	}
	return definition;
}

2.3 GroovyBeanDefinitionReader

GroovyBeanDefinitionReader 代表从 groovy 文件读取 bean definition

文件语法示例

  import org.hibernate.SessionFactory
  import org.apache.commons.dbcp.BasicDataSource
 
  def reader = new GroovyBeanDefinitionReader(myApplicationContext)
  reader.beans {
      dataSource(BasicDataSource) {                  // <--- invokeMethod
          driverClassName = "org.hsqldb.jdbcDriver"
          url = "jdbc:hsqldb:mem:grailsDB"
          username = "sa"                            // <-- setProperty
          password = ""
          settings = [mynew:"setting"]
      }
      sessionFactory(SessionFactory) {
          dataSource = dataSource                    // <-- getProperty for retrieving references
      }
      myService(MyService) {
          nestedBean = { AnotherBean bean ->         // <-- setProperty with closure for nested bean
              dataSource = dataSource
          }
      }
  }

loadBeanDefinitions 方法源码

// 简化代码

public int loadBeanDefinitions(EncodedResource encodedResource) {	
	
	Closure<Object> beans = new Closure<>(this) {
		@Override
		public Object call(Object... args) {
			invokeBeanDefiningClosure((Closure<?>) args[0]);
			return null;
		}
	};

	Binding binding = new Binding() {
		@Override
		public void setVariable(String name, Object value) {
			if (currentBeanDefinition != null) {
				applyPropertyToBeanDefinition(name, value);
			}
			else {
				super.setVariable(name, value);
			}
		}
	};
	binding.setVariable("beans", beans);
	int countBefore = getRegistry().getBeanDefinitionCount();
    
    // groovy 解析
    GroovyShell shell = new GroovyShell(getBeanClassLoader(), binding);
	shell.evaluate(encodedResource.getReader(), "beans");


	int count = getRegistry().getBeanDefinitionCount() - countBefore;
	return count;
}


// grovvy 解析回调
@Override
public Object invokeMethod(String name, Object arg) {
	Object[] args = (Object[])arg;
	if ("beans".equals(name) && args.length == 1 && args[0] instanceof Closure<?> closure) {
		return beans(closure);
	}
	else if ("ref".equals(name)) {
		String refName;
		if (args[0] == null) {
			throw new IllegalArgumentException("Argument to ref() is not a valid bean or was not found");
		}
		if (args[0] instanceof RuntimeBeanReference runtimeBeanReference) {
			refName = runtimeBeanReference.getBeanName();
		}
		else {
			refName = args[0].toString();
		}
		boolean parentRef = false;
		if (args.length > 1 && args[1] instanceof Boolean bool) {
			parentRef = bool;
		}
		return new RuntimeBeanReference(refName, parentRef);
	}
	else if (this.namespaces.containsKey(name) && args.length > 0 && args[0] instanceof Closure) {
		GroovyDynamicElementReader reader = createDynamicElementReader(name);
		reader.invokeMethod("doCall", args);
	}
	else if (args.length > 0 && args[0] instanceof Closure) {
		// abstract bean definition
		return invokeBeanDefiningMethod(name, args);
	}
	else if (args.length > 0 &&
			(args[0] instanceof Class || args[0] instanceof RuntimeBeanReference || args[0] instanceof Map)) {
		return invokeBeanDefiningMethod(name, args);
	}
	else if (args.length > 1 && args[args.length -1] instanceof Closure) {
		return invokeBeanDefiningMethod(name, args);
	}
	MetaClass mc = DefaultGroovyMethods.getMetaClass(getRegistry());
	if (!mc.respondsTo(getRegistry(), name, args).isEmpty()){
		return mc.invokeMethod(getRegistry(), name, args);
	}
	return this;
}

在 invokeBeanDefiningMethod 最后 注册了 bean definition

private GroovyBeanDefinitionWrapper invokeBeanDefiningMethod(String beanName, Object[] args) {
	boolean hasClosureArgument = (args[args.length - 1] instanceof Closure);
	if (args[0] instanceof Class<?> beanClass) {
		if (hasClosureArgument) {
			if (args.length - 1 != 1) {
				this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
						beanName, beanClass, resolveConstructorArguments(args, 1, args.length - 1));
			}
			else {
				this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, beanClass);
			}
		}
		else  {
			this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(
					beanName, beanClass, resolveConstructorArguments(args, 1, args.length));
		}
	}
	else if (args[0] instanceof RuntimeBeanReference runtimeBeanReference) {
		this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
		this.currentBeanDefinition.getBeanDefinition().setFactoryBeanName(runtimeBeanReference.getBeanName());
	}
	else if (args[0] instanceof Map<?, ?> namedArgs) {
		// named constructor arguments
		if (args.length > 1 && args[1] instanceof Class<?> clazz) {
			List<Object> constructorArgs =
					resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
			this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, clazz, constructorArgs);
			for (Map.Entry<?, ?> entity : namedArgs.entrySet()) {
				String propName = (String) entity.getKey();
				setProperty(propName, entity.getValue());
			}
		}
		// factory method syntax
		else {
			this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
			// First arg is the map containing factoryBean : factoryMethod
			Map.Entry<?, ?> factoryBeanEntry = namedArgs.entrySet().iterator().next();
			// If we have a closure body, that will be the last argument.
			// In between are the constructor args
			int constructorArgsTest = (hasClosureArgument ? 2 : 1);
			// If we have more than this number of args, we have constructor args
			if (args.length > constructorArgsTest){
				// factory-method requires args
				int endOfConstructArgs = (hasClosureArgument ? args.length - 1 : args.length);
				this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null,
						resolveConstructorArguments(args, 1, endOfConstructArgs));
			}
			else {
				this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
			}
			this.currentBeanDefinition.getBeanDefinition().setFactoryBeanName(factoryBeanEntry.getKey().toString());
			this.currentBeanDefinition.getBeanDefinition().setFactoryMethodName(factoryBeanEntry.getValue().toString());
		}
	}
	else if (args[0] instanceof Closure) {
		this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName);
		this.currentBeanDefinition.getBeanDefinition().setAbstract(true);
	}
	else {
		List<Object> constructorArgs =
				resolveConstructorArguments(args, 0, hasClosureArgument ? args.length - 1 : args.length);
		this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, null, constructorArgs);
	}
	if (hasClosureArgument) {
		Closure<?> callable = (Closure<?>) args[args.length - 1];
		callable.setDelegate(this);
		callable.setResolveStrategy(Closure.DELEGATE_FIRST);
		callable.call(this.currentBeanDefinition);
	}
	GroovyBeanDefinitionWrapper beanDefinition = this.currentBeanDefinition;
	this.currentBeanDefinition = null;
	beanDefinition.getBeanDefinition().setAttribute(GroovyBeanDefinitionWrapper.class.getName(), beanDefinition);


	// 注册 bean definition
	getRegistry().registerBeanDefinition(beanName, beanDefinition.getBeanDefinition());
	return beanDefinition;
}

2.4 PropertiesBeanDefinitionReader

PropertiesBeanDefinitionReader 代表从 properties 文件读取 bean definition

文件语法示例

  employee.(class)=MyClass       // bean is of class MyClass
  employee.(abstract)=true       // this bean can't be instantiated directly
  employee.group=Insurance       // real property
  employee.usesDialUp=false      // real property (potentially overridden)
 
  salesrep.(parent)=employee     // derives from "employee" bean definition
  salesrep.(lazy-init)=true      // lazily initialize this singleton bean
  salesrep.manager(ref)=tony     // reference to another bean
  salesrep.department=Sales      // real property
 
  techie.(parent)=employee       // derives from "employee" bean definition
  techie.(scope)=prototype       // bean is a prototype (not a shared instance)
  techie.manager(ref)=jeff       // reference to another bean
  techie.department=Engineering  // real property
  techie.usesDialUp=true         // real property (overriding parent value)
 
  ceo.$0(ref)=secretary          // inject 'secretary' bean as 0th constructor arg
  ceo.$1=1000000                 // inject value '1000000' at 1st constructor arg

loadBeanDefinitions 源码

这个源码就简单了,直接将文件流加载到 properties 里,然后进行注册 bean definition

// 简化代码

public int loadBeanDefinitions(EncodedResource encodedResource, @Nullable String prefix) {
	Properties props = new Properties();
	  // 获取到文件的 inputStream	
    try (InputStream is = encodedResource.getResource().getInputStream()) {
			if (encodedResource.getEncoding() != null) {
                // 将流 加载到 Properties 对象里
				getPropertiesPersister().load(props, new InputStreamReader(is, encodedResource.getEncoding()));
			}
			else {
                // 将流 加载到 Properties 对象里
				getPropertiesPersister().load(props, is);
			}
		}

        // 注册 bean definition
		int count = registerBeanDefinitions(props, prefix, encodedResource.getResource().getDescription());
		
		return count;
	}
}

3. BeanDefinitionRegistry

BeanDefinitionReader 读取到 BeanDefinition 后,就使用 BeanDefinitionRegistry 来注册 BeanDefinitionRegistry。

类图

有三个直接实现

3.1 SimpleBeanDefinitionRegistry 

简单实现(用于测试用的),看看源码如何实现的 注册 bean definition:

以下能够直观的看出,注册 bean definition、删除 bean definition 的本质就是对 map 的操作。

// 简化代码

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {


	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);


	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}

	@Override
	public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		if (this.beanDefinitionMap.remove(beanName) == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
	}

	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}

}

3.2 DefaultListableBeanFactory

真正的注册逻辑实现在这个类中

观察代码,发现和上面的 SimpleBeanDefinitionRegistry  本质差不多,都是存入 map。只不过在其基础上,增加了许多前置合法性判断功能。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");
	if (beanDefinition instanceof AbstractBeanDefinition abd) {
		try {
			abd.validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}
	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	if (existingDefinition != null) {
		if (!isAllowBeanDefinitionOverriding()) {
			// 如果不允许覆盖定义,就直接抛出异常
			throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
		}
		else if (existingDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (logger.isInfoEnabled()) {
				logger.info("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						existingDefinition + "] with [" + beanDefinition + "]");
			}
		}
		else if (!beanDefinition.equals(existingDefinition)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		
		// 覆盖定义
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	else {
		// 第一次注册该 beanName
		
		if (isAlias(beanName)) {
			// 是一个别名
			
			if (!isAllowBeanDefinitionOverriding()) {
				// 不允许覆盖定义,直接抛出异常
				String aliasedName = canonicalName(beanName);
				if (containsBeanDefinition(aliasedName)) {  // alias for existing bean definition
					throw new BeanDefinitionOverrideException(
							beanName, beanDefinition, getBeanDefinition(aliasedName));
				}
				else {  // alias pointing to non-existing bean definition
					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
							"Cannot register bean definition for bean '" + beanName +
							"' since there is already an alias for bean '" + aliasedName + "' bound.");
				}
			}
			else {
				// 删除别名
				removeAlias(beanName);
			}
		}
		if (hasBeanCreationStarted()) {
			// 工厂的 bean 创建阶段已经启动
			
			// 存在并发风险,同步放入
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				// 注册 bean
				this.beanDefinitionMap.put(beanName, beanDefinition);
				
				// 更新 beanDefinitionNames 列表:加入当前的 bean name
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				
				// 删除掉 manualSingletonNames 中的 当前 beanName
				removeManualSingletonName(beanName);
			}
		}
		else {
			// 工厂的 bean 创建阶段没启动
			
			// 没启动,不存在并发风险,直接放进去
			// Still in startup registration phase
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			removeManualSingletonName(beanName);
			
		}
		this.frozenBeanDefinitionNames = null;
	}
	if (existingDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
	else if (isConfigurationFrozen()) {
		clearByTypeCache();
	}
}

3.3 GenericApplicationContext

查看源码,注册 bean definition 其实是委托给了 DefaultListableBeanFactory。

private final DefaultListableBeanFactory beanFactory;

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
	this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}

小结

BeanDefinition 描述了一个 bean 的相关信息,比如 作用域、是否懒加载、依赖 bean 等。

BeanDefinition 告诉 Spring 如何创建 Bean。

BeanDefinition 由 BeanDefinitionReader 来读出来 使用 BeanDefinitionRegistry 注册到 BeanFactory

参考

  • BeanDefinition详解 - 知乎 (zhihu.com)
  • Spring IoC容器中核心定义之------BeanDefinition深入分析

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

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

相关文章

(跨模态)AI作画——使用stable-diffusion生成图片

AI作画——使用stable-diffusion生成图片 0. 简介1. 注册并登录huggingface2. 下载模型3. 生成 0. 简介 自从DallE问世以来&#xff0c;AI绘画越来越收到关注&#xff0c;从最初只能画出某些特征&#xff0c;到越来越逼近真实图片&#xff0c;并且可以利用prompt来指导生成图片…

软件测试面试题——数据库知识

1、要查询每个商品的入库数量&#xff0c;可以使用以下SQL语句&#xff1a; SELECT 商品编号, SUM(入库数量) AS 入库数量 FROM Stock GROUP BY 商品编号;这将从Stock表中选择每个商品的入库数量&#xff0c;并使用SUM函数对入库数量进行求和。结果将按照商品编号进行分组&…

数据宝藏与精灵法师:探秘Elf擦除魔法的奇幻故事

在数字领域的奇幻王国中&#xff0c;大家视数据为宝藏。作为奇幻王国的国王&#xff0c;在他的宝库中&#xff0c;自然是有着无数的数据宝藏。这么多的数据宝藏&#xff0c;却让国王发难了。因为宝库有限&#xff0c;放不下这么多数据宝藏。因此&#xff0c;国王广招天下的精灵…

【备战秋招】每日一题:3月18日美团春招第三题:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站&#xff08;含题解&#xff09; www.codefun2000.com 最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据&#xff0c;挂载到我们的OJ上&#xff0c;供大家学习交流&#xff0c;体会笔试难度。现已录入200道互联网大厂模拟练习题&…

简易someip服务发现SD报文演示

环境 $ cat /etc/os-release PRETTY_NAME"Ubuntu 22.04.1 LTS" NAME"Ubuntu" VERSION_ID"22.04" VERSION"22.04.1 LTS (Jammy Jellyfish)" VERSION_CODENAMEjammy IDubuntu ID_LIKEdebian HOME_URL"https://www.ubuntu.com/"…

chatgpt赋能Python-pythonsum

Pythonsum&#xff1a;优秀的Python算法包介绍 Pythonsum是Python语言的一个优秀的算法包&#xff0c;具有很高的可重用性和性能&#xff0c;支持大规模数据处理和复杂算法实现。本文将为大家介绍Pythonsum的基本功能和优势。 Pythonsum的基本功能 Pythonsum提供了一系列丰富…

华为OD机试真题 Java 实现【对称字符串】【2023Q2 200分】

一、题目描述 对称就是最大的美学&#xff0c;现有一道关于对称字符串的美学。 已知&#xff1a; 第 1 个字符串&#xff1a;R 第 2 个字符串&#xff1a;BR 第 3 个字符串&#xff1a;RBBR 第 4 个字符串&#xff1a;BRRBRBBR 第 5 个字符串&#xff1a;RBBRBRRBBRRBRBBR …

扑克牌大小OJ题

题目链接 扑克牌大小_牛客题霸_牛客网 题目完整代码 #include <iostream> #include<string> #include<algorithm> using namespace std;// left_str 左边牌 // right_str 右边牌// left_count 左边牌数 // right_count 右边牌数// left_first 左边第一个牌…

chatgpt赋能Python-pythonsep怎么用

Python在SEO中的应用 Python一直是广受欢迎的编程语言之一&#xff0c;它拥有强大的功能和易于使用的特性&#xff0c;使得它成为了许多开发人员们的首选。“Pythonsep”是Python在SEO中的应用&#xff0c;它可以帮助用户更好地优化自己的网站&#xff0c;让网站更容易被用户发…

搭建python web环境----Django

第一步&#xff1a;安装Django 1.进入cmd&#xff1a;pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple 2.检测版本&#xff1a; 第二步&#xff1a;配置环境变量 1.查找python安装位置: 2.打开django文件夹中bin文件夹&#xff1a; 查看django的安装位置&am…

火爆CV圈的SAM是什么?

SAM是什么 前言 最近几周&#xff0c;人工智能的圈子里都在讨论SAM&#xff08;Segment Anything Model&#xff09;&#xff0c;一个号称&#xff08;零样本&#xff09;分割一切的图像分割模型。 图&#xff1a;Segment Anything Demo 2023年4月6号&#xff0c;Meta AI发布…

npm install(报错)

1、npm install 报错&#xff08;如图&#xff09; WARN ERESOLVE overriding peer dependency npm WARN While resolving: intervolga/optimize-cssnano-plugin1.0.6 npm WARN Found: webpack3.12.0 npm WARN node_modules/webpack npm WARN peer webpack"^2.0.0 || ^3…

spring源码学习

1.xmlBeanFactory对defaultListableBeanFactory类进行扩展&#xff0c;主要用于从XML文档中获取BeanDefinition&#xff0c;对于注册及获取bean都是使用从父类DefaultListableBeanFactory继承的方法去实现。 xmlBeanFactory 主要是使用reader属性对资源文件进行读取和注册。 2.…

VMware ESXi 6.7 U3 Final - ESXi 6 系列最终版下载

VMware ESXi 6.7 U3 Final - ESXi 6 系列最终版下载 VMware ESXi 6 Standard 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-6/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org VersionRelease NameRelease …

APIO2023 游记

GDOI 和 GDKOI 的游记都咕咕咕了&#xff0c;而且都炸了&#xff0c;APIO 的游记提前发&#xff0c;就是要破釜沉舟。 我是线上选手。 Day -7 我们原题检测&#xff0c;阿克了&#xff0c;毕竟是原题&#xff0c;虽然有两道博弈论黑题确实挺毒瘤的。 教练让我做 APIO2012 的…

centos8安装mysql8

本次介绍捆绑包rpm方式安装mysql 首先到mysql官网:MySQL 1.下载捆绑包 2.上传至服务器 3.解压 tar -xvf mysql捆绑包.tar 4.重点来了,按照以下顺序分别安装(命令中的版本号按照自己下载的版本调整) rpm -ivh mysql-community-common-8.0.26-1.el7.x86_64.rpm rpm -ivh my…

东南亚市场攻略:如何利用海外网红实现品牌曝光与销售增长

在当今数字化时代&#xff0c;社交媒体的兴起改变了品牌推广和市场开发的方式。尤其是在东南亚地区&#xff0c;网红营销迅速发展&#xff0c;成为品牌开发该地市场的重要策略之一。本文Nox聚星将和大家详细探讨出海品牌该如何利用海外网红营销来开发东南亚市场。 ​一、东南亚…

怎么做邮件营销?邮件营销必备攻略

电子邮件营销是与受众沟通、建立关系和推动转化有效的方式之一。然而&#xff0c;撰写有效的电子邮件营销活动需要创造力和方法技巧的结合。做好电子邮件营销能够为企业带来长期的客源&#xff0c;并为其培养稳定优质的客户&#xff0c;为企业带来长期收益。在这篇文章中&#…

这样做WhatsApp群组营销,转化率猛UP

WhatsApp群组营销是一种利用WhatsApp群组进行推广和营销活动的策略。通过创建或参与相关主题的群组&#xff0c;您可以与潜在客户建立联系&#xff0c;传递信息并促进销售。 以下是一些WhatsApp群组营销的建议&#xff1a; 1.确定目标受众&#xff0c;建立目标群组&#xff1a…

2023天一永安杯部分wp

web Query 布尔盲注 import requests import stringdictionary string.digitsstring.ascii_letters"_-{,}" url "http://cd5a2660b462c867.node.nsctf.cn/login.php" xxx"" for i in range(1,666):print("正在爆破第{}位".format…