龙空技术网

dubbo中的SpringMVC依赖注入

菜根谭 375

前言:

此刻朋友们对“net mvc 依赖注入”可能比较关注,同学们都需要剖析一些“net mvc 依赖注入”的相关文章。那么小编同时在网上网罗了一些对于“net mvc 依赖注入””的相关内容,希望小伙伴们能喜欢,姐妹们一起来学习一下吧!

dubbo中的SpringMVC依赖注入

dubbo中有许多和SpringMVC相关的操作,这篇文章来探讨一下dubbo是如何利用SpringMVC的依赖注入机制完成bean的注入的。

首先我们知道,依赖注入是通过在配置文件中指定component-scan来确定的:

而SpringMVC里最终通过ContextNamespaceHandler这个类去注册了一个parse用来扫描“component-scan”。

publicclassContextNamespaceHandlerextendsNamespaceHandlerSupport{ publicContextNamespaceHandler() { } public void init() {this.registerBeanDefinitionParser("property-placeholder",newPropertyPlaceholderBeanDefinitionParser());this.registerBeanDefinitionParser("property-override",newPropertyOverrideBeanDefinitionParser());this.registerBeanDefinitionParser("annotation-config",newAnnotationConfigBeanDefinitionParser());this.registerBeanDefinitionParser("component-scan",newComponentScanBeanDefinitionParser());this.registerBeanDefinitionParser("load-time-weaver",newLoadTimeWeaverBeanDefinitionParser());this.registerBeanDefinitionParser("spring-configured",newSpringConfiguredBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-export",newMBeanExportBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-server",newMBeanServerBeanDefinitionParser()); }}

可以看到,通过ComponentScanBeanDefinitionParser这个类去解析。

publicBeanDefinition parse(Element element, ParserContext parserContext) { String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute("base-package"),",; \t\n"); ClassPathBeanDefinitionScanner scanner =this.configureScanner(parserContext, element); Set beanDefinitions = scanner.doScan(basePackages);this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);returnnull;}

可以看到它的parse方法,通过定义一个scanner去完成。这个scanner是ClassPathBeanDefinitionScanner。

protectedSet doScan(String... basePackages) { Assert.notEmpty(basePackages,"At least one base package must be specified");Set beanDefinitions =newLinkedHashSet();String[] var3 = basePackages;intvar4 = basePackages.length;for(intvar5 =0; var5 < var4; ++var5) {StringbasePackage = var3[var5];Set candidates =this.findCandidateComponents(basePackage);Iteratorvar8 = candidates.iterator();while(var8.hasNext()) { BeanDefinition candidate = (BeanDefinition)var8.next(); ScopeMetadata scopeMetadata =this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName());StringbeanName =this.beanNameGenerator.generateBeanName(candidate,this.registry);if(candidate instanceof AbstractBeanDefinition) {this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); }if(candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); }if(this.checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder =newBeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder,this.registry); beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry); } } }returnbeanDefinitions;}

我们看它的doScan方法。通过调用findCandidateComponents方法去扫描basePackage下的所有需要注入的类,转换成BeanDefinition。

publicSet findCandidateComponents(String basePackage) { LinkedHashSet candidates = new LinkedHashSet();try{ String packageSearchPath ="classpath*:"+this.resolveBasePackage(basePackage) +"/"+this.resourcePattern; Resource[] resources =this.resourcePatternResolver.getResources(packageSearchPath); boolean traceEnabled =this.logger.isTraceEnabled(); boolean debugEnabled =this.logger.isDebugEnabled(); Resource[] var7 = resources; int var8 = resources.length;for(int var9 =0; var9 < var8; ++var9) { Resource resource = var7[var9];if(traceEnabled) {this.logger.trace("Scanning "+ resource); }if(resource.isReadable()) {try{ MetadataReader metadataReader =this.metadataReaderFactory.getMetadataReader(resource);if(this.isCandidateComponent(metadataReader)) { ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource);if(this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {if(debugEnabled) {this.logger.debug("Identified candidate component class: "+ resource); } candidates.add(sbd); }elseif(debugEnabled) {this.logger.debug("Ignored because not a concrete top-level class: "+ resource); } }elseif(traceEnabled) {this.logger.trace("Ignored because not matching any filter: "+ resource); } }catch(Throwable var13) {thrownew BeanDefinitionStoreException("Failed to read candidate component class: "+ resource, var13); } }elseif(traceEnabled) {this.logger.trace("Ignored because not readable: "+ resource); } }returncandidates; }catch(IOException var14) {thrownew BeanDefinitionStoreException("I/O failure during classpath scanning", var14); }}

findCandidateComponents方法比较长。

ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

其中这一句,就将basePackage下的类转换成了BeanDefinition。

至此,我们知道了SpringMVC是如何去扫描配置文件中的注入类的——通过定义对应的parser,将element转换成BeanDefinition。

dubbo中当然也有自己的parser:

publicclassDubboNamespaceHandlerextendsNamespaceHandlerSupport{ publicDubboNamespaceHandler() { } public void init() {this.registerBeanDefinitionParser("application",newDubboBeanDefinitionParser(ApplicationConfig.class,true));this.registerBeanDefinitionParser("module",newDubboBeanDefinitionParser(ModuleConfig.class,true));this.registerBeanDefinitionParser("registry",newDubboBeanDefinitionParser(RegistryConfig.class,true));this.registerBeanDefinitionParser("monitor",newDubboBeanDefinitionParser(MonitorConfig.class,true));this.registerBeanDefinitionParser("provider",newDubboBeanDefinitionParser(ProviderConfig.class,true));this.registerBeanDefinitionParser("consumer",newDubboBeanDefinitionParser(ConsumerConfig.class,true));this.registerBeanDefinitionParser("protocol",newDubboBeanDefinitionParser(ProtocolConfig.class,true));this.registerBeanDefinitionParser("service",newDubboBeanDefinitionParser(ServiceBean.class,true));this.registerBeanDefinitionParser("reference",newDubboBeanDefinitionParser(ReferenceBean.class,false));this.registerBeanDefinitionParser("annotation",newDubboBeanDefinitionParser(AnnotationBean.class,true)); } static {Version.checkDuplicate(DubboNamespaceHandler.class); }}

可以看到,所有的节点都有自己的parser,将其进行转换。

上面的流程是将配置文件进行解析并转换保存,那么具体的注入是什么时候呢?

在SpringMVC的AbstractApplicationContext中的refresh方法里,SpringMVC会遍历之前注册的所有的BeanDefinition,并判断是否是懒加载的,如果不是,则调用getBean方法去初始化。最终会调用到AbstractAutowireCapableBeanFactory的doCreateBean方法。

protectedObjectdoCreateBean(finalStringbeanName,finalRootBeanDefinition mbd,Object[] args) { BeanWrapper instanceWrapper =null;if(mbd.isSingleton()) { instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName); }if(instanceWrapper ==null) { instanceWrapper =this.createBeanInstance(beanName, mbd, args); }finalObjectbean = instanceWrapper !=null?instanceWrapper.getWrappedInstance():null; Class beanType = instanceWrapper !=null?instanceWrapper.getWrappedClass():null;Objectvar7 = mbd.postProcessingLock; synchronized(mbd.postProcessingLock) {if(!mbd.postProcessed) {this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed =true; } } boolean earlySingletonExposure = mbd.isSingleton() &&this.allowCircularReferences &&this.isSingletonCurrentlyInCreation(beanName);if(earlySingletonExposure) {if(this.logger.isDebugEnabled()) {this.logger.debug("Eagerly caching bean '"+ beanName +"' to allow for resolving potential circular references"); }this.addSingletonFactory(beanName,newObjectFactory() { publicObjectgetObject() throws BeansException {returnAbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean); } }); }ObjectexposedObject = bean;try{this.populateBean(beanName, mbd, instanceWrapper);if(exposedObject !=null) { exposedObject =this.initializeBean(beanName, exposedObject, mbd); } }catch(Throwable var17) {if(var17 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var17).getBeanName())) {throw(BeanCreationException)var17; }thrownewBeanCreationException(mbd.getResourceDescription(), beanName,"Initialization of bean failed", var17); }if(earlySingletonExposure) {ObjectearlySingletonReference =this.getSingleton(beanName,false);if(earlySingletonReference !=null) {if(exposedObject == bean) { exposedObject = earlySingletonReference; }elseif(!this.allowRawInjectionDespiteWrapping &&this.hasDependentBean(beanName)) {String[] dependentBeans =this.getDependentBeans(beanName);Set actualDependentBeans =newLinkedHashSet(dependentBeans.length);String[] var12 = dependentBeans;intvar13 = dependentBeans.length;for(intvar14 =0; var14 < var13; ++var14) {StringdependentBean = var12[var14];if(!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } }if(!actualDependentBeans.isEmpty()) {thrownewBeanCurrentlyInCreationException(beanName,"Bean with name '"+ beanName +"' has been injected into other beans ["+ StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been "+"wrapped. This means that said other beans do not use the final version of the "+"bean. This is often the result of over-eager type matching - consider using "+"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } }try{this.registerDisposableBeanIfNecessary(beanName, bean, mbd);returnexposedObject; }catch(BeanDefinitionValidationException var16) {thrownewBeanCreationException(mbd.getResourceDescription(), beanName,"Invalid destruction signature", var16); }}

方法很长,我们先看这一句:

instanceWrapper= this.createBeanInstance(beanName, mbd, args);

创建一个wrapper,这里如果我们打断点就会发现,对于dubbo的bean来说,如果是引用的服务,最终创建出来的就是一个ReferenceBean了。

下面再来看:

this.populateBean(beanName, mbd, instanceWrapper);

在这个方法中,SpringMVC遍历注册的BeanPostProcessor,并调用其postProcessPropertyValues方法将已经生成的wrapper注入其中。

publicPropertyValuespostProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)throwsBeansException{ InjectionMetadata metadata =this.findAutowiringMetadata(beanName, bean.getClass());try{ metadata.inject(bean, beanName, pvs);returnpvs; }catch(Throwable var7) {thrownewBeanCreationException(beanName,"Injection of autowired dependencies failed", var7); }}

调用inject进行真正的注入。

前面我们说过,对于dubbo来说,每一个服务都会变成一个ReferenceBean,而ReferenceBean是实现了InitializingBean接口的,会在对应的afterPropertiesSet方法里进行初始化。

以上就是dubbo中的SpringMVC依赖注入,整套流程比较规范,通过定义parse解析自己的node,然后在对应的bean中通过实现InitializingBean接口在afterPropertiesSet进行初始化操作,一般的框架想要整合SpringMVC,都会这么做。

标签: #net mvc 依赖注入