当前位置: 首页 > news >正文

Orleans GetGrain<T>(string) 底层原理

Orleans GetGrain(string) 底层原理(结合源码)

本文解析以下调用的底层流程,并给出关键源码引用:

// 获取 GrainFactory
var grainFactory = host.Services.GetRequiredService<IGrainFactory>();// 获取 IHelloGrain 的引用,主键为字符串 "friend"
var friend = grainFactory.GetGrain<IHelloGrain>("friend");

1) IGrainFactory 暴露的 API(定义)

using System;
using System.Threading.Tasks;
using Orleans.Runtime;namespace Orleans
{/// <summary>/// Functionality for creating references to grains./// </summary>public interface IGrainFactory{/// <summary>/// Gets a reference to a grain./// </summary>/// <typeparam name="TGrainInterface">The interface type.</typeparam>/// <param name="primaryKey">The primary key of the grain.</param>/// <param name="grainClassNamePrefix">An optional class name prefix used to find the runtime type of the grain.</param>/// <returns>A reference to the specified grain.</returns>TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidKey;/// <summary>/// Gets a reference to a grain./// </summary>/// <typeparam name="TGrainInterface">The interface type.</typeparam>/// <param name="primaryKey">The primary key of the grain.</param>/// <param name="grainClassNamePrefix">An optional class name prefix used to find the runtime type of the grain.</param>/// <returns>A reference to the specified grain.</returns>TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerKey;/// <summary>/// Gets a reference to a grain./// </summary>/// <typeparam name="TGrainInterface">The interface type.</typeparam>/// <param name="primaryKey">The primary key of the grain.</param>/// <param name="grainClassNamePrefix">An optional class name prefix used to find the runtime type of the grain.</param>/// <returns>A reference to the specified grain.</returns>TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithStringKey;/// <summary>/// Gets a reference to a grain.

要点:GetGrain<T>(string) 是强类型接口,参数 primaryKey 为字符串主键。


2) GrainFactory 实现:字符串主键到 GrainReference

  • 入口:GetGrain<TGrainInterface>(string primaryKey, ...) 将字符串转换为 IdSpan,再走私有重载。
        /// <inheritdoc />public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerKey{var grainKey = GrainIdKeyExtensions.CreateIntegerKey(primaryKey);return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);}/// <inheritdoc />public TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null)where TGrainInterface : IGrainWithStringKey{var grainKey = IdSpan.Create(primaryKey);return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);}
  • 关键:私有方法将接口类型映射到实现 GrainType,合成 GrainId,再通过 GrainReferenceActivator 创建引用。
        /// <summary>/// Gets a grain reference which implements the specified grain interface type and has the specified grain key, without specifying the grain type directly./// </summary>/// <remarks>/// This method infers the most appropriate <see cref="GrainId.Type"/> value based on the <paramref name="interfaceType"/> argument and optional <paramref name="grainClassNamePrefix"/> argument./// The <see cref="GrainInterfaceTypeToGrainTypeResolver"/> type is responsible for determining the most appropriate grain type./// </remarks>/// <param name="interfaceType">The interface type which the returned grain reference will implement.</param>/// <param name="grainKey">The <see cref="GrainId.Key"/> portion of the grain id.</param>/// <param name="grainClassNamePrefix">An optional grain class name prefix.</param>/// <returns>A grain reference which implements the provided interface.</returns>private IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix){var grainInterfaceType = this.interfaceTypeResolver.GetGrainInterfaceType(interfaceType);GrainType grainType;if (!string.IsNullOrWhiteSpace(grainClassNamePrefix)){grainType = this.interfaceTypeToGrainTypeResolver.GetGrainType(grainInterfaceType, grainClassNamePrefix);}else{grainType = this.interfaceTypeToGrainTypeResolver.GetGrainType(grainInterfaceType);}var grainId = GrainId.Create(grainType, grainKey);var grain = this.referenceActivator.CreateReference(grainId, grainInterfaceType);return grain;}

要点:

  • 字符串主键通过 IdSpan.Create(primaryKey) 成为 GrainId 的 Key 部分。
  • GrainInterfaceTypeResolver 将接口类型(如 IHelloGrain)转换为 GrainInterfaceType
  • GrainInterfaceTypeToGrainTypeResolver 找到实际的 GrainType(某个实现类)。
  • GrainId.Create(grainType, grainKey) 形成稳定标识,GrainReferenceActivator.CreateReference(...) 返回可调用的代理引用。

3) 接口到实现的解析:GrainInterfaceTypeResolverGrainInterfaceTypeToGrainTypeResolver

  • 接口类型解析:
using System;
using System.Collections.Generic;
using System.Linq;
using Orleans.Runtime;
using Orleans.Serialization.TypeSystem;namespace Orleans.Metadata
{/// <summary>/// Associates a <see cref="GrainInterfaceType"/> with a <see cref="Type" />./// </summary>public class GrainInterfaceTypeResolver{private readonly IGrainInterfaceTypeProvider[] _providers;private readonly TypeConverter _typeConverter;
...public GrainInterfaceType GetGrainInterfaceType(Type type){if (!type.IsInterface){throw new ArgumentException($"Argument {nameof(type)} must be an interface. Provided value, \"{type}\", is not an interface.", nameof(type));}// Configured providers take precedenceforeach (var provider in _providers){if (provider.TryGetGrainInterfaceType(type, out var interfaceType)){interfaceType = AddGenericParameters(interfaceType, type);return interfaceType;}}// Conventions are used as a fallback.return GetGrainInterfaceTypeByConvention(type);}
  • 接口到实现类型映射:
    /// <summary>/// Associates <see cref="GrainInterfaceType"/>s with a compatible <see cref="GrainType"/>./// </summary>/// <remarks>/// This is primarily intended for end-users calling <see cref="IGrainFactory"/> methods without needing to be overly explicit./// </remarks>public class GrainInterfaceTypeToGrainTypeResolver{
.../// <summary>/// Returns the <see cref="GrainType"/> which supports the provided <see cref="GrainInterfaceType"/> and which has an implementing type name beginning with the provided prefix string./// </summary>public GrainType GetGrainType(GrainInterfaceType interfaceType, string prefix){if (string.IsNullOrWhiteSpace(prefix))

要点:运行时使用集群清单/Provider 解析接口到实现,支持泛型与前缀选择。


4) GrainReference:引用的结构与调用入口

  • GrainReference 组合 GrainType + IdSpan(Key) 形成 GrainId,保存 GrainInterfaceTypeIGrainReferenceRuntime
    public class GrainReference : IAddressable, IEquatable<GrainReference>, ISpanFormattable{/// <summary>/// The grain reference functionality which is shared by all grain references of a given type./// </summary>[NonSerialized]private readonly GrainReferenceShared _shared;/// <summary>/// The underlying grain id key./// </summary>[NonSerialized]private readonly IdSpan _key;
.../// <summary>/// Gets the grain id./// </summary>public GrainId GrainId => GrainId.Create(_shared.GrainType, _key);/// <summary>/// Gets the interface type./// </summary>public GrainInterfaceType InterfaceType => _shared.InterfaceType;
...protected GrainReference(GrainReferenceShared shared, IdSpan key){_shared = shared;_key = key;}
  • 方法调用由 GrainReference.InvokeAsync(...) 委派到 IGrainReferenceRuntime
        /// <summary>/// Invokes the provided method./// </summary>/// <typeparam name="T">The underlying method return type.</typeparam>/// <param name="methodDescription">The method description.</param>/// <returns>The result of the invocation.</returns>protected ValueTask<T> InvokeAsync<T>(IRequest methodDescription){return this.Runtime.InvokeMethodAsync<T>(this, methodDescription, methodDescription.Options);}
...protected void Invoke(IRequest methodDescription){this.Runtime.InvokeMethod(this, methodDescription, methodDescription.Options);}

要点:friend 是一个轻量代理;真正的远程调用在后续方法执行时才发生。


5) GrainReferenceRuntime:发送请求到运行时

  • 调用被包装为 IInvokable,通过 IRuntimeClient.SendRequest(...) 派发:
    internal class GrainReferenceRuntime : IGrainReferenceRuntime{private readonly GrainReferenceActivator referenceActivator;private readonly GrainInterfaceTypeResolver interfaceTypeResolver;private readonly IGrainCancellationTokenRuntime cancellationTokenRuntime;private readonly IOutgoingGrainCallFilter[] filters;private readonly Action<GrainReference, IResponseCompletionSource, IInvokable, InvokeMethodOptions> sendRequest;public GrainReferenceRuntime(IRuntimeClient runtimeClient,IGrainCancellationTokenRuntime cancellationTokenRuntime,IEnumerable<IOutgoingGrainCallFilter> outgoingCallFilters,GrainReferenceActivator referenceActivator,GrainInterfaceTypeResolver interfaceTypeResolver){this.RuntimeClient = runtimeClient;this.cancellationTokenRuntime = cancellationTokenRuntime;this.referenceActivator = referenceActivator;this.interfaceTypeResolver = interfaceTypeResolver;this.filters = outgoingCallFilters.ToArray();this.sendRequest = (GrainReference reference, IResponseCompletionSource callback, IInvokable body, InvokeMethodOptions options) => RuntimeClient.SendRequest(reference, body, callback, options);}
  • 发送逻辑(无过滤器时直发):
        public ValueTask<TResult> InvokeMethodAsync<TResult>(GrainReference reference, IInvokable request, InvokeMethodOptions options){// TODO: Remove expensive interface type checkif (this.filters.Length == 0 && request is not IOutgoingGrainCallFilter){SetGrainCancellationTokensTarget(reference, request);var responseCompletionSource = ResponseCompletionSourcePool.Get<TResult>();this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options);return responseCompletionSource.AsValueTask();}

6) 端到端流程(简述)

  • 获取服务:host.Services.GetRequiredService<IGrainFactory>() 从 DI 容器取得 GrainFactory 实例(宿主初始化时注册)。
  • 构建引用:GetGrain<IHelloGrain>("friend")
    • 将 “friend” → IdSpan
    • IHelloGrainGrainInterfaceType
    • 解析实现 → GrainType
    • 合成 GrainId = GrainType + Key(friend)
    • GrainReferenceActivator 生成 GrainReference
  • 延迟调用:对 friend 调用方法时,GrainReference 将请求交给 GrainReferenceRuntime,它通过 IRuntimeClient.SendRequest(...) 将消息发往目标激活,期间经历目录定位、消息路由、序列化、过滤链等。

7) 关键点与常见疑问

  • 引用不是实例化:GetGrain 不会立即激活 Grain;引用是可序列化的代理,真正的网络交互在首次方法调用时发生。
  • 主键如何影响定位:字符串主键构成 GrainId.Key,与 GrainType 一起决定放置与目录定位;不同主键对应不同实例身份。
  • 多实现选择:若同一接口有多个实现,可通过 grainClassNamePrefix 决定绑定的 Grain 类型(实现类名前缀匹配)。

8) 小结

  • GetGrain<IHelloGrain>("friend") 的核心工作:接口类型解析、实现类型解析、主键封装、GrainId 构造、GrainReference 生成。
  • 方法调用时才触发网络请求,由 GrainReferenceRuntimeIRuntimeClient 发送。

9) 生成代码 HelloWorld.orleans.g.cs 的生成时机与作用

  • 生成时机:编译期由 Orleans 的 Roslyn Source Generator 运行,向编译管线追加生成源,文件名为 <AssemblyName>.orleans.g.cs(例如项目程序集名为 HelloWorld,则为 HelloWorld.orleans.g.cs)。
[Generator]
public class OrleansSerializationSourceGenerator : ISourceGenerator
{public void Execute(GeneratorExecutionContext context){...var codeGenerator = new CodeGenerator(context.Compilation, options);var syntax = codeGenerator.GenerateCode(context.CancellationToken);var sourceString = syntax.NormalizeWhitespace().ToFullString();var sourceText = SourceText.From(sourceString, Encoding.UTF8);context.AddSource($"{context.Compilation.AssemblyName ?? "assembly"}.orleans.g.cs", sourceText);}
}
  • 生成内容:接口代理(Proxy)、方法 Invokable、序列化器、元数据、激活器等。按需发射生成(如果编译集中不存在对应类型则注入):
if (Compilation.GetTypeByMetadataName(generatedInvokable.MetadataName) == null)
{// Emit the generated code on-demand.AddMember(generatedInvokable.GeneratedNamespace, generatedInvokable.ClassDeclarationSyntax);// Ensure the type will have a serializer generated for it.MetadataModel.SerializableTypes.Add(generatedInvokable);...
}
  • 在运行时如何被使用:
    • 第 2/3 步的接口到实现解析会使用生成的元数据(帮助从接口映射到实现类型)。
    • 方法调用时,GrainReference 获取并使用生成的 Invokable 类型打包调用请求,再交由 GrainReferenceRuntime 发送:
protected TInvokable GetInvokable<TInvokable>() => ActivatorUtilities.GetServiceOrCreateInstance<TInvokable>(Shared.ServiceProvider);
protected ValueTask<T> InvokeAsync<T>(IRequest methodDescription)
{return this.Runtime.InvokeMethodAsync<T>(this, methodDescription, methodDescription.Options);
}

10) 时序图(从 GetGrain 到一次方法调用)

应用代码Host DI 容器GrainFactoryGrainInterfaceTypeResolverGrainInterfaceTypeToGrainTypeResolverGrainReferenceActivatorGrainReferenceGrainReferenceRuntimeIRuntimeClientGetRequiredService<IGrainFactory>()1GrainFactory 实例2GetGrain<IHelloGrain>("friend")3IdSpan.Create("friend")4GetGrainInterfaceType(typeof(IHelloGrain))5GrainInterfaceType6GetGrainType(interfaceType, prefix)7GetGrainType(interfaceType)8alt[指定 prefix][无 prefix]GrainType9GrainId.Create(GrainType, Key)10CreateReference(GrainId, GrainInterfaceType)11GrainReference (Ref)12IHelloGrain 引用 (Ref)13仅创建代理,不触发远程调用调用方法(例如 SayHello("x"))14InvokeAsync(Request)15SendRequest(Ref, Request, Completion)16异步响应(或 OneWay 无响应)17结果/完成18返回任务/结果19应用代码Host DI 容器GrainFactoryGrainInterfaceTypeResolverGrainInterfaceTypeToGrainTypeResolverGrainReferenceActivatorGrainReferenceGrainReferenceRuntimeIRuntimeClient

11) 关键类关系简图

创建
GrainFactory
- GrainReferenceActivator referenceActivator
- GrainInterfaceTypeResolver interfaceTypeResolver
- GrainInterfaceTypeToGrainTypeResolver interfaceTypeToGrainTypeResolver
+GetGrain(string key)
-GetGrain(Type, IdSpan, string)
GrainInterfaceTypeResolver
+GetGrainInterfaceType(Type)
GrainInterfaceTypeToGrainTypeResolver
+GetGrainType(GrainInterfaceType)
+GetGrainType(GrainInterfaceType, string)
GrainReferenceActivator
+CreateReference(GrainId, GrainInterfaceType)
GrainReference
+ GrainId: GrainId
+ InterfaceType: GrainInterfaceType
+InvokeAsync(IRequest)
GrainReferenceRuntime
+InvokeMethodAsync(GrainReference, IInvokable, InvokeMethodOptions)
IRuntimeClient
+SendRequest(GrainReference, IInvokable, IResponseCompletionSource, InvokeMethodOptions)

12) 端到端要点回顾

  • GetGrain<T>(string) 只创建引用,不会立即激活 Grain。
  • 接口类型解析与实现选择基于运行时元数据(部分来自编译期生成代码)。
  • 真正的远程交互发生在方法调用时,由 GrainReferenceRuntimeIRuntimeClient 协作完成。
http://www.dtcms.com/a/555760.html

相关文章:

  • 网站开发 pythonwin7 asp网站发布
  • 国内网站放国外服务器国际新闻头条
  • 做家具厂招聘有哪些网站自媒体网站源码
  • 网站建设到上线有云服务器怎么做网站
  • 深圳推广网站做招聘网站代理商需要多少钱
  • 海口高端品牌网站建设买一个网页需要多少钱
  • 做网站用什么软件?中山百度seo排名公司
  • app 微网站建设网站需要具备什么条件
  • 西安网站设计公司抄袭网站违法
  • 上海市建设安全协会网站j公司官网的意义
  • 济南网站优化推广公司电话重庆公司注册服务
  • 网站建设目标规划网络营销的策划方案
  • wordpress积分墙南昌做网站优化价格
  • 福建远方建设有限公司网站竞价托管魏大帅
  • 翻墙国外网站做兼职网站做留言板怎么清空源码
  • 个人网站对应网站网址前期做网站宣传费用怎样做账
  • html制作个人简历seo网站概述
  • 加入网站帮忙做网站企业宣传册模板文案
  • 建设网站所需的费用的估算封面上的网站怎么做的
  • 网站设计实用实例拓者室内设计联盟
  • cms建站系统免费重庆名威建设工程咨询有限公司网站
  • 梅州建站推荐网站开发与app差距
  • 集团网站定制成都本地推广平台
  • 外贸网站设计多少钱wordpress cosy主题破解
  • 稻香村网站建设南海最新军事新闻
  • 高仿id97网站模板在长沙阳光医院做网站编辑
  • 网站的内容品牌建设和品牌推广
  • 江门网站制作华企立方百度招聘电话
  • 企业网站域名注册云南做网站多少钱
  • 广东圆心科技网站开发长春网站制作企业