Dubbo源码解析之@DubboService、@DubboReference(Dubbo源码一)

2024-08-29 22:12

本文主要是介绍Dubbo源码解析之@DubboService、@DubboReference(Dubbo源码一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

更好的阅读体验:Dubbo源码解析之@DubboService、@DubboReference(Dubbo源码一)
视频讲解:https://www.bilibili.com/video/BV1nBsMejEbL



对于Dubbo用的最多的就是@DubboService、@DubboReference,与之对应的就是服务的提供方、调用方。

之所以加上注解就可以运行,定是生成了代理对象,这篇文章就来讲讲如何基于这两个注解生成代理对象。


不管是服务端还是客户端,在使用Dubbo的时候都会先使用@EnableDubbo,比如下面的demo

@SpringBootApplication
@EnableDubbo
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}

@EnableDubbo 是一个组合注解,它头上还有@DubboComponentScan和@EnableDubboConfig,它们就是分别来解析@DubboService、@DubboReference


EnableDubbo

@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {}

DubboComponentScan

@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {}

EnableDubboConfig

@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {}

一、@DubboReference 注解解析


DubboConfigConfigurationRegistrar 里面注入了一个bean处理器 ReferenceAnnotationBeanPostProcessor,这个处理器会把带有下面三个注解的bean代理成一个 ReferenceBean

  • DubboReference
  • Reference
  • com.alibaba.dubbo.config.annotation.Reference

1、入口


入口跳的很多,全部把代码复制过来阅读体验不好,也全无必要,这里给出每个方法的关键代码

EnableDubbo

@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {}

EnableDubboConfig

@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {}

DubboConfigConfigurationRegistrar

public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// initialize dubbo beansDubboSpringInitializer.initialize(registry);}
}

DubboSpringInitializer

public static void initialize(BeanDefinitionRegistry registry) {// ...// init dubbo contextinitContext(context, registry, beanFactory);
}private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,ConfigurableListableBeanFactory beanFactory) {// ...// register common beansDubboBeanUtils.registerCommonBeans(registry);
}

DubboBeanUtils

static void registerCommonBeans(BeanDefinitionRegistry registry) {// ...// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure BeanregisterInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,ReferenceAnnotationBeanPostProcessor.class);// ...
}

2、bean处理器


所谓bean的后置处理器,其实就是在bean完成初始化之后,就会调用这个方法,给你所有的bean,然后你就可以对这个bean为所欲为了

bean处理器有很多,有前置处理器、后置处理器、bean工厂处理器


2-1、前、后置处理器

只需要实现BeanPostProcessor 接口,重写里面的前置、后置处理器就好了,系统会把每个bean作为参数去调用这个方法

public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

2-2、bean工厂处理器

上面的前后置处理器,是系统拿到bean去调用这个方法,bean工厂处理器直接把bean工厂给你

public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}

3、循环所有的bean,找到使用注解的bean生成代理对象


ReferenceAnnotationBeanPostProcessor实现了BeanFactoryPostProcessor,重写了postProcessBeanFactory,在这个方法里面对使用了注解的bean进行代理

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 遍历所有的beanString[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {Class<?> beanType;// 判断是不是工厂bean,显然我们不是if (beanFactory.isFactoryBean(beanName)) {// ...} else {// 走这个、拿到classbeanType = beanFactory.getType(beanName);}if (beanType != null) {// 找到需要被代理的 metadataAnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);try {// 进行代理生成prepareInjection(metadata);} catch (BeansException e) {throw e;} catch (Exception e) {throw new IllegalStateException("Prepare dubbo reference injection element failed", e);}}}
}

4、找到合适的bean


匹配逻辑,其实就是拿每一个Class 上面的注解,看看是否和DubboReference相关注解匹配,下面代码给出大概步骤,忽略一些判断逻辑

setp 1
protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {// ...try {// 走这里构建metadata = buildAnnotatedMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);} catch (NoClassDefFoundError err) {throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +"] for annotation metadata: could not find class that it depends on", err);} // ...return metadata;
}
setp 2
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {// 这个方法就会找到合适匹配的beanCollection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
setp 3
private List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {final List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<>();ReflectionUtils.doWithFields(beanClass, field -> {for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);if (attributes != null) {if (Modifier.isStatic(field.getModifiers())) {if (logger.isWarnEnabled()) {logger.warn(CONFIG_DUBBO_BEAN_INITIALIZER, "", "", "@" + annotationType.getName() + " is not supported on static fields: " + field);}return;}elements.add(new AnnotatedFieldElement(field, attributes));}}});return elements;
}

getAnnotationTypes 就是在初始化的时候Set进去的

public ReferenceAnnotationBeanPostProcessor() {super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}public AbstractAnnotationBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");this.annotationTypes = annotationTypes;
}

5、注册 ReferenceBean类型的 beanDefinition


让我们再回到 ReferenceAnnotationBeanPostProcessor#postProcessBeanFactory 在这个方法里面循环每一个bean看它是否用到了 DubboReference 相关注解,如果有就进行代理对象

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {// ...if (beanType != null) {// 找到满足代理的bean,上一节已经讲了AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);try {// 进行代理prepareInjection(metadata);}}// ... }
}

protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {try {//find and register bean definition for @DubboReference/@Referencefor (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {if (fieldElement.injectedObject != null) {continue;}Class<?> injectedType = fieldElement.field.getType();AnnotationAttributes attributes = fieldElement.attributes;// 注册代理beanString referenceBeanName = registerReferenceBean(fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);//associate fieldElement and reference beanfieldElement.injectedObject = referenceBeanName;injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);}// ...} catch (ClassNotFoundException e) {throw new BeanCreationException("prepare reference annotation failed", e);}
}

registerReferenceBean 方法很长,前面有一系列的校验和缓存处理,这里为了简便,只给出后面注册 beanDefinition 部分

public String registerReferenceBean(String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member) throws BeansException {// ... 省略一大段校验缓存逻辑// Register the reference bean definition to the beanFactoryRootBeanDefinition beanDefinition = new RootBeanDefinition();// 看看看看,找到了,注册的这个 beanDefinition ,是 ReferenceBean.classbeanDefinition.setBeanClassName(ReferenceBean.class.getName());// ... 省略赋值的逻辑// 注册BeanDefinition, 被注册的 BeanDefinition,会生成一个对象beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);logger.info("Register dubbo reference bean: " + referenceBeanName + " = " + referenceKey + " at " + member);return referenceBeanName;
}

6、生成代理对象 ReferenceBean


ReferenceBean 是一个FactoryBean,所以在需要这个bean的时候会调用getObject 获取bean

ReferenceBean<T> implements FactoryBean<T>,ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean 
@Override
public T getObject() {if (lazyProxy == null) {createLazyProxy();}return (T) lazyProxy;
}

private void createLazyProxy() {// ....// 这里默认走的就是Javassist代理if (StringUtils.isEmpty(this.proxy) || CommonConstants.DEFAULT_PROXY.equalsIgnoreCase(this.proxy)) {generateFromJavassistFirst(interfaces);}if (this.lazyProxy == null) {generateFromJdk(interfaces);}
}

好啦,到这里代理对象就生成完毕了,这里看到它在代理对象里面注册了一个 LazyTargetInvocationHandler,它本质上是一个 InvocationHandler,所以当执行这个代理对象的时候就会执行org.apache.LazyTargetInvocationHandler#invoke 这就行下一期要讲的,运行原理

private void generateFromJavassistFirst(List<Class<?>> interfaces) {try {this.lazyProxy = Proxy.getProxy(interfaces.toArray(new Class[0])).newInstance(new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));} catch (Throwable fromJavassist) {// ...}
}

二、@DubboService 注解解析


相较于@DubboReference,@DubboService的解析要复杂不少,先是扫描到带有注解的实体,生成 ServiceBean,再基于ServiceBean生成CallbackRegistrationInvoker对象


1、入口


@EnableDubbo > @DubboComponentScan > DubboComponentScanRegistrar.class

DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar,重写了registerBeanDefinitions,这个方法里面就注入了Service处理器,通过扫描包下面使用相关注解的bean

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// initialize dubbo beansDubboSpringInitializer.initialize(registry);Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);// 注册Service处理器registerServiceAnnotationPostProcessor(packagesToScan, registry);
}

2、bean 处理器


通过扫描指定包下的bean来筛选是否满足生成 ServiceBean

org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor#postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {this.registry = registry;scanServiceBeans(resolvedPackagesToScan, registry);
}

scanServiceBeans

看看这里把 serviceAnnotationTypes 装进去了,下面判断的时候会用到

private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {// 循环每个包for (String packageToScan : packagesToScan) {DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);// 🌈🌈🌈🌈构建需要包含哪些bean, serviceAnnotationTypes 就是上面定义的注解for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));}// 扫描每个包scanner.scan(packageToScan);// 找到合适的 BeanDefinitionSet<BeanDefinitionHolder> beanDefinitionHolders =findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);// 循环每一个合适的 BeanDefinitionfor (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {// 生成 ServiceBeanprocessScannedBeanDefinition(beanDefinitionHolder);servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());}servicePackagesHolder.addScannedPackage(packageToScan);}
}

serviceAnnotationTypes

private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007DubboService.class,// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.ServiceService.class,// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue : https://github.com/apache/dubbo/issues/4330com.alibaba.dubbo.config.annotation.Service.class
);

3、找到合适的 BeanDefinition


这里寻找的过程有一点绕,还是和之前一起,给出每个关键节点的关键代码

本质上就是扫描包下面的BeanDefinition看看是否有包含 @DubboService相关注解


findServiceBeanDefinitionHolders

org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor#findServiceBeanDefinitionHolders

private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,BeanNameGenerator beanNameGenerator) {Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());for (BeanDefinition beanDefinition : beanDefinitions) {String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);beanDefinitionHolders.add(beanDefinitionHolder);}return beanDefinitionHolders;}

findCandidateComponents

org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner#findCandidateComponents

@Override
public Set<BeanDefinition> findCandidateComponents(String basePackage) {Set<BeanDefinition> beanDefinitions = beanDefinitionMap.get(basePackage);// if beanDefinitions size is null => scanif (Objects.isNull(beanDefinitions)) {beanDefinitions = super.findCandidateComponents(basePackage);beanDefinitionMap.put(basePackage, beanDefinitions);}return beanDefinitions;
}

scanCandidateComponents

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet();// ...MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);if (this.isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);// 判断当前bean是不是满足if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {if (debugEnabled) {this.logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);} else if (debugEnabled) {this.logger.debug("Ignored because not a concrete top-level class: " + resource);}} // ...return candidates;
}

isCandidateComponent

includeFilters 数据就是在scanServiceBeans 里面设置进去的

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent(org.springframework.core.type.classreading.MetadataReader)

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {Iterator var2 = this.excludeFilters.iterator();TypeFilter tf;do {if (!var2.hasNext()) {var2 = this.includeFilters.iterator();do {if (!var2.hasNext()) {return false;}tf = (TypeFilter)var2.next();} while(!tf.match(metadataReader, this.getMetadataReaderFactory()));return this.isConditionMatch(metadataReader);}tf = (TypeFilter)var2.next();} while(!tf.match(metadataReader, this.getMetadataReaderFactory()));return false;
}

4、生成ServiceBean


org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor#processScannedBeanDefinition


private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder) {Class<?> beanClass = resolveClass(beanDefinitionHolder);Annotation service = findServiceAnnotation(beanClass);// The attributes of @Service annotationMap<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();// ServiceBean Bean nameString beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);AbstractBeanDefinition serviceBeanDefinition =buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);}

生成beanName

private String generateServiceBeanName(Map<String, Object> serviceAnnotationAttributes, String serviceInterface) {ServiceBeanNameBuilder builder = create(serviceInterface, environment).group((String) serviceAnnotationAttributes.get("group")).version((String) serviceAnnotationAttributes.get("version"));return builder.build();
}

构建bean参数

定义 BeanDefinition 的class,并且解析注解上的参数,放入BeanDefinition

private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,String serviceInterface,String refServiceBeanName) {// 设置class                                                            BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();String[] ignoreAttributeNames = ObjectUtils.of("provider", "monitor", "application", "module", "registry", "protocol","methods", "interfaceName", "parameters", "executor");propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));addPropertyReference(builder, "ref", refServiceBeanName);// Set interfacebuilder.addPropertyValue("interface", serviceInterface);// ... 设置各种参数return builder.getBeanDefinition();
}

注册到 BeanDefinitionRegistry

private void registerServiceBeanDefinition(String serviceBeanName, AbstractBeanDefinition serviceBeanDefinition, String serviceInterface) {// check service bean// ...registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition);// ...
}

5、ServiceBean


一般生成代理对象,都会有一个 invoker方法,但ServiceBean没有,这是因为ServiceBean 只是存储DubboService的相关信息,后面还会生成一个真正invoker。


先来看一下ServiceBean的继承关系

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {}

真正的invoker是在 ServiceConfig中生成的


ServiceBean 重写了 afterPropertiesSet ,把自己注册到了moduleConfigManager(这个后面会看到)
@Override
public void afterPropertiesSet() throws Exception {if (StringUtils.isEmpty(getPath())) {if (StringUtils.isNotEmpty(getInterface())) {setPath(getInterface());}}//register service beanModuleModel moduleModel = DubboBeanUtils.getModuleModel(applicationContext);moduleModel.getConfigManager().addService(this);moduleModel.getDeployer().setPending();
}

6、invoker生成


Dubbo注册了一个事件监听器,这个事件监听器会做很多初始化的工作,就会到生成Invoker的地方,这里的调用链路太长了,给一个Debug的图

在这里插入图片描述


最终会到当前类的org.apache.dubbo.config.ServiceConfig#doExportUrl方法

private void doExportUrl(URL url, boolean withMetaData, RegisterTypeEnum registerType) {if (!url.getParameter(REGISTER_KEY, true)) {registerType = RegisterTypeEnum.MANUAL_REGISTER;}if (registerType == RegisterTypeEnum.NEVER_REGISTER ||registerType == RegisterTypeEnum.MANUAL_REGISTER ||registerType == RegisterTypeEnum.AUTO_REGISTER_BY_DEPLOYER) {url = url.addParameter(REGISTER_KEY, false);}Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);if (withMetaData) {invoker = new DelegateProviderMetaDataInvoker(invoker, this);}Exporter<?> exporter = protocolSPI.export(invoker);exporters.computeIfAbsent(registerType, k -> new CopyOnWriteArrayList<>()).add(exporter);
}

interfaceClass 取的是刚刚解析ServiceBean来的,也就是使用DubboService注解的类,invoker 返回的是Java生成的代理对象,Dubbo会再把它包装一层,所谓的包装就是用 Filter去包它,一层层的。最终生成 CallbackRegistrationInvoker。


在这里插入图片描述


withMetaData: 每一个使用DubboService注解的对象都会生成两个代理对象,一个正常的代理对象,用来执行服务,一个 MetaData 类型的代理对象,用来维护基础数据


后续Netty收到请求,就会转而找到对应的 Invoker。

这篇关于Dubbo源码解析之@DubboService、@DubboReference(Dubbo源码一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118994

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

OWASP十大安全漏洞解析

OWASP(开放式Web应用程序安全项目)发布的“十大安全漏洞”列表是Web应用程序安全领域的权威指南,它总结了Web应用程序中最常见、最危险的安全隐患。以下是对OWASP十大安全漏洞的详细解析: 1. 注入漏洞(Injection) 描述:攻击者通过在应用程序的输入数据中插入恶意代码,从而控制应用程序的行为。常见的注入类型包括SQL注入、OS命令注入、LDAP注入等。 影响:可能导致数据泄

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [