ABPvnext源碼分析 (二):Autofac整合及動態代理


寫在前面:

上一篇我們講了Abp的核心模塊,這一篇我們把DI 的serviceProvider替換成Autofac,另外添加動態代理攔截器功能。動態代理指從DI容器獲取組件實例時組件實例不是原實例,而是代理實例。代理實例是對原實例進行了封裝, 在實例方法前后添加邏輯處理,讓獲取的對象表現基於應有對象但又有自己的邏輯。舉個例子,代理對象方法可以在原方法前后記錄時間戳,來分析原方法的處理時長。Abp Core默認使用的是微軟官方的DI實現, 那個功能較簡單沒有代理功能,為了添加動態代理功能,我們把DI實現替換為Autofac,並使用Autofac集成的代理實現方式Castle Core。
集成Autofac,我們需要添加Volo.Abp.Autofac包,這個包本身是Abp模塊,其依賴AbpCastleCoreModule模塊(Volo.Abp.CatleCore)

namespace Volo.Abp.Autofac
{
[DependsOn(typeof(AbpCastleCoreModule))]
public class AbpAutofacModule : AbpModule
{

}
}

 所以我們添加Volo.Abp.Autofac包並讓我們的應用模塊DependsOn(typeof(AbpAutofacModule))就自動的把AbpAutofacModule,AbpCastleCoreModule加入到我們的Core中進行模塊管理,也就是說那些基於約定的服務會自動注冊到我們的abpApplication.Services中,非常的方便。我們在使用Abp中發現好多第三方庫都有對應的Volo.Abp.Xxx包也是這個道理,通過把包加入我們Abp的模塊管理體系,把各自的服務注冊放入各自的包當中,這樣我們的應用代碼就不需要一個一個的注冊這些三方庫服務,應用模塊直接添加DependsOn(typeof(Xxx))即可。

 

正菜開始:

Abp集成Autofac非常簡單 var application = services.AddApplication<TStartupModule>(option=>options.UseAutofac(););
我們看下UseAutofac這個方法

public static void UseAutofac(this AbpApplicationCreationOptions options)
{
var builder = new ContainerBuilder();
options.Services.AddObjectAccessor(builder);
options.Services.AddSingleton((IServiceProviderFactory<ContainerBuilder>) new AbpAutofacServiceProviderFactory(builder));
}

回憶上一篇最后的代碼,由於注冊了IServiceProviderFactory<ContainerBuilder>,於是使用該實例serviceProviderFactory的工廠方法serviceProviderFactory.CreateServiceProvider(serviceProviderFactory.CreateBuilder(services)完成DI容器IServiceProvider的創建,這就把DI容器具體的創建邏輯交給了AbpAutofacServiceProviderFactory,非常巧妙的設計。

    public ContainerBuilder CreateBuilder(IServiceCollection services)
        {
            _services = services;

            _builder.Populate(services);

            return _builder;
        }

在AbpAutofacServiceProviderFactory中CreateBuilder調用了方法_builder.Populate(services);注意這里的Populate方法是
Autofac.Extensions.DependencyInjection.AutofacRegistration.Populate,
重新實現了Autofac的同名擴展方法 Microsoft.Extensions.DependencyInjection.AutofacRegistration.Populate

,他和原擴展方法類似但加入了新的邏輯,我們不要引用錯誤包。

跟蹤其實現

    public static void Populate(
                this ContainerBuilder builder,
                IServiceCollection services)
        {
            builder.RegisterType<AutofacServiceProvider>().As<IServiceProvider>();
            builder.RegisterType<AutofacServiceScopeFactory>().As<IServiceScopeFactory>(); //注冊IServiceProvider,IServiceScopeFactory

            Register(builder, services);
        }
private static void Register(
                ContainerBuilder builder,
                IServiceCollection services)
        {
            var moduleContainer = services.GetSingletonInstance<IModuleContainer>();  //植入的內容
            var registrationActionList = services.GetRegistrationActionList(); //植入的內容

            foreach (var service in services)
            {
                if (service.ImplementationType != null)
                {
                    // Test if the an open generic type is being registered
                    var serviceTypeInfo = service.ServiceType.GetTypeInfo();
                    if (serviceTypeInfo.IsGenericTypeDefinition) //IsGenericTypeDefinition 這個可以泛型類型判斷是否參數實例化了
                    {
                        builder
                            .RegisterGeneric(service.ImplementationType) //注冊一個無參數實例化的泛型類型
                            .As(service.ServiceType)
                            .ConfigureLifecycle(service.Lifetime)
                            .ConfigureAbpConventions(moduleContainer, registrationActionList); //這一步是新添加的邏輯  包含攔截器
                    }
                    else
                    {
                        builder
                            .RegisterType(service.ImplementationType)
                            .As(service.ServiceType)
                            .ConfigureLifecycle(service.Lifetime)
                            .ConfigureAbpConventions(moduleContainer, registrationActionList);  //這一步是新添加的邏輯  包含攔截器
                    }
                }
                else if (service.ImplementationFactory != null)
                {
                    var registration = RegistrationBuilder.ForDelegate(service.ServiceType, (context, parameters) =>
                    {
                        var serviceProvider = context.Resolve<IServiceProvider>();
                        return service.ImplementationFactory(serviceProvider);
                    })
                    .ConfigureLifecycle(service.Lifetime)
                    .CreateRegistration();
                    //TODO: ConfigureAbpConventions ?

                    builder.RegisterComponent(registration);
                }
                else
                {
                    builder
                        .RegisterInstance(service.ImplementationInstance)
                        .As(service.ServiceType)
                        .ConfigureLifecycle(service.Lifetime);
                }
            }
        }

其主要邏輯是把serives中每一個服務注冊在builder中注冊。其中對每個服務還調用了ConfigureAbpConventions(moduleContainer, registrationActionList)

        public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> ConfigureAbpConventions<TLimit, TActivatorData, TRegistrationStyle>(  //builder.Populate(services)植入的ABP部分
                this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder, 
                IModuleContainer moduleContainer, 
                ServiceRegistrationActionList registrationActionList)
            where TActivatorData : ReflectionActivatorData
        {
            var serviceType = registrationBuilder.RegistrationData.Services.OfType<IServiceWithType>().FirstOrDefault()?.ServiceType;
            if (serviceType == null)
            {
                return registrationBuilder; //直接返回
            }

            var implementationType = registrationBuilder.ActivatorData.ImplementationType;
            if (implementationType == null)
            {
                return registrationBuilder; //沒有實現類型 直接返回
            }

            registrationBuilder = registrationBuilder.EnablePropertyInjection(moduleContainer, implementationType); //當前type程序集包含Abp模塊則開啟屬性注入
            registrationBuilder = registrationBuilder.InvokeRegistrationActions(registrationActionList, serviceType, implementationType); //調用registration HOOK  如果有攔截器,則添加攔截器

            return registrationBuilder;
        }

上面serviceType是Autofac的registrationBuilder添加的元數據我們不必理會,implementationType是組件(服務實例)類型。重點我們跟蹤下InvokeRegistrationActions

        private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InvokeRegistrationActions<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder, ServiceRegistrationActionList registrationActionList, Type serviceType, Type implementationType) 
            where TActivatorData : ReflectionActivatorData
        {
            var serviceRegistredArgs = new OnServiceRegistredContext(serviceType, implementationType);

            foreach (var registrationAction in registrationActionList)  //執行每一個registrationAction
            {
                registrationAction.Invoke(serviceRegistredArgs);
            }

            if (serviceRegistredArgs.Interceptors.Any())  //IMPORTANT 如果有攔截器,則添加攔截器
            {
                registrationBuilder = registrationBuilder.AddInterceptors(
                    serviceType,
                    serviceRegistredArgs.Interceptors
                );
            }

            return registrationBuilder;
        }
        private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> AddInterceptors<TLimit, TActivatorData, TRegistrationStyle>(
            this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder, 
            Type serviceType,
            IEnumerable<Type> interceptors)
            where TActivatorData : ReflectionActivatorData
        {
            if (serviceType.IsInterface)
            {
                registrationBuilder = registrationBuilder.EnableInterfaceInterceptors(); //開啟接口攔截器
            }
            else
            {
                (registrationBuilder as IRegistrationBuilder<TLimit, ConcreteReflectionActivatorData, TRegistrationStyle>)?.EnableClassInterceptors(); //開啟類攔截器
            }

            foreach (var interceptor in interceptors)
            {
                registrationBuilder.InterceptedBy( //https://www.cnblogs.com/stulzq/p/8547839.html autofac的動態代理  Autofac.Extras.DynamicProxy程序集
                    typeof(CastleAbpInterceptorAdapter<>).MakeGenericType(interceptor) //范型類型實例化  ABP攔截器轉CASTLE攔截器 
                );
            }

            return registrationBuilder;
        }

動態代理實現使用的是Castle.Core的api中  

public static IRegistrationBuilder<TLimit, TActivatorData, TStyle> InterceptedBy<TLimit, TActivatorData, TStyle>(
    this IRegistrationBuilder<TLimit, TActivatorData, TStyle> builder,
    params Type[] interceptorServiceTypes)

其中interceptorServiceTypes為IInterceptor的類型的Type。我們Abp使用的是IAbpInterceptor。 CastleAbpInterceptorAdapter類就是實現從IAbpInterceptor到IInterceptor的適配。

       public void Intercept(IInvocation invocation) //攔截器業務邏輯  Castle 的攔截器有一個 Intercept() 方法,該方法將在被攔截方法執行的時候觸發。
        {
            var proceedInfo = invocation.CaptureProceedInfo();

            var method = invocation.MethodInvocationTarget ?? invocation.Method;// MethodInvocationTarget目標類方法的methodInfo, Method代理方法的methodInfo 

            if (method.IsAsync())
            {
                InterceptAsyncMethod(invocation, proceedInfo);
            }
            else
            {
                InterceptSyncMethod(invocation, proceedInfo);
            }
        }
     private void InterceptSyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
        {
            _abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation, proceedInfo));
        }

看一下CastleAbpInterceptorAdapter類型的Intercept方法,又調用的是_abpInterceptor.Intercept方法。

由上面可以看出。我們是通過CastleAbpInterceptorAdapter完成從castle core攔截器到abp攔截器的適配。 我們定義好apb攔截器,abp自動為我們生成對應的castle core攔截器進行適配,進行攔截時castle core攔截器調用我們的apb攔截器的攔截接口void Intercept(IAbpMethodInvocation invocation);

以上是abp攔截器的實現機制。通過CastleAbpInterceptorAdapter適配層完成調用castle core攔截器到間接調用 abp攔截器的轉換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM