皮皮网

【jquery 源码】【小白源码站】【双六空间源码】inject源码

2024-12-27 15:14:15 来源:酒店pms+源码

1.学习vue源码(18)三探生命周期之初始化provide与inject
2.从源码层面带你实现一个自动注入注解
3.Vue 中 provide/inject 的源码应用
4.vue中的provide和inject

inject源码

学习vue源码(18)三探生命周期之初始化provide与inject

       在深入研究Vue源码()的学习中,我们重点关注了初始化阶段的源码生命周期钩子——initInjections和initProvide。这两个概念在created钩子函数触发前,源码beforeCreate钩子之后,源码为组件间的源码通信提供了重要手段。

       provide和inject是源码jquery 源码一对核心概念,它们的源码作用在于跨层级组件间的数据传递。父组件通过provide方法提供数据,源码而子组件则通过inject方法注入这些数据。源码它们解决了多级组件间数据共享的源码问题,避免了过多的源码$parent属性调用和代码结构的混乱。

       provide是源码小白源码站一个对象或返回对象的函数,通常包含子孙组件可注入的源码属性,可以使用ES6的源码Symbols作为键。而inject则接受字符串数组或对象,源码用于在本地绑定中查找并设置数据。通过实例,我们看到它们的工作原理:提供者通过vm._provided传递数据,消费者通过resolveInject方法查找并设置接收的数据。

       源码分析显示,provide将提供数据存储在Vue实例的全局数据中,而inject则在搜索到提供者的数据后,为这些数据设置getter和setter。双六空间源码在写inject时,通常需要为from属性指定的键或默认值,或者提供一个默认工厂方法。

       总的来说,理解并熟练运用provide和inject,是构建高效、可维护的Vue组件架构的关键。接下来,我们会详细研究initState,以全面探索Vue的初始化过程。

从源码层面带你实现一个自动注入注解

       首先,批发商城源码需要了解到的是。SpringBean的生命周期

       在生命周期中。注入bean属性的位置是在以下代码:populateBean位置中

       那么我们在项目中使用注解产生一个bean的时候必定会经过以下代码进行一个bean的创建流程

/**省略代码**///开始初始化bean实例对象ObjectexposedObject=bean;try{ //<5>对bean进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性populateBean(beanName,mbd,instanceWrapper);//<6>调用初始化方法exposedObject=initializeBean(beanName,exposedObject,mbd);}catch(Throwableex){ if(exinstanceofBeanCreationException&&beanName.equals(((BeanCreationException)ex).getBeanName())){ throw(BeanCreationException)ex;}else{ thrownewBeanCreationException(mbd.getResourceDescription(),beanName,"Initializationofbeanfailed",ex);}}/**省略代码**/

       在生命周期中populateBean进行填充bean数据。把其他依赖引入进来

       BeanPostProcessor是一个bean创建时候的一个钩子。

       以下代码是循环调用实现了BeanPostProcessor子类InstantiationAwareBeanPostProcessor#postProcessProperties方法

       Spring在以下代码中有自动注入的拓展点。关键就是实现InstantiationAwareBeanPostProcessor#postProcessProperties

/**省略代码**/for(BeanPostProcessorbp:getBeanPostProcessors()){ if(bpinstanceofInstantiationAwareBeanPostProcessor){ InstantiationAwareBeanPostProcessoribp=(InstantiationAwareBeanPostProcessor)bp;//对所有需要依赖检查的属性进行后处理PropertyValuespvsToUse=ibp.postProcessProperties(pvs,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ //从bw对象中提取PropertyDescriptor结果集//PropertyDescriptor:可以通过一对存取方法提取一个属性if(filteredPds==null){ filteredPds=filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);}pvsToUse=ibp.postProcessPropertyValues(pvs,filteredPds,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ return;}}pvs=pvsToUse;}}/**省略代码**/

       我们展开来讲一下@Autowired的实现是怎么样的吧:

       实现类为AutowiredAnnotationBeanPostProcessor.java

       从上面可以得知,填充bean的时候。时调用了方法ibp.postProcessPropertyValues()

       那么AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues()则会被调用

       调用findAutowiringMetadata获取class以及父类带有@Autowired或者@Value的产品销售源码属性或者方法:

/**省略代码**/publicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){ //获取所有可以注入的元数据InjectionMetadatametadata=findAutowiringMetadata(beanName,bean.getClass(),pvs);try{ //注入数据metadata.inject(bean,beanName,pvs);}catch(BeanCreationExceptionex){ throwex;}catch(Throwableex){ thrownewBeanCreationException(beanName,"Injectionofautowireddependenciesfailed",ex);}returnpvs;}privateInjectionMetadatafindAutowiringMetadata(StringbeanName,Class<?>clazz,@NullablePropertyValuespvs){ //缓存名字获取StringcacheKey=(StringUtils.hasLength(beanName)?beanName:clazz.getName());InjectionMetadatametadata=this.injectionMetadataCache.get(cacheKey);//获取是否已经读取过这个class类的InjectionMetadata有的话直接从缓存中获取出去if(InjectionMetadata.needsRefresh(metadata,clazz)){ synchronized(this.injectionMetadataCache){ //双重检查metadata=this.injectionMetadataCache.get(cacheKey);if(InjectionMetadata.needsRefresh(metadata,clazz)){ if(metadata!=null){ metadata.clear(pvs);}//构建自动注入的元数据metadata=buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey,metadata);}}}returnmetadata;}privateInjectionMetadatabuildAutowiringMetadata(finalClass<?>clazz){ if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){ returnInjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement>elements=newArrayList<>();Class<?>targetClass=clazz;do{ finalList<InjectionMetadata.InjectedElement>currElements=newArrayList<>();//循环targetClass的所有field并执FieldCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalFields(targetClass,field->{ //获得字段上面的Annotation注解MergedAnnotation<?>ann=findAutowiredAnnotation(field);if(ann!=null){ //判断是否为静态属性如果是,则不进行注入if(Modifier.isStatic(field.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticfields:"+field);}return;}//注解是否为必须依赖项booleanrequired=determineRequiredStatus(ann);currElements.add(newAutowiredFieldElement(field,required));}});//循环targetClass的所有Method并执MethodCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalMethods(targetClass,method->{ MethodbridgedMethod=BridgeMethodResolver.findBridgedMethod(method);if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method,bridgedMethod)){ return;}MergedAnnotation<?>ann=findAutowiredAnnotation(bridgedMethod);if(ann!=null&&method.equals(ClassUtils.getMostSpecificMethod(method,clazz))){ //判断是否为静态方法如果是,则不进行注入if(Modifier.isStatic(method.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticmethods:"+method);}return;}//判断静态方法参数是否为0if(method.getParameterCount()==0){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationshouldonlybeusedonmethodswithparameters:"+method);}}booleanrequired=determineRequiredStatus(ann);PropertyDescriptorpd=BeanUtils.findPropertyForMethod(bridgedMethod,clazz);currElements.add(newAutowiredMethodElement(method,required,pd));}});//数据加到数组最前方父类的的注解都放在靠前的位置elements.addAll(0,currElements);//如果有父类则设置targetClass为父类。如此循环targetClass=targetClass.getSuperclass();}while(targetClass!=null&&targetClass!=Object.class);returnInjectionMetadata.forElements(elements,clazz);}/**省略代码**/

       真正注入数据的是metadata.inject(bean,beanName,pvs);

       调用的是InjectionMetadata#inject方法

publicvoidinject(Objecttarget,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ Collection<InjectedElement>checkedElements=this.checkedElements;//带有注解的方法或者属性列表Collection<InjectedElement>elementsToIterate=(checkedElements!=null?checkedElements:this.injectedElements);if(!elementsToIterate.isEmpty()){ for(InjectedElementelement:elementsToIterate){ element.inject(target,beanName,pvs);}}}

       循环调用之前加入的带有注解的方法或者属性构建的对象AutowiredFieldElement#inject,AutowiredMethodElement#inject

/***属性上有注解构建的处理对象*/privateclassAutowiredFieldElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObjectcachedFieldValue;publicAutowiredFieldElement(Fieldfield,booleanrequired){ super(field,null);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //获取属性名Fieldfield=(Field)this.member;Objectvalue;//Bean不是单例的话,会重复进入注入的这个操作,if(this.cached){ try{ value=resolvedCachedArgument(beanName,this.cachedFieldValue);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvevalue=resolveFieldValue(field,bean,beanName);}}else{ //首次创建的时候进入该方法value=resolveFieldValue(field,bean,beanName);}if(value!=null){ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(field);field.set(bean,value);}}@NullableprivateObjectresolveFieldValue(Fieldfield,Objectbean,@NullableStringbeanName){ //构建DependencyDescriptor对象DependencyDescriptordesc=newDependencyDescriptor(field,this.required);desc.setContainingClass(bean.getClass());//注入bean的数量。有可能字段上是一个ListSet<String>autowiredBeanNames=newLinkedHashSet<>(1);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");//获得beanFactory类型转换类TypeConvertertypeConverter=beanFactory.getTypeConverter();Objectvalue;try{ //查找依赖关系value=beanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter);}catch(BeansExceptionex){ thrownewUnsatisfiedDependencyException(null,beanName,newInjectionPoint(field),ex);}synchronized(this){ if(!this.cached){ ObjectcachedFieldValue=null;if(value!=null||this.required){ cachedFieldValue=desc;//填入依赖关系registerDependentBeans(beanName,autowiredBeanNames);//判断如果注入依赖是只有一个if(autowiredBeanNames.size()==1){ StringautowiredBeanName=autowiredBeanNames.iterator().next();if(beanFactory.containsBean(autowiredBeanName)&&beanFactory.isTypeMatch(autowiredBeanName,field.getType())){ cachedFieldValue=newShortcutDependencyDescriptor(desc,autowiredBeanName,field.getType());}}}this.cachedFieldValue=cachedFieldValue;this.cached=true;}}returnvalue;}}/***方法上有注解构建的处理对象*/privateclassAutowiredMethodElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObject[]cachedMethodArguments;publicAutowiredMethodElement(Methodmethod,booleanrequired,@NullablePropertyDescriptorpd){ super(method,pd);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //检查属性是不会在之前就已经注入过了。如果主如果则不进行二次覆盖if(checkPropertySkipping(pvs)){ return;}Methodmethod=(Method)this.member;Object[]arguments;if(this.cached){ try{ arguments=resolveCachedArguments(beanName);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvearguments=resolveMethodArguments(method,bean,beanName);}}else{ //首次创建的时候进入该方法arguments=resolveMethodArguments(method,bean,beanName);}if(arguments!=null){ try{ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(method);//调用方法并传入参数method.invoke(bean,arguments);}catch(InvocationTargetExceptionex){ throwex.getTargetException();}}}@NullableprivateObject[]resolveCachedArguments(@NullableStringbeanName){ Object[]cachedMethodArguments=this.cachedMethodArguments;if(cachedMethodArguments==null){ returnnull;}Object[]arguments=newObject[cachedMethodArguments.length];for(inti=0;i<arguments.length;i++){ arguments[i]=resolvedCachedArgument(beanName,cachedMethodArguments[i]);}returnarguments;}@NullableprivateObject[]resolveMethodArguments(Methodmethod,Objectbean,@NullableStringbeanName){ //获取方法上有几个参数intargumentCount=method.getParameterCount();Object[]arguments=newObject[argumentCount];DependencyDescriptor[]descriptors=newDependencyDescriptor[argumentCount];Set<String>autowiredBeans=newLinkedHashSet<>(argumentCount);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");TypeConvertertypeConverter=beanFactory.getTypeConverter();for(inti=0;i<arguments.length;i++){ //方法参数,从方法参数中取出i构造MethodParameter对象MethodParametermethodParam=newMethodParameter(method,i);DependencyDescriptorcurrDesc=newDependencyDescriptor(methodParam,this.required);currDesc.setContainingClass(bean.getClass());descriptors[i]=currDesc;try{ //获取方法中i参数的内容Objectarg=beanFactory.resolveDependency(currDesc,beanName,autowiredBeans,typeConverter);if(arg==null&

Vue 中 provide/inject 的应用

       Vue框架提供了丰富的组件通信手段,如父子组件的props/$emit、EventBus以及Vuex的全局状态管理。然而,在众多选项中,provide/inject显得相对低调。然而,这项功能在特定情况下却有着独特的价值,那就是依赖注入的运用。

       provide/inject是Vue从2.2.0版引入的新特性,官方文档解释说,它允许祖先组件向所有后代组件注入依赖,这种关系不受组件层级影响。可以理解为一种“跨层级的全局prop”。

       实际应用中,provide/inject可以用来实现全局状态管理,尤其在项目协作中,当Vuex过于繁琐且需求仅限于共享全局状态时,它就派上用场。例如,通过在根组件中提供变量,后代组件可以直接使用,但需注意provide的非响应式特性,确保提供数据本身是可响应的。

       尽管$root可以访问根组件,但在多人协作中,提供/inject有助于避免全局变量冲突。每个模块的入口组件可以单独注入给子组件,保持模块独立性。然而,这并不是说Vuex被替代,因为Vuex的变更追踪功能是provide/inject所不具备的,它保证了数据修改的可追溯性,降低了耦合度。

       在组件设计中,Vue官方提倡使用provide/inject来编写组件,如在elementUI的表单和按钮组件中,通过注入上下文,可以解决层级关系不确定带来的强耦合问题。理解provide/inject的源码实现,如Vue^2.6.,可以帮助我们更好地利用这项功能。

       总结来说,provide/inject是Vue中的一个实用工具,它的价值取决于具体的应用场景。选择最符合项目需求的通信方式,才是最明智的做法。

vue中的provide和inject

        阅读element-ui源码,发现在设计子组时件用到了 inject 属性,随即查了一下 官方文档,得知vue在2.2.0版本里新增了 provide / inject :

        按照文档的描述,我的理解是:在多级嵌套的组件体系中,某级外层组件可以通过 provide 属性向其下任意一级子组件提供一个依赖,不管层级有多深;而某级子组件则可以通过 inject 属性接收来自其上任意一级父组件提供的依赖(通过 this.xxx 形式获取)。注意: provide 和 inject 需要一起使用。

        举个例子说明:

        清朝三位皇帝:康熙(玄烨)、雍正(胤禛)、乾隆(弘历)是祖孙三代,我们用vue组件的思想表示他们之间的关系,并模拟他们的一段对话,以此理解vue中的 provide 和 inject 。

        调用组件——大清帝国:qing-dynasty.vue

        定义爷爷组件——康熙皇帝:kangxi.vue

        定义儿子组件——雍正皇帝:yongzheng.vue

        定义孙子组件——乾隆:qianlong.vue