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的类和方法上会展示开发者信息 不想展示的话可以做以下配置:...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
