正文
dubbo中有许多和SpringMVC相关的操作,这篇文章来探讨一下dubbo是如何利用SpringMVC的依赖注入机制完成bean的注入的。
首先我们知道,依赖注入是通过在配置文件中指定component-scan来确定的:
<context:component-scan base-package="com.xxxx.xxxx"/>
而SpringMVC里最终通过ContextNamespaceHandler这个类去注册了一个parse用来扫描“component-scan”。
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
public ContextNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
可以看到,通过ComponentScanBeanDefinitionParser这个类去解析。
public BeanDefinition parse(Element element, ParserContext parserContext) {
String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute("base-package"), ",; \t\n");
ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
可以看到它的parse方法,通过定义一个scanner去完成。这个scanner是ClassPathBeanDefinitionScanner。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
String[] var3 = basePackages;
int var4 = basePackages.length;
for(int var5 = 0; var5 < var4; ++var5) {
String basePackage = var3[var5];
Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
Iterator var8 = candidates.iterator();
while(var8.hasNext()) {
BeanDefinition candidate = (BeanDefinition)var8.next();
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = 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 = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
this.registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
我们看它的doScan方法。通过调用findCandidateComponents方法去扫描basePackage下的所有需要注入的类,转换成BeanDefinition。
public Set<BeanDefinition> 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);
} else if(debugEnabled) {
this.logger.debug("Ignored because not a concrete top-level class: " + resource);
}
} else if(traceEnabled) {
this.logger.trace("Ignored because not matching any filter: " + resource);
}
} catch (Throwable var13) {
throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var13);
}
} else if(traceEnabled) {
this.logger.trace("Ignored because not readable: " + resource);
}
}
return candidates;
} catch (IOException var14) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var14);
}
}
findCandidateComponents方法比较长。
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
其中这一句,就将basePackage下的类转换成了BeanDefinition。
至此,我们知道了SpringMVC是如何去扫描配置文件中的注入类的——通过定义对应的parser,将element转换成BeanDefinition。
dubbo中当然也有自己的parser:
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
public DubboNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
this.registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
}
可以看到,所有的节点都有自己的parser,将其进行转换。
上面的流程是将配置文件进行解析并转换保存,那么具体的注入是什么时候呢?
在SpringMVC的AbstractApplicationContext中的refresh方法里,SpringMVC会遍历之前注册的所有的BeanDefinition,并判断是否是懒加载的,如果不是,则调用getBean方法去初始化。最终会调用到AbstractAutowireCapableBeanFactory的doCreateBean方法。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = null;
if(mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if(instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper != null?instanceWrapper.getWrappedInstance():null;
Class<?> beanType = instanceWrapper != null?instanceWrapper.getWrappedClass():null;
Object var7 = 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, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = 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;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var17);
}
if(earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if(earlySingletonReference != null) {
if(exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if(!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if(!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if(!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(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);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
方法很长,我们先看这一句: