2026/4/6 3:47:27
网站建设
项目流程
网站服务器 优帮云,如何制作一个网页网站,ps做网站要多大,中国采购与招标网官方网站day06-SpringDI 依赖注入
前言#xff1a;2026新年第一篇文章#xff0c;首先祝福大家#xff0c;马年大吉#xff0c;马年吉祥。开始继续编写源码…
1、依赖注入的流程2、寻找注入点
创建bean的过程中#xff0c;Spring会利用
org.springframework.beans.factory.annotat…day06-SpringDI 依赖注入前言2026新年第一篇文章首先祝福大家马年大吉马年吉祥。开始继续编写源码…1、依赖注入的流程2、寻找注入点创建bean的过程中Spring会利用org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata() 找出注入点并缓存遍历所有类的属性filed【字段扫描】查看Field上面是否存在Autowired、Value、Inject中注解任何一个如果 Field是static则不自动注入获取Autowired注入点的request的数值为true 构建AutowiredFieldElement 对象并添加到currElements里面遍历 当前类所有的方法 Method 【方法扫描】判断是否是桥接方法不是桥接方法直接返回是桥接方法检查是否缓存没有缓存进行查找收集声明类中所有方法名和参数数量与桥接方法相同的方法通过isBridgedCandidateFor方法过滤如果只有一个候选方法那么就是它如果有多个则通过searchCandidates方法进一步筛选如果没有找到桥接方法返回桥接方法本身判断当前方法Method是否存在Autowired、Value、Inject中注解任何一个如果方法不是statis则注入获取Autowired 中的required属性的值构建AutowiredMethodElement属性并添加到 currElements集合中private InjectionMetadatabuildAutowiringMetadata(final Class?clazz){// 如果一个Bean的类型是String...那么则根本不需要进行依赖注入if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){returnInjectionMetadata.EMPTY;}ListInjectionMetadata.InjectedElementelementsnew ArrayList();Class?targetClassclazz;do{final ListInjectionMetadata.InjectedElementcurrElementsnew ArrayList();// 遍历targetClass中的所有FieldReflectionUtils.doWithLocalFields(targetClass,field-{// field上是否存在Autowired、Value、Inject中的其中一个MergedAnnotation?annfindAutowiredAnnotation(field);if(ann!null){// static filed不是注入点不会进行自动注入if(Modifier.isStatic(field.getModifiers())){if(logger.isInfoEnabled()){logger.info(Autowired annotation is not supported on static fields: field);}return;}// 构造注入点boolean requireddetermineRequiredStatus(ann);currElements.add(newAutowiredFieldElement(field,required));}});// 遍历targetClass中的所有MethodReflectionUtils.doWithLocalMethods(targetClass,method-{Method bridgedMethodBridgeMethodResolver.findBridgedMethod(method);if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method,bridgedMethod)){return;}// method上是否存在Autowired、Value、Inject中的其中一个MergedAnnotation?annfindAutowiredAnnotation(bridgedMethod);if(ann!nullmethod.equals(ClassUtils.getMostSpecificMethod(method,clazz))){// static method不是注入点不会进行自动注入if(Modifier.isStatic(method.getModifiers())){if(logger.isInfoEnabled()){logger.info(Autowired annotation is not supported on static methods: method);}return;}// set方法最好有入参if(method.getParameterCount()0){if(logger.isInfoEnabled()){logger.info(Autowired annotation should only be used on methods with parameters: method);}}boolean requireddetermineRequiredStatus(ann);PropertyDescriptor pdBeanUtils.findPropertyForMethod(bridgedMethod,clazz);currElements.add(newAutowiredMethodElement(method,required,pd));}});// 父类的注入点会先处理插入表头elements.addAll(0,currElements);// 保证注入顺序父类字段方法 - 子类字段方法targetClasstargetClass.getSuperclass();}while(targetClass!nulltargetClass!Object.class);returnInjectionMetadata.forElements(elements,clazz);}关键特性1、继承层次扫描// 父类的注入点会先处理插入表头elements.addAll(0,currElements);// 保证注入顺序父类字段方法 - 子类字段方法targetClasstargetClass.getSuperclass();2、桥接方法处理// 为什么需要处理桥接方法// 1. 泛型方法在编译时会生成桥接方法// 2. 注解可能只存在于原始方法上// 3. 使用BridgeMethodResolver确保找到正确的注解方法Method bridgedMethodBridgeMethodResolver.findBridgedMethod(method);3、性能优化// 1. 预先过滤候选类避免不必要的扫描if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){returnInjectionMetadata.EMPTY;}// 2. 只扫描本地字段/方法父类在后续循环中处理ReflectionUtils.doWithLocalFields(targetClass,...)ReflectionUtils.doWithLocalMethods(targetClass,...)桥接interface ConverterS,T{Tconvert(S source);}public class StringToInteger implements ConverterString,Integer{Override public Integerconvert(String source){returnInteger.valueOf(source);}}字节码// class version 52.0 (52)// access flags 0x21// signature Ljava/lang/Object;Lcom/xx/service/ConverterLjava/lang/String;Ljava/lang/Integer;;// declaration: com/xxx/service/StringToInteger implements com.xxx.service.Converterjava.lang.String, java.lang.Integerpublic class com/xxx/service/StringToInteger implements com/xxx/service/Converter{// compiled from: StringToInteger.java// access flags 0x1publicinit()V L0 LINENUMBER3L0 ALOAD0INVOKESPECIAL java/lang/Object.init()V RETURN L1 LOCALVARIABLE this Lcom/xxxx/service/StringToInteger;L0 L10MAXSTACK1MAXLOCALS1// access flags 0x1publicconvert(Ljava/lang/String;)Ljava/lang/Integer;L0 LINENUMBER6L0 ALOAD1INVOKESTATIC java/lang/Integer.valueOf(Ljava/lang/String;)Ljava/lang/Integer;ARETURN L1 LOCALVARIABLE this Lcom/xxx/service/StringToInteger;L0 L10LOCALVARIABLE source Ljava/lang/String;L0 L11MAXSTACK1MAXLOCALS2// access flags 0x1041public synthetic bridgeconvert(Ljava/lang/Object;)Ljava/lang/Object;L0 LINENUMBER3L0 ALOAD0ALOAD1CHECKCAST java/lang/String INVOKEVIRTUAL com/xx/service/StringToInteger.convert(Ljava/lang/String;)Ljava/lang/Integer;ARETURN L1 LOCALVARIABLE this Lcom/xx/service/StringToInteger;L0 L10MAXSTACK2MAXLOCALS2}字节码有2个convertpublic convert(Ljava/lang/String;)Ljava/lang/Integer;public synthetic bridge convert(Ljava/lang/Object;)Ljava/lang/Object;spring当遍历桥接时候会找到原方法。3、Spring在AutowiredAnnotationBeanPostProcessor的postProcessProperties() 字段注入第一步遍历注入点进行注入属性填充阶段有入口org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties方法找到所有的注入点注入点找逻辑同上。第二步封装 DependencyDescriptor入口org.springframework.beans.factory.annotation.InjectionMetadata#inject核心代码如下DependencyDescriptor descnewDependencyDescriptor(field,this.required);desc.setContainingClass(bean.getClass());这里将Java反射的 Field 对象、以及 Autowired 的 required 属性等信息封装成一个DependencyDescriptor 对象。第三步 beanFactory.resolveDependency() 解析依赖入口org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Setjava.lang.String, org.springframework.beans.TypeConverter)核心方法valuebeanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter);解析流程resolveDependency() 方法会处理一些特殊类型比如Optional、ObjectFactroy或者ObjectProvider并且检查Lazy注解 如果没有特殊处理走 doResolveDependency() 方法 主要负责功能如下检查缓存通过descriptor.resolveShortcut(this);处理Value注解如果有使用则这里进行解析按照类型进行获取Beans调用findAutowireCandidates(beanName, type, descriptor) 获取所有匹配的数据确定唯一Bean如果找到多个则通过Primary、Priority 属性匹配规则确定唯一值MapString,ObjectmatchingBeansfindAutowireCandidates(beanName,type,descriptor);第四步创建缓存 ShortcutDependencyDescriptor解析完成后为了后续提高原型Bean的场景会进行缓存位置org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptorsynchronized(this){if(!this.cached){Object cachedFieldValuenull;if(value!null||this.required){cachedFieldValuedesc;// ... 注册依赖关系 ...if(autowiredBeanNames.size()1){String autowiredBeanNameautowiredBeanNames.iterator().next();if(beanFactory.containsBean(autowiredBeanName)beanFactory.isTypeMatch(autowiredBeanName,field.getType())){// 构建缓存cachedFieldValuenewShortcutDependencyDescriptor(desc,autowiredBeanName,field.getType());}}}this.cachedFieldValuecachedFieldValue;this.cachedtrue;}}逻辑判断如果(!this.cached) ,并且成功找到唯一 Bean 则会封装一个 ShortcutDependencyDescriptor 对象细节如下resolveShortcut 方法重写能够直接返回之前解析好的Bean的名称。privatestaticclass ShortcutDependencyDescriptor extends DependencyDescriptor{private final String shortcut;private final Class?requiredType;publicShortcutDependencyDescriptor(DependencyDescriptor original,String shortcut,Class?requiredType){super(original);this.shortcutshortcut;this.requiredTyperequiredType;}// 会对 resolveShortcut 方法重写Override public ObjectresolveShortcut(BeanFactory beanFactory){returnbeanFactory.getBean(this.shortcut,this.requiredType);}}第五步反射赋值查到到的 Bean实例反射设置到目标字段中。入口org.springframework.util.ReflectionUtils#makeAccessible(java.lang.reflect.Field)if(value!null){// 反射赋值ReflectionUtils.makeAccessible(field);field.set(bean,value);}字段和方法的区别统一入口地方org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject注入类型核心处理类依赖描述符封装来源字段注入AutowiredFieldElement直接由 Field 对象创建 DependencyDescriptor。方法注入AutowiredMethodElement遍历方法的每个参数为每个 MethodParameter 对象创建 DependencyDescriptor。SpringIOC容器的核心方法DefaultListableBeanFactory.doResolveDependency流程图。4、Resource 注解1、Autowired和Resource的区别AutowiredResource字段加static不会报错会报错IllegalStateException 异常包位置org.springframework.beans.factory.annotationjavax.annotation (Java EE)jakarta.annotation (Jakarta EE)默认的注入类型按类型byType按名称 (byName)是否必须requiredtrue (默认)总是必须名称指定需要结合 Qualifier使用 name 属性参数注入支持支持数据来源Spring 框架原生注解JSR-250 (Java 标准)2、Resource 执行流程如下--属性填充后 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties ↓ ↓--寻找注入点 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#buildResourceMetadata ↓ ↓--组装bean的名称bean的类型如果指定类型校验bean的类型 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#ResourceElement ↓ ↓--遍历每一个注入点 org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject ↓ ↓ org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject ↓ ↓ org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#autowireResource3、Resource流程图详解4、核心源码讲解/***factorySpring 容器负责查找和提供 Bean。*element 封装了被 Resource 注解的字段或方法的所有信息*requestingBeanName当前正在被注入的、发出依赖请求的那个 Bean 的名字。*/protected Object autowireResource(BeanFactory factory, LookupElement element, Nullable String requestingBeanName)throws NoSuchBeanDefinitionException {Object resource; SetString autowiredBeanNames; String name element.name; if (factory instanceof AutowireCapableBeanFactory) { AutowireCapableBeanFactory beanFactory (AutowireCapableBeanFactory) factory; DependencyDescriptor descriptor element.getDependencyDescriptor(); // 主要判断是否会退到按照类型查找 if (this.fallbackToDefaultTypeMatch element.isDefaultName !factory.containsBean(name)) { autowiredBeanNames new LinkedHashSet(); // 路径A根据类型查找 resource beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); if (resource null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), No resolvable resource object); } } else { // 路径B按照名称查找,如果有名称根据名称查找bean resource beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames Collections.singleton(name); } } else { resource factory.getBean(name, element.lookupType); autowiredBeanNames Collections.singleton(name); } if (factory instanceof ConfigurableBeanFactory) { ConfigurableBeanFactory beanFactory (ConfigurableBeanFactory) factory; for (String autowiredBeanName : autowiredBeanNames) { if (requestingBeanName ! null beanFactory.containsBean(autowiredBeanName)) { beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName); } } } return resource;}喜欢我的文章记得点个在看或者点赞持续更新中ing…