Spring中引入dubbo有多种方式,比如xml/api/config/annotation,以下以annotation进行探讨Spring中引入dubbo的细节:
首先从一个注解类开始:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.config.spring.context.annotation;
import com.alibaba.dubbo.config.AbstractConfig;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Enables Dubbo components as Spring Beans, equals
* {@link DubboComponentScan} and {@link EnableDubboConfig} combination.
* <p>
* Note : {@link EnableDubbo} must base on Spring Framework 4.2 and above
*
* @see DubboComponentScan
* @see EnableDubboConfig
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
/**
* Base packages to scan for annotated @Service classes.
* <p>
* Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
* @see DubboComponentScan#basePackages()
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
* @see DubboComponentScan#basePackageClasses
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
/**
* It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @see EnableDubboConfig#multiple()
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default false;
}
在注解类EnableDubbo中包含了两个注解的注解类,EnableDubboConfig和DubboComponentScan。
EnableDubboConfig分析
首先看一下对应的类定义
package com.alibaba.dubbo.config.spring.context.annotation;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.ModuleConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import org.springframework.context.annotation.Import;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* As a convenient and multiple {@link EnableDubboConfigBinding}
* in default behavior , is equal to single bean bindings with below convention prefixes of properties:
* <ul>
* <li>{@link ApplicationConfig} binding to property : "dubbo.application"</li>
* <li>{@link ModuleConfig} binding to property : "dubbo.module"</li>
* <li>{@link RegistryConfig} binding to property : "dubbo.registry"</li>
* <li>{@link ProtocolConfig} binding to property : "dubbo.protocol"</li>
* <li>{@link MonitorConfig} binding to property : "dubbo.monitor"</li>
* <li>{@link ProviderConfig} binding to property : "dubbo.provider"</li>
* <li>{@link ConsumerConfig} binding to property : "dubbo.consumer"</li>
* </ul>
* <p>
* In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be <code>true</code> :
* <ul>
* <li>{@link ApplicationConfig} binding to property : "dubbo.applications"</li>
* <li>{@link ModuleConfig} binding to property : "dubbo.modules"</li>
* <li>{@link RegistryConfig} binding to property : "dubbo.registries"</li>
* <li>{@link ProtocolConfig} binding to property : "dubbo.protocols"</li>
* <li>{@link MonitorConfig} binding to property : "dubbo.monitors"</li>
* <li>{@link ProviderConfig} binding to property : "dubbo.providers"</li>
* <li>{@link ConsumerConfig} binding to property : "dubbo.consumers"</li>
* </ul>
*
* @see EnableDubboConfigBinding
* @see DubboConfigConfiguration
* @see DubboConfigConfigurationSelector
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationSelector.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @revised 2.5.9
*/
boolean multiple() default false;
}
从注释中可以看出该类的目的就是将配置信息转换成类信息,比如:dubbo.application->ApplicationConfig.其中
com.alibaba.dubbo.config.ApplicationConfig为Dubbo中代表应用配置的类。另外注意到注解中Import了一个类型为DubboConfigConfigurationSelector的类,该类通过读取注解中的元数据进行选择所需要的类。查看该类:
/**
* Dubbo {@link AbstractConfig Config} Registrar
*
* @see EnableDubboConfig
* @see DubboConfigConfiguration
* @since 2.5.8
*/
public class DubboConfigConfigurationSelector implements ImportSelector, Ordered {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
if (multiple) {
return of(DubboConfigConfiguration.Multiple.class.getName());
} else {
return of(DubboConfigConfiguration.Single.class.getName());
}
}
private static <T> T[] of(T... values) {
return values;
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
针对ImportSelector的扩展分析:
ConfigurationClassParser.processConfigurationClass->doProcessConfigurationClass
ConfigurationClassParser是针对于注解了@Configuration类的解析,会从classpath中找到符合要求的类生成Bean注入到Spring容器中
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
首先会收集符合要求的@Import类
/**
* Returns {@code @Import} class, considering all meta-annotations.
*/
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
collectImports(sourceClass, imports, visited);
return imports;
}
最后会在processImports方法执行处理,
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
通过调用selector类的selectImports方法返回需要被注入的类信息,最后执行processImports操作。
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(currentSourceClass.getMetadata(),candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
由于DubboConfigConfigurationSelector是通过@Import引入的,所以Spring会将DubboConfigConfiguration类中的静态内部类Single或Multiple作为一个@Configuration类进行处理
public class DubboConfigConfiguration {
/**
* Single Dubbo {@link AbstractConfig Config} Bean Binding
*/
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class)
})
public static class Single {
}
DubboComponentScan分析
/**
* Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as
* Spring beans. Dubbo-provided {@link Service} and {@link Reference}.
*
* @see Service
* @see Reference
* @since 2.5.7
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
* {@code @DubboComponentScan(basePackages="org.my.pkg")}.
*
* @return the base packages to scan
*/
String[] value() default {};
/**
* Base packages to scan for annotated @Service classes. {@link #value()} is an
* alias for (and mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default {};
}
从注解可知,该类负责查找标注了Dubbo的注解@Service和@Reference,并注入为Spring的Bean.
真正的逻辑首先看DubboComponentScanRegistrar类:
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 1. 根据DubboComponentScan的注解获取需要扫描的包路径
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 2. 注册ServiceAnnotationBeanPostProcessor类来处理注解Service的类
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 3. 注册ReferenceAnnotationBeanPostProcessor类来处理注解Reference的类
registerReferenceAnnotationBeanPostProcessor(registry);
}
}
其中ServiceAnnotationBeanPostProcessor主要的逻辑如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
// 注册serviceBean
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
/**
* Registers Beans whose classes was annotated {@link Service}
*
* @param packagesToScan The base packages to scan
* @param registry {@link BeanDefinitionRegistry}
*/
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// Dubbo自定义的Bean定义扫描器
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// 解析BeanNameGenerator 用于解析Bean的名称
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 设置需要扫描的注解类型
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
// 遍历扫描路径进行扫描操作
for (String packageToScan : packagesToScan) {
// Registers @Service Bean first
scanner.scan(packageToScan);
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
registerServiceBean(beanDefinitionHolder, registry, scanner);
}
if (logger.isInfoEnabled()) {
logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]");
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
+ packageToScan + "]");
}
}
}
}
在上面被注册的bean的类型为ServiceBean。看一下ServiceBean的定义:
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware,ApplicationEventPublisherAware
这个ServiceBean实现了ApplicationContextAware、InitializingBean接口和ApplicationListener接口,在容器初始化的过程中会执行如下的逻辑:
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
// 此处会将上下文信息添加到SpringExtensionFactory中 当Dubbo通过SPI查找Bean的时候
// 方便查找Spring的Bean对象
SpringExtensionFactory.addApplicationContext(applicationContext);
if (applicationContext != null) {
SPRING_CONTEXT = applicationContext;
try {
// 兼容低版本的Spring 可忽略
Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1
method.invoke(applicationContext, new Object[]{this});
supportedApplicationListener = true;
} catch (Throwable t) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, new Object[]{this});
supportedApplicationListener = true;
} catch (Throwable t2) {
}
}
}
}
}
@Override
@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
// ... 省略其他代码 主要是进行各种配置的初始化
if (!isDelay()) {
// 非懒加载模式 在bean初始化之后就就行服务暴露
export();
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 如果是延迟发布模式 而且 当前Bean没有发布 而且 支持发布
// 在Spring容器启动完成之后 会触发容器刷新完成事件 此时会将当前的ServiceBean进行远程暴露
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
// 懒加载模式 在容器刷新完成服务暴露
export();
}
}
/**
* @since 2.6.5
*/
@Override
public void export() {
super.export();
// Publish ServiceBeanExportedEvent
publishExportEvent();
}
父类中的逻辑:
private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
public synchronized void export() {
if (provider != null) {
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
if (export != null && !export) {
return;
}
if (delay != null && delay > 0) {
delayExportExecutor.schedule(new Runnable() {
@Override
public void run() {
doExport();
}
}, delay, TimeUnit.MILLISECONDS);
} else {
doExport();
}
}
// 真正执行暴露操作
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
if (exported) {
return;
}
exported = true;
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
checkDefault();
if (provider != null) {
if (application == null) {
application = provider.getApplication();
}
if (module == null) {
module = provider.getModule();
}
if (registries == null) {
registries = provider.getRegistries();
}
if (monitor == null) {
monitor = provider.getMonitor();
}
if (protocols == null) {
protocols = provider.getProtocols();
}
}
if (module != null) {
if (registries == null) {
registries = module.getRegistries();
}
if (monitor == null) {
monitor = module.getMonitor();
}
}
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
try {
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
checkInterfaceAndMethods(interfaceClass, methods);
checkRef();
generic = Boolean.FALSE.toString();
}
if (local != null) {
if ("true".equals(local)) {
local = interfaceName + "Local";
}
Class<?> localClass;
try {
localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(localClass)) {
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
if (stub != null) {
if ("true".equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
checkApplication();
checkRegistry();
checkProtocol();
appendProperties(this);
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
// 执行暴露的方法
doExportUrls();
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
在doExportUrlsFor1Protocol方法中逻辑非常复杂,但最重要的逻辑如下:
// 获取SPI的AdptiveExtension 从ProxyFactory接口中标注了@SPI("javassist")可知默认采用的是
// javassist模式(静态代理)
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
// 通过动态代理来给真实的对象进行包装 所有的protocol都只面对Invoker类型对象
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// 通过协议对象导出Invoker对象
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
备注:通过ProxyFactory静态代理生成的代理对象定义(实际为字符串)如下所示:
public class Protocol$Adaptive2 implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
// 真正执行export方法时候 会根据协议的名称
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
// 通过SPI查找对应的协议实现类
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
// 通过查找的实现类进行暴露操作
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}
ReferenceAnnotationBeanPostProcessor(解析Reference注解)主要的逻辑如下:
@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception {
// 构建bean的名称
String referencedBeanName = buildReferencedBeanName(reference, injectedType);
// 构建bean定义
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
// 缓存bean定义
cacheInjectedReferenceBean(referenceBean, injectedElement);
// 生成代理类对象
Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
// 返回代理对象
return proxy;
}
父类AnnotationInjectedBeanPostProcessor:
/**
* 从对应注解中获取需要注入的对象
* Get injected-object from specified {@link A annotation} and Bean Class
*
* @param annotation {@link A annotation}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return An injected object
* @throws Exception If getting is failed
*/
protected Object getInjectedObject(A annotation, Object bean, String beanName, Class<?> injectedType,InjectionMetadata.InjectedElement injectedElement) throws Exception {
// 首先构建缓存主键
String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement);
// 获取缓存
Object injectedObject = injectedObjectsCache.get(cacheKey);
// 如果缓存对象不存在 则执行doGetInjectedBean的逻辑
if (injectedObject == null) {
injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
return injectedObject;
}
通过以上的方式进行ReferenceBean类型Bean的注入操作
ReferenceBean的定义如下:
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean
与ServiceBean相同的逻辑:
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
@Override
@SuppressWarnings({"unchecked"})
public void afterPropertiesSet() throws Exception {
// ... 省略大部分代码 进行一系列的解析操作
Boolean b = isInit();
if (b == null && getConsumer() != null) {
b = getConsumer().isInit();
}
if (b != null && b.booleanValue()) {
// 获取真实对象
getObject();
}
}
不同与ServiceBean的是,ReferenceBean是一个FactoryBean,当从容器中获取真实Bean的时候,会调取getObject方法
@Override
public Object getObject() throws Exception {
return get();
}
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("Already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
在init中会进行一系列的操作,主要部分如下:
// 创建代理
ref = createProxy(map);
ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods());
ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel);
在createProxy中主要部分如下:
if (urls.size() == 1) {
// 创建代理
invoker = refprotocol.refer(interfaceClass, urls.get(0));
} else {
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) {
invokers.add(refprotocol.refer(interfaceClass, url));
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // use last registry url
}
}
if (registryURL != null) { // registry url is available
// use AvailableCluster only when register's cluster is available
URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
invoker = cluster.join(new StaticDirectory(u, invokers));
} else { // not a registry url
invoker = cluster.join(new StaticDirectory(invokers));
}
}
总结:
- Spring容器在启动的过程中会查找@com.alibaba.dubbo.config.annotation.Service注解的类,并生成ServiceBean对象和com.alibaba.dubbo.config.annotation.Reference标注的属性或方法,生成ReferenceBean对象,然后注入到Spring容器中。
- 在Bean初始化或者Bean容器刷新完成的时候,会执行ServiceBean的暴露操作,通过代理工厂生成Invoker对象,然后通过protocol进行export操作,这样远程的客户端就可以进行服务调用了
- 对于ReferenceBean,在初始化或者通过getObject方法获取真实Bean对象时,也会生成代理对象并包装为Invoker对象,最后通过protocol.refer与远程服务进行拉通
- 注意:无论是客户端还是服务端都使用了代理设计模式,只有在发生真实调用的时候,才会真正执行对应业务类的逻辑,其他的时候都是操作代理类