java-spring 图灵 04 doscan

01.本次的重点依旧是扫描函数,这次是spring中的源码:

02.第一步,构造AnnotationConfigApplicationContext

主方法:

	public static void main(String[] args) {// 创建一个Spring容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.test();}

AnnotationConfigApplicationContext 的构造函数:(这个时候是有参)

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScannerthis();register(componentClasses);refresh();}

this()是指的AnnotationConfigApplicationContext 的无参构造函数:

StartupStep 这个接口是用来记录 AnnotatedBeanDefinitionReader 这个函数运行的时间的

public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// 额外会创建StandardEnvironmentthis.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner = new ClassPathBeanDefinitionScanner(this);}

03.来到了本次的重点类:ClassPathBeanDefinitionScanner类,这里依次执行方法

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment) {this(registry, useDefaultFilters, environment,(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));}
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;if (useDefaultFilters) {registerDefaultFilters();//重点}setEnvironment(environment);setResourceLoader(resourceLoader);}

注:
这个BeanDefinitionRegistry 是注册 是一个接口

public interface BeanDefinitionRegistry extends AliasRegistry {
}

他其实有一个很重要的实现类,也是DefaultListableBeanFactory ,在扫描中起作用的其实也是DefaultListableBeanFactory ,但是这里是只需要注册,所以,还是用接口比较准确

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {}

最后一个的registerDefaultFilters:

	protected void registerDefaultFilters() {// 注册@Component对应的AnnotationTypeFilterthis.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}}

04.扫描scan:我也不知道怎么就到了这个地方

	public int scan(String... basePackages) {//在容器中计算BeanDefinition的数量int beanCountAtScanStart = this.registry.getBeanDefinitionCount();//真正扫描的函数doScan(basePackages);// Register annotation config processors, if necessary.if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}//得到本次的扫描的BeanDefinition的数量return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);}

05.scan中的doScan方法(重点)

//参数传入一组包名
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified");//创建一个BeanDefinitionHolder的集合Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); //循环这组包名for (String basePackage : basePackages) {//扫描之后得到一个包的全部BeanDefinitionSet<BeanDefinition> candidates = findCandidateComponents(basePackage);//循环这个集合for (BeanDefinition candidate : candidates) {//获取BeanDefinition 中的Scope注解的value值ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());//获取BeanDefinition 所代表的bean 的名字String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 解析@Lazy、@Primary、@DependsOn、@Role、@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanNameif (checkCandidate(beanName, candidate)) {//用BeanDefinitionHolder 来包装 已经通过检查的BeanDefinitionBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//添加到BeanDefinitionHolder集合中beanDefinitions.add(definitionHolder);// 注册registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

06.findCandidateComponents方法: 扫描之后得到一个包的全部BeanDefinition

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {//这个和简便扫描的索引文件有关,在MENF-INF的文件中的spring.componentsif (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {//一般都是这里的函数return scanCandidateComponents(basePackage);}}

07.scanCandidateComponents方法:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// 获取basePackage下所有的文件资源  //ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX  是 classpath*://在Spring框架中,可以使用org.springframework.core.io.support.ResourcePatternResolver接口的resolveBasePackage方法来将指定的基础包解析为用于包搜索路径的模式规范。//例如,如果基础包是com.example.app,则可以使用resolveBasePackage方法将其解析为类路径下的资源路径,如classpath:com/example/app/。//this.resourcePattern 是  **/*.class//classpath*:com.xxx.xxx//*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//得到所有的class 的file对象Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {//可读的话,读入元数据MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// excludeFilters、includeFilters判断if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断//构造一个BeanDefinitionScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);//sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}

注释:

ResourcePatternResolver接口:默认实现类是PathMatchingResourcePatternResolver类。

public interface ResourcePatternResolver extends ResourceLoader {String CLASSPATH_ALL_URL_PREFIX = "classpath*:";Resource[] getResources(String locationPattern) throws IOException;}

Resource接口:Resource一般包括这些实现类:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource

public interface Resource extends InputStreamSource {boolean exists();default boolean isReadable() {return true;}default boolean isOpen() {//返回一个布尔值,指示此资源是否具有开放流的句柄return false;}default boolean isFile() {return false;}URL getURL() throws IOException;//返回一个URL句柄,如果资源不能够被解析为URL,将抛出IOExceptionURI getURI() throws IOException;File getFile() throws IOException;//返回某个文件,如果资源不能够被解析称为绝对路径,将会抛出FileNotFoundExceptiondefault ReadableByteChannel readableChannel() throws IOException {return Channels.newChannel(getInputStream());}long contentLength() throws IOException;long lastModified() throws IOException;Resource createRelative(String relativePath) throws IOException;String getFilename();String getDescription();
}

这里的语句的结果:resources 数组是一个个的class 的file对象 具体的类是FileSystemResource

Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

在这里插入图片描述

08.isCandidateComponent方法:
通过传入的元数据,判断是不是这个类和容器中的已经扫描存在的excludeFilter是不是匹配,有的话,排除,不是一个bean

在@Component注解中,如果没有显示声明includeFilter,那么就会这个类的Component的includeFilter是被修饰类名

	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return false;}}// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditionalfor (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return isConditionMatch(metadataReader);}}return false;}

09.isConditionMatch 进一步 查看是不是有@Conditional注解

	private boolean isConditionMatch(MetadataReader metadataReader) {if (this.conditionEvaluator == null) {this.conditionEvaluator =new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);}return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());}

10.shouldSkip方法:表示是不是要跳过,如果有@Conditional ,不要跳过

	public boolean shouldSkip(AnnotatedTypeMetadata metadata) {return shouldSkip(metadata, null);}

shouldSkip

	public boolean  shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {//判断有无Conditional  没有就跳过if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {return false;}
//有的话,这块是编译原理的phase  if (phase == null) {if (metadata instanceof AnnotationMetadata &&ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);}return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);}}
//后面还有,但不是重点,会去执行那个实现接口的类,看一下条件是什么,成立的话,@Conditional修饰的类就会是一个bean

注释:@Conditional,参数是一个类
怎么使用@Conditional注解了?
01.先创建一个实现类,实现Condition接口:
这里写的是条件

public class User implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {try {context.getClassLoader().loadClass("com.zhouyu.service.OrderService");} catch (ClassNotFoundException e) {throw new RuntimeException(e);}return false;}
}

02.使用@Conditional注解

@Component
@Conditional(User.class)
public class UserService  {}

11.回到scanCandidateComponents方法:

第7到10步,此时已经扫描完成了包,完成了判断通过,符合构造一个BeanDefinition 的条件,不匹配容器中excludeFilter,在includeFilter上有符合的,也完成了关于@Conditional判断

构造一个BeanDefinition :
ScannedGenericBeanDefinition 方法:

	public ScannedGenericBeanDefinition(MetadataReader metadataReader) {Assert.notNull(metadataReader, "MetadataReader must not be null");//获取元数据this.metadata = metadataReader.getAnnotationMetadata();// 这里只是把className设置到BeanDefinition中setBeanClassName(this.metadata.getClassName());setResource(metadataReader.getResource());}
@Overridepublic void setBeanClassName(@Nullable String beanClassName) {this.beanClass = beanClassName;}
@Overridepublic void setResource(@Nullable Resource resource) {this.resource = resource;}

12.创建完成了,要判断isCandidateComponent方法,判断01.这个类是不是内部类,因为内部类也有class文件,内部类不能成为bean,02.是不是接口或者抽象类 ,这些都不能成为bean ,03.是抽象类,但是类中有一个注解@Lookup,可以成为bean

	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {AnnotationMetadata metadata = beanDefinition.getMetadata();return (metadata.isIndependent() && (metadata.isConcrete() ||(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));}

成功的话,把这个BeanDefinition加入数组中,结束了这个scanCandidateComponents方法

if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}

13.回到了doscan方法,这里获取的是Scope注解的值和beanname的值

for (BeanDefinition candidate : candidates) {//获取Scope注解的值ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());
//获取beanname的值,在注解@Component中String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

14.其中的this.beanNameGenerator:

	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

AnnotationBeanNameGenerator类:

	public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();

用到的方法:
AnnotationBeanNameGenerator的generateBeanName方法:

	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {// 获取注解@Component的注解所指定的beanNameif (definition instanceof AnnotatedBeanDefinition) {String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {// 返回一个return beanName;}}// 返回一个默认的名字return buildDefaultBeanName(definition, registry);}

determineBeanNameFromAnnotation方法:返回注解中的指定的名字,如果没有返回一个null

@Nullableprotected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {//获得元数据AnnotationMetadata amd = annotatedDef.getMetadata();//获取元数据中的注解信息Set<String> types = amd.getAnnotationTypes();String beanName = null;for (String type : types) {AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);if (attributes != null) {Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {Set<String> result = amd.getMetaAnnotationTypes(key);return (result.isEmpty() ? Collections.emptySet() : result);});if (isStereotypeWithNameValue(type, metaTypes, attributes)) {//获取value值Object value = attributes.get("value");if (value instanceof String) {String strVal = (String) value;if (StringUtils.hasLength(strVal)) {if (beanName != null && !strVal.equals(beanName)) {throw new IllegalStateException("Stereotype annotations suggest inconsistent " +"component names: '" + beanName + "' versus '" + strVal + "'");}beanName = strVal;}}}}}return beanName;}

isStereotypeWithNameValue方法:
对注解@Component判断是不是有指定的value,有的话返回value


用到的常量private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";protected boolean isStereotypeWithNameValue(String annotationType,Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||annotationType.equals("javax.annotation.ManagedBean") ||annotationType.equals("javax.inject.Named");return (isStereotype && attributes != null && attributes.containsKey("value"));}

15.回到generateBeanName方法:
buildDefaultBeanName:如果没有指定value,那么就生成一个默认的名字

	protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return buildDefaultBeanName(definition);}
	protected String buildDefaultBeanName(BeanDefinition definition) {String beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");String shortClassName = ClassUtils.getShortName(beanClassName);return Introspector.decapitalize(shortClassName);}

这句话回生成一个默认的名字:

Introspector.decapitalize(shortClassName);
  public static String decapitalize(String name) {if (name == null || name.length() == 0) {return name;}if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){return name;}char[] chars = name.toCharArray();chars[0] = Character.toLowerCase(chars[0]);return new String(chars);}

16.再回到doscan方法:
这一步设置一些默认的值

if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {// 设置BeanDefinition的默认值beanDefinition.applyDefaults(this.beanDefinitionDefaults);// AutowireCandidate表示某个Bean能否被用来做依赖注入if (this.autowireCandidatePatterns != null) {beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));}}

具体设置那些

public void applyDefaults(BeanDefinitionDefaults defaults) {Boolean lazyInit = defaults.getLazyInit();if (lazyInit != null) {setLazyInit(lazyInit);}setAutowireMode(defaults.getAutowireMode());setDependencyCheck(defaults.getDependencyCheck());setInitMethodName(defaults.getInitMethodName());setEnforceInitMethod(false);setDestroyMethodName(defaults.getDestroyMethodName());setEnforceDestroyMethod(false);}

17.一些其他的注解

if (candidate instanceof AnnotatedBeanDefinition) {// 解析@Lazy、@Primary、@DependsOn、@Role、@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}
	public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {processCommonDefinitionAnnotations(abd, abd.getMetadata());}
	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));}else if (abd.getMetadata() != metadata) {lazy = attributesFor(abd.getMetadata(), Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));}}if (metadata.isAnnotated(Primary.class.getName())) {abd.setPrimary(true);}AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);if (dependsOn != null) {abd.setDependsOn(dependsOn.getStringArray("value"));}AnnotationAttributes role = attributesFor(metadata, Role.class);if (role != null) {abd.setRole(role.getNumber("value").intValue());}AnnotationAttributes description = attributesFor(metadata, Description.class);if (description != null) {abd.setDescription(description.getString("value"));}}

18.再回到doscan方法:
最后一步,判断是不是已经存在bean

// 检查Spring容器中是否已经存在该beanNameif (checkCandidate(beanName, candidate)) {//没有的话BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册registerBeanDefinition(definitionHolder, this.registry);}
	protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {if (!this.registry.containsBeanDefinition(beanName)) {//如果没有的话,就直接返回ture,容器中没有相同的beanNamereturn true;}BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();if (originatingDef != null) {existingDef = originatingDef;}// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。if (isCompatible(beanDefinition, existingDef)) {return false;}throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");}

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

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

相关文章

C#基础|Debug程序调试学习和技巧总结

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 在程序的开发过程中&#xff0c;可能绝大部分时间是用来调试程序&#xff0c; 当完成了某个功能的编程&#xff0c;都需要调试一下程序&#xff0c;看编程是否存在问题。 01 为什么需要程序调试 无论是电气工程师还…

深入探究图像增强(C语言实现)

我们将从基础出发使用C语言进行图像处理与分析&#xff0c;重点讨论图像增强和平滑技术。图像增强技术旨在通过增加对比度、亮度和整体清晰度来改善图像的视觉质量。另一方面&#xff0c;图像平滑方法则用于减少噪声并减少图像中的突变&#xff0c;使图像更加均匀和视觉上吸引人…

2024新版淘宝客PHP网站源码

源码介绍 2024超好看的淘客PHP网站源码&#xff0c;可以做优惠券网站&#xff0c;上传服务器&#xff0c;访问首页进行安装 安装好了之后就可以使用了&#xff0c;将里面的信息配置成自己的就行 喜欢的朋友们拿去使用把 效果截图 源码下载 2024新版淘宝客网站源码

高精度算法(1)

前言 今天来讲一讲高精度算法&#xff0c;我们说一个数据类型&#xff0c;有它的对应范围比如int类型最多 可以包含到负2的31次方到2的31次方减一 其实大概就是20亿左右那么其他的类型也同样如此 那么&#xff0c;如何解决一个很大很大的数的运算呢&#xff1f; 我们今天介…

OSPF综合大实验

1、R4为ISP&#xff0c;其上只配置IP地址&#xff1b;R4与其他所直连设备间均使用公有IP&#xff1b; 2、R3-R5、R6、R7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3、整个OSPF环境IP基于172.16.0.0/16划分&#xff1b;除了R12有两个环回&#xff0c;其他路由器均有一个环…

局域网管理软件,适合在局域网内的管理软件有哪些?

信息技术的不断发展&#xff0c;局域网在企业、学校等机构中得到了广泛应用。 局域网不仅能够提高数据传输效率&#xff0c;还能实现资源共享和协同工作。 为了更好地管理和维护局域网&#xff0c;需要使用一些专业的局域网管理软件。 一、局域网的应用范围 局域网&#xff…

【算法一则】分隔链表

题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x …

做一个图像分类任务(一)准备数据集

文章目录 环境准备准备数据集爬取数据代码删除多余的文件fruit81水果数据图像分类数据集下载统计图像的尺寸和比例分布代码划分训练集和数据集代码可视化图像代码统计各类别的数量 环境准备 推荐按照原作者推荐的环境&#xff1a;代码测试云GPU环境&#xff1a;GPU RTX 3060、…

如何安全、高速、有效地利用IP代理爬取数据

陈老老老板&#x1f9d9;‍♂️ &#x1f46e;‍♂️本文专栏&#xff1a;生活&#xff08;主要讲一下自己生活相关的内容&#xff09;生活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f934;本文简述&#xff1a;如何安全、高速、有效地利用IP代理爬取数据 &#x1f473…

多模态AnyGPT——整合图像、语音和文本多模态大规模语言模型算法原理与实践

概述 大规模语言模型在理解和生成人类语言方面具有非凡的能力&#xff0c;但迄今为止&#xff0c;它们的能力主要局限于文本处理。然而&#xff0c;现实世界是一个多模式的环境&#xff0c;信息通过视觉、听觉和触觉等多种感官进行交换。融入这种多样性是开发下一代系统的主要…

云原生Kubernetes: K8S 1.29版本 部署Jenkins

目录 一、实验 1.环境 2.K8S 1.29版本 部署Jenkins 服务 3.jenkins安装Kubernetes插件 二、问题 1.创建pod失败 2.journalctl如何查看日志信息 2.容器内如何查询jenkins初始密码 3.jenkins离线安装中文包报错 4.jenkins插件报错 一、实验 1.环境 &#xff08;1&…

上位机图像处理和嵌入式模块部署(树莓派4b固件功能设计)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;上位机的功能都是基于插件进行开发的。但是上位机的成本比较贵&#xff0c;一般的企业不一定愿意接接受。这个时候另外一…

【第三版 系统集成项目管理工程师】 十五至尊图

持续更新。。。。。。。。。。。。。。。 【第三版】十五至尊图 十五至尊图【必会】1.整合&#xff08;7&#xff09;2.范围 &#xff08;6&#xff09;3.进度 &#xff08;6&#xff09;4.成本 &#xff08;4&#xff09;5.质量&#xff08;3&#xff09;6.资源&#xff08;6&…

【LeetCode: 3117. 划分数组得到最小的值之和 + 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Jmeter 测试Dubbo接口-实例

1、Dubbo插件准备 ①把jmeter-plugins-dubbo-2.7.4.1-jar-with-dependencies.jar包放在D:\apache-jmeter-5.5\lib\ext目录 ②重新打开Jmeter客户端 在线程组-添加-取样器-dubbo simple&#xff0c;添加dubbo接口请求 2、Jmeter测试lottery接口 ①配置zookeeper参数 由于dub…

【蓝桥杯嵌入式】蓝桥杯嵌入式第十四届省赛程序真题,真题分析与代码讲解

&#x1f38a;【蓝桥杯嵌入式】专题正在持续更新中&#xff0c;原理图解析✨&#xff0c;各模块分析✨以及历年真题讲解✨都已更新完毕&#xff0c;欢迎大家前往订阅本专题&#x1f38f; &#x1f38f;【蓝桥杯嵌入式】蓝桥杯第十届省赛真题 &#x1f38f;【蓝桥杯嵌入式】蓝桥…

在PostgreSQL中如何处理大对象(Large Objects),例如存储和检索二进制文件?

文章目录 存储二进制文件为大对象步骤 1&#xff1a;创建一个大对象步骤 2&#xff1a;写入数据到大对象 检索大对象为二进制文件步骤 1&#xff1a;打开大对象以进行读取步骤 2&#xff1a;从大对象读取数据 注意事项 PostgreSQL 提供了对大对象&#xff08;Large Objects&…

2024蓝桥杯省赛C++软件算法研究生组题解(含代码)+游记

A题 给你一个音游的游戏记录log.txt&#xff0c;判断玩家的最高连击数 题解 水题&#xff0c;但是要小心&#xff0c;miss的键需要重置k0&#xff0c;超时但正确的键重置k1 个人答案是9 代码&#xff1a; #include<cstdio> #include<cstring> #include<al…

高可用集群——keepalived

目录 1 高可用的概念 2 心跳监测与漂移 IP 地址 3 Keepalived服务介绍 4 Keepalived故障切换转移原理介绍 5 Keepalived 实现 Nginx 的高可用集群 5.1 项目背景 5.2 项目环境 5.3 项目部署 5.3.1 web01\web02配置&#xff1a; 5.3.2nginx负载均衡配置 5.3.3 主调度服…

[lesson43]继承的概念和意义

继承的概念和意义 类之间的组合关系 组合关系的特点 将其他类的对象作为当前类的成员使用当前类的对象与成员对象的生命期相同成员对象在用法上与普通对象完全一致 惊艳的继承 面相对象中的继承指类之间的父子关系 子类拥有父类的所有属性和行为子类就是一种特殊的父类子类…