前言
紧接上文,dubbo 3服务注册源码分析,本文开始分析dubbo 3服务消费源码,消费端的源码相对注册端来说要更加复杂一些
首先需要了解以下,服务消费需要做哪些操作,本文从dubbo和springboot的结合开始分析
服务消费必须做的以下一些事情
- 扫描@DubboReference的字段,并把这些对象注入到spring中成为bean,后续其他字段无论使用@DubboReference还是@Autowird都能够注入对象
- 注入的对象在被调用时必定会发起一个远程RPC调用访问远程服务,这个就很容易想到必定是一个动态代理对象
本文以dubbo 3.0.6的源码来进行分析,需要对spring比较熟悉才能比较好的看懂源码逻辑,pom.xml核心依赖如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>3.0.6</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version><version>2.3.7.RELEASE</version></version>
<type>pom</type>
<scope>import</scope>
</dependency>
首先介绍下通过注解来注入某个远程接口对象可以如何配置
方式1,通过注入字段,不适合管理,不推荐
@DubboReference(
protocol = "dubbo",
loadbalance = "random",
cluster = "failover",check = false,retries = 5)
private SayHelloService sayHelloService;
方式2,通过注入到方法的参数中,适合管理,在某个配置文件统一管理所有bean,在需要使用的地方使用@Autowird注入即可
@DubboReference(
protocol = "dubbo",
loadbalance = "random",
timeout = 500,
cluster = "failfast",check = false,retries = 5)
public SayHelloService sayHelloService(SayHelloService sayHelloService) {
return sayHelloService;
}
服务消费源码
服务消费者如果不需要暴露的话,是不需要加@DubboComponentScan注解的,那么它是如何启动的呢?
这里就使用到了springboot的自动装配机制,可以在jar包下找到自动装配的关键类DubboAutoConfiguration
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration {
/**
* Creates {@link ServiceAnnotationPostProcessor} Bean
*
* @param packagesToScan the packages to scan
* @return {@link ServiceAnnotationPostProcessor}
*/
@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
@Bean
public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
Set<String> packagesToScan) {
return new ServiceAnnotationPostProcessor(packagesToScan);
}
}
看@EnableDubboConfig注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>true</code>
* @revised 2.5.9
*/
boolean multiple() default true;
}
看@Import(DubboConfigConfigurationRegistrar.class),都是spring的扩展机制
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// initialize dubbo beans
DubboSpringInitializer.initialize(registry);
}
}
这里就一行关键代码,initialize方法
public static void initialize(BeanDefinitionRegistry registry) {
// Spring ApplicationContext may not ready at this moment (e.g. load from xml), so use registry as key
if (contextMap.putIfAbsent(registry, new DubboSpringInitContext()) != null) {
return;
}
// prepare context and do customize
DubboSpringInitContext context = contextMap.get(registry);
// find beanFactory
ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
// init dubbo context
// 核心代码
initContext(context, registry, beanFactory);
}
这个方法在服务注册源码时也看到过
private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory) {
context.setRegistry(registry);
context.setBeanFactory(beanFactory);
// customize context, you can change the bind module model via DubboSpringInitCustomizer SPI
customize(context);
// init ModuleModel
ModuleModel moduleModel = context.getModuleModel();
if (moduleModel == null) {
ApplicationModel applicationModel;
if (findContextForApplication(ApplicationModel.defaultModel()) == null) {
// first spring context use default application instance
applicationModel = ApplicationModel.defaultModel();
logger.info("Use default application: " + safeGetModelDesc(applicationModel));
} else {
// create an new application instance for later spring context
applicationModel = FrameworkModel.defaultModel().newApplication();
logger.info("Create new application: " + safeGetModelDesc(applicationModel));
}
// init ModuleModel
moduleModel = applicationModel.getDefaultModule();
context.setModuleModel(moduleModel);
logger.info("Use default module model of target application: " + safeGetModelDesc(moduleModel));
} else {
logger.info("Use module model from customizer: " + safeGetModelDesc(moduleModel));
}
logger.info("Bind " + safeGetModelDesc(moduleModel) + " to spring container: " + ObjectUtils.identityToString(registry));
// set module attributes
if (context.getModuleAttributes().size() > 0) {
context.getModuleModel().getAttributes().putAll(context.getModuleAttributes());
}
// bind dubbo initialization context to spring context
registerContextBeans(beanFactory, context);
// mark context as bound
context.markAsBound();
// register common beans
// 核心方法
DubboBeanUtils.registerCommonBeans(registry);
}
registerCommonBeans方法
static void registerCommonBeans(BeanDefinitionRegistry registry) {
registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
// 核心代码
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
ReferenceAnnotationBeanPostProcessor.class);
// TODO Whether DubboConfigAliasPostProcessor can be removed ?
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
DubboConfigAliasPostProcessor.class);
// Since 2.7.4 Register DubboBootstrapApplicationListener as an infrastructure Bean
// registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME,
// DubboBootstrapApplicationListener.class);
// register ApplicationListeners
registerInfrastructureBean(registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);
registerInfrastructureBean(registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);
// Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
// Dubbo config initializer
registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
// register infra bean if not exists later
registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
}
这里关注ReferenceAnnotationBeanPostProcessor这个PostProcessor
public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor
implements ApplicationContextAware, BeanFactoryPostProcessor {
......
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedFieldReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private ApplicationContext applicationContext;
private ReferenceBeanManager referenceBeanManager;
private BeanDefinitionRegistry beanDefinitionRegistry;
// 核心代码1
public ReferenceAnnotationBeanPostProcessor() {
super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
Class<?> beanType;
if (beanFactory.isFactoryBean(beanName)){
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (isReferenceBean(beanDefinition)) {
continue;
}
if (isAnnotatedReferenceBean(beanDefinition)) {
// process @DubboReference at java-config @bean method
processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);
continue;
}
String beanClassName = beanDefinition.getBeanClassName();
// if (beanDefinition instanceof AnnotatedBeanDefinition) {
// AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
// beanClassName = annotatedBeanDefinition.getFactoryMethodMetadata().getDeclaringClassName();
// }
beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());
} else {
beanType = beanFactory.getType(beanName);
}
if (beanType != null) {
// 核心代码2
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
try {
// 核心代码3
prepareInjection(metadata);
} catch (BeansException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
......
首先核心代码1处有几个注解,这个就是消费者需要去扫描的一些注解,有DubboReference,以及apache的Reference和alibaba的Reference,这里推荐使用DubboReference,这里会设置到父类的一个annotationTypes中
核心代码2,findInjectionMetadata方法,注意这里是在一个beanNames的循环中,beanNames是现在spring中所有的bean,也就是要开始扫描这些bean里面需要扫描的字段或者方法了
protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (needsRefreshInjectionMetadata(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (needsRefreshInjectionMetadata(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
// 核心代码
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
"] for annotation metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
buildAnnotatedMetadata方法
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements
= findFieldAnnotationMetadata(beanClass);
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements
= findAnnotatedMethodMetadata(beanClass);
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
这里看方法名可以猜测一个是针对字段的,另外一个是针对方法的,获取到的数据最终组合为了一个AnnotatedInjectionMetadata返回
这里就看一个findFieldAnnotationMetadata方法把
private List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 前面保存的三个要扫描的注解
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
// 获取注解上的属性
AnnotationAttributes attributes = getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);
if (attributes != null) {
// 如果能获取到属性对象AnnotationAttributes,那么说明有我们需要扫描的注解存在
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
}
return;
}
// 最终加到list elements中返回
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
}
});
return elements;
}
针对方法的也是一样,这里就是针对我们上述分析的两种使用情况来做了不同处理
接下来看上面的核心代码3,prepareInjection(metadata)
protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {
try {
//find and register bean definition for @DubboReference/@Reference
// 针对字段,进行遍历
for (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {
if (fieldElement.injectedObject != null) {
continue;
}
// 只有上面扫描到我们注解的,这里才能继续,否则在上面就continue了
Class<?> injectedType = fieldElement.field.getType();
AnnotationAttributes attributes = fieldElement.attributes;
// 核心方法
String referenceBeanName = registerReferenceBean(fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);
//associate fieldElement and reference bean
fieldElement.injectedObject = referenceBeanName;
injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);
}
// 这个是针对方法的,和上面类似
for (AnnotatedMethodElement methodElement : metadata.getMethodElements()) {
if (methodElement.injectedObject != null) {
continue;
}
Class<?> injectedType = methodElement.getInjectedType();
AnnotationAttributes attributes = methodElement.attributes;
String referenceBeanName = registerReferenceBean(methodElement.getPropertyName(), injectedType, attributes, methodElement.method);
//associate fieldElement and reference bean
methodElement.injectedObject = referenceBeanName;
injectedMethodReferenceBeanCache.put(methodElement, referenceBeanName);
}
} catch (ClassNotFoundException e) {
throw new BeanCreationException("prepare reference annotation failed", e);
}
}
public String registerReferenceBean(String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member) throws BeansException {
。。。。。。
// Register the reference bean definition to the beanFactory
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(ReferenceBean.class.getName());
beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);
// set attribute instead of property values
beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);
beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);
// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean
// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()
GenericBeanDefinition targetDefinition = new GenericBeanDefinition();
targetDefinition.setBeanClass(interfaceClass);
String id = getPropertyValue(beanDefinition.getPropertyValues(), ReferenceAttributes.ID);
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, id+"_decorated"));
// signal object type since Spring 5.2
beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
logger.info("Register dubbo reference bean: "+referenceBeanName+" = "+referenceKey+" at "+member);
return referenceBeanName;
}
这个方法很长,只关注核心逻辑即可,核心逻辑就是注册了一个beanDefinition,设置了它的beanClass=ReferenceBean,并且设置了一些注解上的属性,设置了接口的类型等,最终注册到spring中,然后这里就结束了
然后又spring来初始化这些beanDefinition,加载为spring的bean
所以要看ReferenceBean
public class ReferenceBean<T> implements FactoryBean<T>,
ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {
private transient ApplicationContext applicationContext;
private ClassLoader beanClassLoader;
// lazy proxy of reference
private Object lazyProxy;
......
@Override
public T getObject() {
if (lazyProxy == null) {
createLazyProxy();
}
return (T) lazyProxy;
}
......
ReferenceBean实现了spring的FactoryBean,那么在实例化到ioc容器时会使用它的getObject方法获取对象,所有要看createLazyProxy是如何初始化对象的
这里中间还有一个关键逻辑,由于ReferenceAnnotationBeanPostProcessor继承了InstantiationAwareBeanPostProcessor,所以在Bean进行依赖注入的过程中所有bean都会调用搭配ReferenceAnnotationBeanPostProcessor的postProcessPropertyValues
ReferenceAnnotationBeanPostProcessor的postProcessPropertyValues
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
try {
// 这两行之前执行过了,在这里会被判断有缓存了而过滤
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
prepareInjection(metadata);
// 核心代码
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
从之前缓存中拿到了metadata,调用inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 拿到当前bean,所有需要注入的属性,因为上面对@DubboReference注解的字段做了处理,所以这里可以取到
// 所有加了@DubboReference的字段
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
// 所有这些字段调用inject
element.inject(target, beanName, pvs);
}
}
}
调用到AnnotatedInjectElement的inject
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
// 核心1
Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);
// 核心2
if (member instanceof Field) {
Field field = (Field) member;
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
} else if (member instanceof Method) {
Method method = (Method) member;
ReflectionUtils.makeAccessible(method);
method.invoke(bean, injectedObject);
}
}
核心1调用到AbstractAnnotationBeanPostProcessor的getInjectedObject
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
return doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
}
模板方法又调用到了ReferenceAnnotationBeanPostProcessor的doGetInjectedBean
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
if (injectedElement.injectedObject == null) {
throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");
}
// 从spring的beanFactory中获取要注入的对象,此时我们要注入的@DubboReference对象还没初始化,所以会进行初始化到ioc容器
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
最终从这里可以拿到要注入的实例,然后调用核心2处针对字段或者针对方法的反射注入实例
到这里为止,完成了这些逻辑
- 对bean中加了@DubboReference的字段、方法进行扫描
- 扫描后注册到了spring容器中,后续都可以使用@Autowird注入
- 对bean中加了@DubboReference的字段,完成了属性的赋值
解下来就要看@DubboReference的对象是如何实例化的,也就是ReferenceBean的getObject方法
public T getObject() {
if (lazyProxy == null) {
createLazyProxy();
}
return (T) lazyProxy;
}
createLazyProxy
private void createLazyProxy() {
//set proxy interfaces
//see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
ProxyFactory proxyFactory = new ProxyFactory();
// 核心1
proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
proxyFactory.addInterface(interfaceClass);
Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
for (Class<?> anInterface : internalInterfaces) {
proxyFactory.addInterface(anInterface);
}
if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
//add service interface
try {
Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
proxyFactory.addInterface(serviceInterface);
} catch (ClassNotFoundException e) {
// generic call maybe without service interface class locally
}
}
// 核心2
this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}
这里先看核心2,获得了一个对象
public Object getProxy(@Nullable ClassLoader classLoader) {
return this.createAopProxy().getProxy(classLoader);
}
会进入JdkDynamicAopProxy的getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 核心
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
jdk的动态代理,也就是生成一个动态代理对象,调用后会执行InvocationHandler的invoke方法,这里的invoker就是JdkDynamicAopProxy对象
JdkDynamicAopProxy的invoke方法
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
Object retVal;
try {
。。。。。。
// 核心代码
retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
return retVal;
}
invokeJoinpointUsingReflection方法
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable {
try {
ReflectionUtils.makeAccessible(method);
// 根据对象target,方法method,参数args进行反射调用,所以这里的target很关键
return method.invoke(target, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", var5);
} catch (IllegalAccessException var6) {
throw new AopInvocationException("Could not access method [" + method + "]", var6);
}
}
这里核心代码的this.advised就是就是上面核心1创建的DubboReferenceLazyInitTargetSource对象,所以要看DubboReferenceLazyInitTargetSource
private class DubboReferenceLazyInitTargetSource extends AbstractLazyCreationTargetSource {
@Override
protected Object createObject() throws Exception {
return getCallProxy();
}
@Override
public synchronized Class<?> getTargetClass() {
return getInterfaceClass();
}
}
这个一看名字就可以猜到是一个延迟初始化的对象,应该是第一次调用的时候才初始化,就要看createObject方法了
private Object getCallProxy() throws Exception {
if (referenceConfig == null) {
throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");
}
//get reference proxy
// 核心
return referenceConfig.get();
}
public T get() {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
if (ref == null) {
// ensure start module, compatible with old api usage
getScopeModel().getDeployer().start();
synchronized (this) {
if (ref == null) {
init();
}
}
}
return ref;
}
这里返回的ref对象,通过一个双重检查锁来进行初始化ref,肯定是在init方法中初始化的
protected synchronized void init() {
if (initialized) {
return;
}
initialized = true;
if (!this.isRefreshed()) {
this.refresh();
}
// init serviceMetadata
initServiceMetadata(consumer);
serviceMetadata.setServiceType(getServiceInterfaceClass());
// TODO, uncomment this line once service key is unified
serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
Map<String, String> referenceParameters = appendConfig();
// init service-application mapping
initServiceAppsMapping(referenceParameters);
ModuleServiceRepository repository = getScopeModel().getServiceRepository();
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
consumerModel = new ConsumerModel(serviceMetadata.getServiceKey(), proxy, serviceDescriptor, this,
getScopeModel(), serviceMetadata, createAsyncMethodInfo());
repository.registerConsumer(consumerModel);
serviceMetadata.getAttachments().putAll(referenceParameters);
// 核心代码
ref = createProxy(referenceParameters);
serviceMetadata.setTarget(ref);
serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);
consumerModel.setProxyObject(ref);
consumerModel.initMethodModels();
checkInvokerAvailable();
}
ref = createProxy(referenceParameters);
private T createProxy(Map<String, String> referenceParameters) {
if (shouldJvmRefer(referenceParameters)) {
createInvokerForLocal(referenceParameters);
} else {
urls.clear();
if (StringUtils.isNotEmpty(url)) {
// user specified URL, could be peer-to-peer address, or register center's address.
parseUrl(referenceParameters);
} else {
// if protocols not in jvm checkRegistry
if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
aggregateUrlFromRegistry(referenceParameters);
}
}
// 核心1
createInvokerForRemote();
}
if (logger.isInfoEnabled()) {
logger.info("Referred dubbo service: [" + referenceParameters.get(INTERFACE_KEY) + "]." +
(Boolean.parseBoolean(referenceParameters.get(GENERIC_KEY)) ?
" it's GenericService reference" : " it's not GenericService reference"));
}
URL consumerUrl = new ServiceConfigURL(CONSUMER_PROTOCOL, referenceParameters.get(REGISTER_IP_KEY), 0,
referenceParameters.get(INTERFACE_KEY), referenceParameters);
consumerUrl = consumerUrl.setScopeModel(getScopeModel());
consumerUrl = consumerUrl.setServiceModel(consumerModel);
MetadataUtils.publishServiceDefinition(consumerUrl, consumerModel.getServiceModel(), getApplicationModel());
// create service proxy
// 核心2
return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
}
核心2处进行了返回对象,又通过了动态代理生成了对象,proxyFactory 的初始化如下,是一个自适应spi,
proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
这里一般url太会进行设置,一般会使用默认的JavassistProxyFactory代理工厂生成对象
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
try {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
} catch (Throwable fromJavassist) {
// try fall back to JDK proxy factory
try {
T proxy = jdkProxyFactory.getProxy(invoker, interfaces);
logger.error("Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. " +
"Interfaces: " + Arrays.toString(interfaces), fromJavassist);
return proxy;
} catch (Throwable fromJdk) {
logger.error("Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + Arrays.toString(interfaces) + " Javassist Error.", fromJavassist);
logger.error("Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + Arrays.toString(interfaces) + " JDK Error.", fromJdk);
throw fromJavassist;
}
}
}
这里又使用了jdk的动态代理,而这次的InvocationHandler是一个InvokerInvocationHandler对象
InvokerInvocationHandler的invoker方法,这个方法已经快接近远程调用的发起了
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
。。。。。。
// 核心1,构建远程调用的几个核心参数对象,方法、接口、参数
RpcInvocation rpcInvocation = new RpcInvocation(serviceModel, method, invoker.getInterface().getName(), protocolServiceKey, args);
String serviceKey = url.getServiceKey();
rpcInvocation.setTargetServiceUniqueName(serviceKey);
。。。。。。
try {
// 核心2
return invoker.invoke(rpcInvocation).recreate();
} finally {
。。。。。。
}
核心2,调用invoker的invoke方法,传入一个rpcInvocation
那么这个invoker对象就是最后要分析的了,是从上面的方法传进来的
这里的invoker在上述没看到初始化,肯定就是在核心1的createInvokerForRemote方法里面了
private void createInvokerForRemote() {
if (urls.size() == 1) {
URL curUrl = urls.get(0);
invoker = protocolSPI.refer(interfaceClass, curUrl);
if (!UrlUtils.isRegistry(curUrl)) {
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(invoker);
invoker = Cluster.getCluster(scopeModel, Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true);
}
} else {
// 核心1
List<Invoker<?>> invokers = new ArrayList<>();
URL registryUrl = null;
for (URL url : urls) {
// For multi-registry scenarios, it is not checked whether each referInvoker is available.
// Because this invoker may become available later.
// 核心2
invokers.add(protocolSPI.refer(interfaceClass, url));
if (UrlUtils.isRegistry(url)) {
// use last registry url
registryUrl = url;
}
}
if (registryUrl != null) {
// registry url is available
// for multi-subscription scenario, use 'zone-aware' policy by default
String cluster = registryUrl.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
// The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker
// (RegistryDirectory, routing happens here) -> Invoker
// 核心3
invoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false).join(new StaticDirectory(registryUrl, invokers), false);
} else {
// not a registry url, must be direct invoke.
if (CollectionUtils.isEmpty(invokers)) {
throw new IllegalArgumentException("invokers == null");
}
URL curUrl = invokers.get(0).getUrl();
String cluster = curUrl.getParameter(CLUSTER_KEY, Cluster.DEFAULT);
invoker = Cluster.getCluster(scopeModel, cluster).join(new StaticDirectory(curUrl, invokers), true);
}
}
}
最上面判断了urls的长度,这个urls是指有几个注册中心上有服务,因为dubbo是支持多注册中心的,那么多个注册中心是不是也需要负载均衡呢,这个逻辑就体现在这里
我们假设有两个注册中心,一个zookeeper一个nacos吧,所以会走下面这个else
核心2的代码逻辑是循环所有url,然后构造了invoker加入到一个invoker列表中,这个详细逻辑等会再看
先看核心3,从一个注册中心的url中取cluster参数,这里随便取一个就行,因为多个注册中心的容错机制肯定要设置为一样,这里取到某一个容错的实现Cluster后,假设是默认的FailoverCluster,执行join方法,会执行到父类的join
@Override
public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
if (buildFilterChain) {
return buildClusterInterceptors(doJoin(directory));
} else {
// 核心
return doJoin(directory);
}
}
模板方法回调到FailoverCluster
@Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new FailoverClusterInvoker<>(directory);
}
也就是这里最终的invoker是FailoverClusterInvoker(StaticDirectory),而StaticDirectory中保护了两个invoker,分别是不同的注册中心
也就是生成的动态代理对象,被调用后会先通过JdkDynamicAopProxy的invoke方法,然后调用到又一个动态代理的InvokerInvocationHandler的invoker方法,最后在InvokerInvocationHandler找到了FailoverClusterInvoker,调用它的invoke方法
FailoverClusterInvoker方法没有符合参数要求的invoke方法,所以会调用父类AbstractClusterInvoker的invoke
@Override
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Router route.");
// 核心1,获取所有invoke,之前是两个注册中心,所以是两个
List<Invoker<T>> invokers = list(invocation);
InvocationProfilerUtils.releaseDetailProfiler(invocation);
// 核心2,获得负载均衡LoadBalance
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Cluster " + this.getClass().getName() + " invoke.");
try {
// 核心3
return doInvoke(invocation, invokers, loadbalance);
} finally {
InvocationProfilerUtils.releaseDetailProfiler(invocation);
}
}
核心2处获得负载均衡LoadBalance
protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(invocation.getModuleModel());
if (CollectionUtils.isNotEmpty(invokers)) {
// 核心,根据url中的key=loadbalance,选择到一个符合要求的loadbalance实现类
return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(
invokers.get(0).getUrl().getMethodParameter(
RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE
)
);
} else {
return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);
}
}
核心3,模板方法调用到FailoverClusterInvoker的doInvoke,并且传递了负载均衡对象loadbalance
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation);
String methodName = RpcUtils.getMethodName(invocation);
// 核心1,获取重试次数+1
int len = calculateInvokeTimes(methodName);
// retry loop.
RpcException le = null; // last exception.
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
Set<String> providers = new HashSet<String>(len);
// 根据重试次数+1,进行循环调用,可以发现里面做了try catch但是不会中断循环,也就是失败了会循环再次调用,
// 这里就是failover的逻辑,失败重试
for (int i = 0; i < len; i++) {
//Reselect before retry to avoid a change of candidate `invokers`.
//NOTE: if `invokers` changed, then `invoked` also lose accuracy.
if (i > 0) {
checkWhetherDestroyed();
copyInvokers = list(invocation);
// check again
checkInvokers(copyInvokers, invocation);
}
// 核心3
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
invoked.add(invoker);
RpcContext.getServiceContext().setInvokers((List) invoked);
boolean success = false;
try {
// 核心4
Result result = invokeWithContext(invoker, invocation);
if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName()
+ " was successful by the provider " + invoker.getUrl().getAddress()
+ ", but there have been failed providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le);
}
success = true;
return result;
} catch (RpcException e) {
if (e.isBiz()) { // biz exception.
throw e;
}
le = e;
} catch (Throwable e) {
le = new RpcException(e.getMessage(), e);
} finally {
if (!success) {
providers.add(invoker.getUrl().getAddress());
}
}
}
throw new RpcException(le.getCode(), "Failed to invoke the method "
+ methodName + " in the service " + getInterface().getName()
+ ". Tried " + len + " times of the providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Last error is: "
+ le.getMessage(), le.getCause() != null ? le.getCause() : le);
}
核心3,负载均衡策略选择需要调用的invoker对象,这里会进行剔除调用过的invoker,优先重试没有调用过的invoker,就不详细看了,最终肯定会使用loadbalance.select方法进行选择
核心4,invokeWithContext
protected Result invokeWithContext(Invoker<T> invoker, Invocation invocation) {
setContext(invoker);
Result result;
try {
if (ProfilerSwitch.isEnableSimpleProfiler()) {
InvocationProfilerUtils.enterProfiler(invocation, "Invoker invoke. Target Address: " + invoker.getUrl().getAddress());
}
result = invoker.invoke(invocation);
} finally {
clearContext(invoker);
InvocationProfilerUtils.releaseSimpleProfiler(invocation);
}
return result;
}
这里的调用链路太长,没办法分析了,大概流程是这样的
首先是一个FailoverClusterInvoker进行注册中心的负载均衡,选择一个注册中心的invoker对象,然后这个invoker最终会再次执行到一个Cluster的invoker,因为同一个注册中心下可以有多个实例,也需要进行容错和负载均衡,所有默认会再次执行到一个FailoverClusterInvoker进行容错和负载均衡,最终选择到一个实例的invoker对象,最底层是基于协议的invoker,是一个dubbo invoker,大概流程有这么一个图
所以现在要看DubboInvoker的doInvoke方法
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment(PATH_KEY, getUrl().getPath());
inv.setAttachment(VERSION_KEY, version);
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = calculateTimeout(invocation, methodName);
invocation.setAttachment(TIMEOUT_KEY, timeout);
if (isOneway) {
// 通信方式1,oneway,单向发送,不需要返回结果
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else {
// 默认的发送方式
ExecutorService executor = getCallbackExecutor(getUrl(), inv);
CompletableFuture<AppResponse> appResponseFuture =
// 核心方法1
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result;
}
} catch (TimeoutException e) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (RemotingException e) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
核心方法1,根据一个currentClient发送请求,currentClient是一个用于通信的对象,应该是一个和服务端netty建立tcp连接的对象,请求对象是一个RpcInvocation
到这里就发现DubboInvoker是最底层的invoker了,它里面有多个ExchangeClient,这个对象是和服务端建立连接进行通信的,每一个DubboInvoker可以理解为是和一个服务端ip:port进行通信用的
消费端的调用逻辑就到这里了
服务端接受消息
服务端接受消息就要看服务注册时最终开启netty服务设置的接收请求用的handler了,找一下对应的代码
protected void doOpen() throws Throwable {
bootstrap = new ServerBootstrap();
bossGroup = NettyEventLoopFactory.eventLoopGroup(1, EVENT_LOOP_BOSS_POOL_NAME);
workerGroup = NettyEventLoopFactory.eventLoopGroup(
getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
EVENT_LOOP_WORKER_POOL_NAME);
// 核心代码1
final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
channels = nettyServerHandler.getChannels();
boolean keepalive = getUrl().getParameter(KEEP_ALIVE_KEY, Boolean.FALSE);
bootstrap.group(bossGroup, workerGroup)
.channel(NettyEventLoopFactory.serverSocketChannelClass())
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.SO_KEEPALIVE, keepalive)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// FIXME: should we use getTimeout()?
int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
ch.pipeline().addLast("negotiation", new SslServerTlsHandler(getUrl()));
}
ch.pipeline()
.addLast("decoder", adapter.getDecoder())
.addLast("encoder", adapter.getEncoder())
.addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS))
// 核心代码2
.addLast("handler", nettyServerHandler);
}
});
// bind
ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
channelFuture.syncUninterruptibly();
channel = channelFuture.channel();
}
核心代码1,2处可以看到是一个NettyServerHandler来接收请求的
看NettyServerHandler的接收读请求的方法channelRead,这里开始需要打断点了,实现类太多
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
handler.received(channel, msg);
}
这里进过了好几个处理器,到了AllChannelHandler的received
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getPreferredExecutorService(message);
try {
// 核心代码
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
if(message instanceof Request && t instanceof RejectedExecutionException){
sendFeedback(channel, (Request) message, t);
return;
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
把请求扔给了线程池,那么就要看ChannelEventRunnable的run方法了
@Override
public void run() {
if (state == ChannelState.RECEIVED) {
try {
// 核心代码1
handler.received(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is " + message, e);
}
} else {
switch (state) {
case CONNECTED:
try {
handler.connected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case DISCONNECTED:
try {
handler.disconnected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case SENT:
try {
handler.sent(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is " + message, e);
}
break;
case CAUGHT:
try {
handler.caught(channel, exception);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is: " + message + ", exception is " + exception, e);
}
break;
default:
logger.warn("unknown state: " + state + ", message is " + message);
}
}
}
核心代码1,进入了DecodeHandler的received
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Decodeable) {
decode(message);
}
if (message instanceof Request) {
// 核心1
decode(((Request) message).getData());
}
if (message instanceof Response) {
decode(((Response) message).getResult());
}
// 核心2
handler.received(channel, message);
}
核心1处进行了解码,断点查看大小解码之前看不到message里面的数据,解码后可以看到我们传过来的参数了
这里又进行了几次链路,最终到了DubboProtocol的reply方法
@Override
public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {
if (!(message instanceof Invocation)) {
throw new RemotingException(channel, "Unsupported request: "
+ (message == null ? null : (message.getClass().getName() + ": " + message))
+ ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
Invocation inv = (Invocation) message;
// 核心1
Invoker<?> invoker = getInvoker(channel, inv);
inv.setServiceModel(invoker.getUrl().getServiceModel());
// switch TCCL
if (invoker.getUrl().getServiceModel() != null) {
Thread.currentThread().setContextClassLoader(invoker.getUrl().getServiceModel().getClassLoader());
}
// need to consider backward-compatibility if it's a callback
if (Boolean.TRUE.toString().equals(inv.getObjectAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) {
String methodsStr = invoker.getUrl().getParameters().get("methods");
boolean hasMethod = false;
if (methodsStr == null || !methodsStr.contains(",")) {
hasMethod = inv.getMethodName().equals(methodsStr);
} else {
String[] methods = methodsStr.split(",");
for (String method : methods) {
if (inv.getMethodName().equals(method)) {
hasMethod = true;
break;
}
}
}
if (!hasMethod) {
logger.warn(new IllegalStateException("The methodName " + inv.getMethodName()
+ " not found in callback service interface ,invoke will be ignored."
+ " please update the api interface. url is:"
+ invoker.getUrl()) + " ,invocation is :" + inv);
return null;
}
}
RpcContext.getServiceContext().setRemoteAddress(channel.getRemoteAddress());
// 核心2
Result result = invoker.invoke(inv);
return result.thenApply(Function.identity());
}
这里核心1获取了一个服务端的invoker,然后核心2进行调用了它的invoke方法,最终返回了
那么这个服务端的invoker方法就是最后的关键了
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
boolean isCallBackServiceInvoke;
boolean isStubServiceInvoke;
int port = channel.getLocalAddress().getPort();
String path = (String) inv.getObjectAttachments().get(PATH_KEY);
// if it's callback service on client side
isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getObjectAttachments().get(STUB_EVENT_KEY));
if (isStubServiceInvoke) {
port = channel.getRemoteAddress().getPort();
}
//callback
isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke;
if (isCallBackServiceInvoke) {
path += "." + inv.getObjectAttachments().get(CALLBACK_SERVICE_KEY);
inv.getObjectAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
}
String serviceKey = serviceKey(
port,
path,
(String) inv.getObjectAttachments().get(VERSION_KEY),
(String) inv.getObjectAttachments().get(GROUP_KEY)
);
// 核心代码
DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
if (exporter == null) {
throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " +
", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + getInvocationWithoutData(inv));
}
return exporter.getInvoker();
}
这个exporterMap是服务注册时保存的一个map,里面存储数据如下
key=com.example.api.SayHelloService:20880
value=DubboExport
serviceKey就是等于com.example.api.SayHelloService:20880,所以最终可以拿到一个之前保存的DubboExport,然后从里面拿到一个invoker
我们来看一下服务注册时是在哪里保存的exporterMap
在DubboProtocol的export中是这样写的
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
checkDestroyed();
URL url = invoker.getUrl();
// export service.
String key = serviceKey(url);
// 核心方法
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
......
// 核心代码
openServer(url);
optimizeSerialization(url);
return exporter;
}
public DubboExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
// 核心,就是在这里放进去的
exporterMap.put(key, this);
}
这个invoker是在很外层的ServiceConfig中的doExportUrl方法初始化的
private void doExportUrl(URL url, boolean withMetaData) {
// 核心
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
if (withMetaData) {
invoker = new DelegateProviderMetaDataInvoker(invoker, this);
}
Exporter<?> exporter = protocolSPI.export(invoker);
exporters.add(exporter);
}
默认的代理工厂类JavassistProxyFactory的getInvoker
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
try {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
。。。。。。
}
这里的invoker也就是一个AbstractProxyInvoker了,这里的proxy实际上是要调用的对象了,这里的具体逻辑可以看上篇,服务注册源码
最终获取到AbstractProxyInvoker,调用invoker方法传递Invocation 对象
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
ProfilerEntry originEntry = null;
if (ProfilerSwitch.isEnableSimpleProfiler()) {
Object fromInvocation = invocation.get(Profiler.PROFILER_KEY);
if (fromInvocation instanceof ProfilerEntry) {
ProfilerEntry profiler = Profiler.enter((ProfilerEntry) fromInvocation, "Receive request. Server biz impl invoke begin.");
invocation.put(Profiler.PROFILER_KEY, profiler);
originEntry = Profiler.setToBizProfiler(profiler);
}
}
// 核心1
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
。。。。。。
核心1,回到上面的匿名内部类重写的doInvoke方法,调用wrapper的invokeMethod方法,并且把四大参数,实例、方法名称、所有参数类型,所有参数都传递过去了,那么基于这些,是不是就可以完成一个方法的调用了呢
到这里,就可以把消费端和服务端进行串联起来了,最终完成了远程的调用
总结
dubbo的消费端源码比注册端要复杂的多,如果不能打断点来看的话,很难明白它的调用逻辑,并且扩展了大量spring的机制来实现自己的功能,如果对spring不熟悉的话也很难看明白具体逻辑