Spring源码分析篇一 @Autowired 是怎样完成注入的?究竟是byType还是byName亦两者皆有
1. 五种不同场景下 @Autowired 的使用
第一种情况 上下文中只有一个同类型的bean
配置类
package org.example.bean;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FruitConfiguration {@Bean("apple")public Fruit apple(){return new Fruit("apple");}}
启动类
@ComponentScan(basePackages = "org.example.bean")
public class AutowiredTestDemo {@Autowiredprivate Fruit fruit;public static void main(String[] args) {AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.fruit);}}
输出
Fruit{name='apple', price=null}
第二种情况 上下文中有两个同类型不同名的bean 且都与注入字段名称不一致
配置类
@Configuration
public class FruitConfiguration {@Bean("apple")public Fruit apple(){return new Fruit("apple");}@Bean("banana")public Fruit banana(){return new Fruit("banana");}}
启动类
@ComponentScan(basePackages = "org.example.bean")
public class AutowiredTestDemo {@Autowiredprivate Fruit fruit;public static void main(String[] args) {AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.fruit);}}
异常结果
No qualifying bean of type 'org.example.bean.Fruit' available: expected single matching bean but found 2: apple,banana
第三种情况 上下文中有两个同类型不同名的bean 且其中一个与注入字段名称一致
配置类
@Configuration
public class FruitConfiguration {@Bean("apple")public Fruit apple(){return new Fruit("apple");}@Bean("banana")public Fruit banana(){return new Fruit("banana");}}
启动类
@ComponentScan(basePackages = "org.example.bean")
public class AutowiredTestDemo {@Autowiredprivate Fruit apple;public static void main(String[] args) {AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.apple);}}
输出结果
Fruit{name='apple', price=null}
第四种情况 上下文中有两个同类型不同名的bean 且都与注入字段名称不一致但其中一个使用@Primary 注解
配置类
package org.example.bean;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;@Configuration
public class FruitConfiguration {@Bean("apple")public Fruit apple(){return new Fruit("apple");}@Primary@Bean("banana")public Fruit banana(){return new Fruit("banana");}}
启动类
package org.example;import org.example.bean.Fruit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;@ComponentScan(basePackages = "org.example.bean")
public class AutowiredTestDemo {@Autowiredprivate Fruit fruit;public static void main(String[] args) {AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.fruit);}
}
输出结果
Fruit{name='banana', price=null}
第五种情况 上下文中有两个同类型不同名的bean 且都与注入字段名称不一致但注入时使用@Qualifier注解
配置类
package org.example.bean;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FruitConfiguration {@Bean("apple")public Fruit apple(){return new Fruit("apple");}@Bean("banana")public Fruit banana(){return new Fruit("banana");}}
启动类
package org.example;import org.example.bean.Fruit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;@ComponentScan(basePackages = "org.example.bean")
public class AutowiredTestDemo {@Autowired@Qualifier("apple")private Fruit fruit;public static void main(String[] args) {AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.fruit);}}
输出结果
Fruit{name='apple', price=null}
2.源码分析
启动类
public static void main(String[] args) {//创建应用上下文的同时注册AutowiredTestDemoAnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AutowiredTestDemo.class);AutowiredTestDemo autowiredTestDemo = app.getBean(AutowiredTestDemo.class);System.out.println(autowiredTestDemo.fruit);}
org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>…)
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {//调用无参构造方法this();//注册组件//调用 BeanDefinitionReaderUtils.registerBeanDefinition 注册bdregister(componentClasses);//刷新容器refresh();}
无参构造创建了一个AnnotatedBeanDefinitionReader对象与ClassPathBeanDefinitionScanner对象,用于读取和扫描带有注解的Bean定义信息
public AnnotationConfigApplicationContext() {this.reader = new AnnotatedBeanDefinitionReader(this);this.scanner = new ClassPathBeanDefinitionScanner(this);}
AnnotatedBeanDefinitionReader在初始化时将会往BeanFactory注册注解相关的处理器对象
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry;this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}
@Autowired注解是由 AutowiredAnnotationBeanPostProcessor 进行处理,而后者又实现了 InstantiationAwareBeanPostProcessorAdapter 与 MergedBeanDefinitionPostProcessor 两个扩展点接口
重写 MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition,在bean实例化前,合并定义信息后执行。将需要注入的字段和方法与之需要注入的bean建立映射关系并封装成InjectedElement集合,再与class对象建立映射关系封装为InjectionMetadata对象并存入缓冲中
@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {//遍历类中的字段与方法,如果需要依赖注入,将封装成InjectionMetadata并放入缓冲中InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);//将成员添加到 beanDefinition 中,以便在配置过程中由外部管理器处理该成员的生命周期和依赖注入metadata.checkConfigMembers(beanDefinition);}
重写 InstantiationAwareBeanPostProcessorAdapter.postProcessProperties,此方法将在bean实例化后,属性填充前执行,此时当前bean已经完成了实例化,因此可以通过之前缓冲起来的映射关系,一一找出需要注入的字段和方法以及其对应需要注入的值,通过反射进行赋值操作
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//从缓存中获取当前bean字节码对象的注解元信息InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//进行属性注入metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);}return pvs;}
大概了解了@Autowired的核心处理类AutowiredAnnotationBeanPostProcessor后,我们进一步分析上述五种情况,再源码底层是怎么处理的
情况一 有且仅有一个候选bean
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
Field field = (Field) this.member;Object value;//默认falseif (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {//处理当前bean所属字段的依赖注入,获取需要注入的对象value = resolveFieldValue(field, bean, beanName);}if (value != null) {//暴力访问ReflectionUtils.makeAccessible(field);//通过反射给当前需要注入的字段设置值field.set(bean, value);}
跟进resolveFieldValue(field, bean, beanName)方法一路往下直到doResolveDependency方法
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
resolveMultipleBeans 方法是处理集合类型的依赖注入,而我们当前是非集合类型,因此会调用
findAutowireCandidates 处理依赖注入
//集合类型注入Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans != null) {return multipleBeans;}//非集合类型注入Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}
protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {//根据需要注入的bean的类型 递归调用 beanNamesForTypeIncludingAncestors 获取父子BeanFactory中 类型的bean的名称// 注入 此处可能返回多个 候选的beanNameString[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);// 判断需要的类型是否是内建beanfor (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {Class<?> autowiringType = classObjectEntry.getKey();if (autowiringType.isAssignableFrom(requiredType)) {Object autowiringValue = classObjectEntry.getValue();autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);if (requiredType.isInstance(autowiringValue)) {result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);break;}}}// ,isSelfReference(beanName, candidate) 用于判断候选项是否是自身引用。// isAutowireCandidate(candidate, descriptor) 用于判断候选项是否符合自动装配的条件for (String candidate : candidateNames) {//调用DefaultListableBeanFactory.isAutowireCandidate() 完成@Qualifier注解过滤// 如果不满足将不会添加到候选Map中if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}if (result.isEmpty()) {boolean multiple = indicatesMultipleBeans(requiredType);// Consider fallback matches if the first pass failed to find anything...DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {addCandidateEntry(result, candidate, descriptor, requiredType);}}if (result.isEmpty() && !multiple) {// Consider self references as a final pass...// but in the case of a dependency collection, not the very same bean itself.for (String candidate : candidateNames) {if (isSelfReference(beanName, candidate) &&(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&isAutowireCandidate(candidate, fallbackDescriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}}}return result;}
此时容器中只有一个Fruit类型的bean,回到doResolveDependency方法中,最终调用descriptor.resolveCandidate获取到bean实例,然后通过反射完成依赖注入
//匹配到一个beanName 不满足if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;//只匹配到一个beanName 不满足if (matchingBeans.size() > 1) {autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}//调用 beanFactory.getBean(beanName) 根据名称获取需要注入的bean对象instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
因此,情况一 容器中只有一个目标类型的bean进行依赖注入就此结束
情况二,三,四 有两个同类型bean的两种情况
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
如果根据类型匹配到两个beanName,将进入此判断语句中
if (matchingBeans.size() > 1) {autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName == null) {//是否必须注入if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didn't even look for collection beans).return null;}}instanceCandidate = matchingBeans.get(autowiredBeanName);}
由determineAutowireCandidate方法决定最终注入的beanName,如果无法选择出最合适的,将执行resolveNotUnique方法抛出NoUniqueBeanDefinitionException 异常,也就是我们情况二看到的异常
进入determineAutowireCandidate 方法
Class<?> requiredType = descriptor.getDependencyType();//@Primary 注解处理 是否有标记了@Primary注解String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);if (primaryCandidate != null) {return primaryCandidate;}//javax.annotation.Priority 优先级匹配 值越小 优先级越高String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);if (priorityCandidate != null) {return priorityCandidate;}// Fallbackfor (Map.Entry<String, Object> entry : candidates.entrySet()) {String candidateName = entry.getKey();Object beanInstance = entry.getValue();if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||//将候选的beanName与依赖注入的字段名称进行匹配matchesBeanName(candidateName, descriptor.getDependencyName())) {return candidateName;}}return null;
首先针对第四种情况,如果有标记了@Primary注解的bean,将优先采用,如果都没有 ,则根据javax.annotation.Priority 注解的值选最小,值越小优先级越高。如果没有使用@Priority注解,将采用兜底方法
matchesBeanName(),哪一个候选的beanName与需要依赖注入的字段名称一致就使用谁
protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {return (candidateName != null &&(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));}
此时就是情况三 候选的beanName的名称与需要依赖注入的字段名称一致,依然能完成注入。
情况五 注入时使用@Qualifier注解
回到
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
在获取到多个候选的beanName后,将会遍历集合,调用isSelfReference,isAutowireCandidate进行筛选,
而Qualifier注解的处理就在isAutowireCandidate方法中
for (String candidate : candidateNames) {//调用DefaultListableBeanFactory.isAutowireCandidate() 完成@Qualifier注解过滤// 如果不满足将不会添加到候选Map中if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}
跟进来到
org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {boolean match = super.isAutowireCandidate(bdHolder, descriptor);if (match) {//Qualifier 注解匹配 获取对象标准的Qualifier注解的值与候选的beanName进行匹配//有Qualifier注解才进行比较判断//否则直接返回truematch = checkQualifiers(bdHolder, descriptor.getAnnotations());if (match) {MethodParameter methodParam = descriptor.getMethodParameter();if (methodParam != null) {Method method = methodParam.getMethod();if (method == null || void.class == method.getReturnType()) {match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());}}}}return match;}
{if (ObjectUtils.isEmpty(annotationsToSearch)) {return true;}SimpleTypeConverter typeConverter = new SimpleTypeConverter();for (Annotation annotation : annotationsToSearch) {Class<? extends Annotation> type = annotation.annotationType();boolean checkMeta = true;boolean fallbackToMeta = false;//有Qualifier注解才进行比较判断if (isQualifier(type)) {if (!checkQualifier(bdHolder, annotation, typeConverter)) {fallbackToMeta = true;}else {checkMeta = false;}}if (checkMeta) {boolean foundMeta = false;for (Annotation metaAnn : type.getAnnotations()) {Class<? extends Annotation> metaType = metaAnn.annotationType();if (isQualifier(metaType)) {foundMeta = true;// Only accept fallback match if @Qualifier annotation has a value...// Otherwise it is just a marker for a custom qualifier annotation.if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||!checkQualifier(bdHolder, metaAnn, typeConverter)) {return false;}}}if (fallbackToMeta && !foundMeta) {return false;}}}return true;}
至此,Spring针对 @Autowired 注解在五种不同的情况下进行依赖注入我们已经分析完毕
3. 结论
@Autowired 首先会通过 BeanFactoryUtils.beanNamesForTypeIncludingAncestors (递归获取父子BeanFactory调用getBeanNamesForType方法),根据需要进行依赖注入的字段的类型或者方法参数的类型取获取相应的beanName,如果注入的是非集合类型的对象,并且找到了一个以上的候选beanName,则下一步会去判断是否有标记优先级,如果都没有则会进行名称匹配,也就是将候选的beanName与字段名或参数名进行equals比较
byType -> 优先级比较 -> byName
相关文章:

Spring源码分析篇一 @Autowired 是怎样完成注入的?究竟是byType还是byName亦两者皆有
1. 五种不同场景下 Autowired 的使用 第一种情况 上下文中只有一个同类型的bean 配置类 package org.example.bean;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class FruitCo…...

Goby 漏洞发布|F5 BIG-IP AJP 身份认证绕过漏洞(CVE-2023-46747)
漏洞名称:F5 BIG-IP AJP 身份认证绕过漏洞(CVE-2023-46747) English Name:F5 BIG-IP AJP authentication bypass vulnerability (CVE-2023-46747) CVSS core: 10 影响资产数: 307282 漏洞描述: Cisco …...
Vue中watch侦听器用法
watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用 watch第一个参数监听源 watch第二个参数回调函数cb(newVal,oldVal) watch第三个参数一个options配置项是一个对象{ immediate:true //是否立即调用一次 deep:true //是否开启…...
[算法前沿]--054-大语言模型的学习材料
大语言模型的学习材料 Other Papers If you’re interested in the field of LLM, you may find the above list of milestone papers helpful to explore its history and state-of-the-art. However, each direction of LLM offers a unique set of insights and contribut…...
DWA算法,仿真转为C用于无人机避障
DWA算法,仿真转为C用于无人机避障 链接: 机器人局部避障的动态窗口法(dynamic window approach) 链接: 机器人局部避障的动态窗口法DWA (dynamic window approach)仿真源码详细注释版 链接: 常见路径规划算法代码-Matlab (纯代码篇) …...
现阶段的主流数据库分别是哪几种?
关系型数据库 1. MySQL数据库 MySQL是最受欢迎的开源SQL数据库管理系统,它由 MySQL AB开发、发布和支持。MySQL AB是一家基于MySQL开发人员的商业公司,它是一家使用了一种成功的商业模式来结合开源价值和方法论的第二代开源公司。MySQL是MySQL AB的注册商…...

“原生感”暴涨311%,这届年轻人不再爱浓妆?丨小红书数据分析
近年来,越来越多美妆博主在社交媒体平台安利“原生感妆容”,即我们所熟知的“伪素颜妆”、“裸妆”、“白开水妆”,显然,追求“原生感”成为当代妆容主流。通过小红书数据分析工具,查看#原生感妆容 话题,近…...

基于深度学习的植物识别算法 - cnn opencv python 计算机竞赛
文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习的植物识别算法 ** …...

k8s调度约束
List-Watch Kubernetes 是通过 List-Watch的机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦。 List-Watch机制 工作机制:用户通过 kubectl请求给 APIServer 来建立一个 Pod。APIServer会将Pod相关元信息存入 etcd 中…...

面经(面试经验)第一步,从自我介绍开始说起
看到一位同学讲自己的面试步骤和过程,我心有所感,故此想整理下面试的准备工作。以便大家能顺利应对面试,通过面试... 求职应聘找工作,面试是必然的关卡,如今竞争激烈呀,想要得到自己喜欢的工作,…...

S/4 HANA 中的 Email Template
1 如何创建Email Template? 没有特定的事务用于创建电子邮件模板,我们可以将其创建为 SE80 事务中的存储库对象,如下所示: 1,选择包(或本地对象)并右键单击。 2,选择“创建”->“更多”->“电子邮件模板” 尽管如此,对于已有的Email Template,可以使用程序…...
\r\n和\n的区别 回车/换行 在不同系统下的区别
文章目录 1 \r\n和\n的区别2 什么是 回车/换行3 \r\n和\n 故事 1 \r\n和\n的区别 \r\n和\n是两个常见的控制字符符号,它们在计算机领域中有着不同的作用和用途。 \r\n在Windows系统中被广泛使用,而\n在Unix和Linux系统中更为常见。 在Windows操作系统中…...

机械应用笔记
1. 螺纹转换头:又名金属塞头,例如M20-M16;适合于大小螺纹转换用; 2. 螺纹分英制和公制,攻丝同样也有英制和公制之分; 3. DB9头制作,M6.5的线,用M6.5的钻头扩线孔,在根…...

机房精密空调发生内部设备通信故障不一会压缩机就停止工作,怎么处理?
环境: 山特AT-DA810U 精密空调 问题描述: 机房精密空调发生内部设备通信故障不一会压缩机就停止工作,怎么处理? 回风处不显示温湿度 解决方案: 1.进入诊断模式工程师密码333333 看到压缩机关闭了,强制输出测试一下压缩机正常 2.尝试更换温湿度传感器模块网口,重启…...

手机端运维管理系统——图扑 HT for Web
随着信息技术的快速发展,网络技术的应用涉及到人们生活的方方面面。其中,手机运维管理系统可提供数字化、智能化的方式,帮助企业和组织管理监控企业的 IT 环境,提高运维效率、降低维护成本、增强安全性、提升服务质量,…...

中期科技:智慧公厕打造智能化城市设施,提升公共厕所管理与服务体验
智慧公厕是利用先进的技术和创新的解决方案来改进公厕的设施和管理。借助物联网、互联网、5G/4G通信、人工智能、大数据、云计算等新兴技术的集成,智慧公厕具备了一系列令人惊叹的应用功能。从监测公厕内部人体活动状态、人体存在状态,到空气质量情况、环…...

innovus: set_ccopt_property的基本用法
我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 clock route clock route的net type分为三种,分别是root、trunk和leaf,其中root是指fanout超过routing_top_fanout_count约束的net,leaf是指…...

打造美团外卖新体验,HarmonyOS SDK持续赋能开发者共赢鸿蒙生态
从今年8月起,所有升级到HarmonyOS 4的手机用户在美团外卖下单后,可通过屏幕上的一个“小窗口”,随时追踪到“出餐、取餐、送达”等订单状态。这个能让用户实时获悉订单进度的神奇“小窗口”,就是实况窗功能。 实况窗:简…...

Realtek 5G pcie网卡 RTL8126-CG简介
总shu:PCIE 5G网卡方案“RTL8126-CG”采用QFN56封装,面积8 x 8毫米,非常小巧,提供一个RJ-45网口、两个USB 3.x接口。它走的是PCIe 3.0 x1系统通道,搭配超五类网线,可以在长达100米的距离上提供满血的5Gbps网…...

新版Idea显示Git提交人信息
新版Idea的类和方法上会展示开发者信息 不想展示的话可以做以下配置:...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...