Autofac依赖注入分析

通过Autofac对接口依赖的实现进行注入,需要用到的核心类如下

可以看到这里面相关的类为
mvcApplication
IEngine,LEngine
EngineContext
IDependencyRegistrar,DependencyRegistrar
下面我们再来看看这些类的核心代码。
每个项目里都有一个DependencyRegistrar,其作用就是调用Autofac相关的API进行依赖注入, 我们只要打开这个类文件,搜索一个指定的接口,就可以找到它依赖的具体类。 例如,我们想看到ICategoryService接口是依赖哪一个实现, 在这个类中搜索ICategoryService,会找到下面的代码:

builder.RegisterType<CategoryService>().As<ICategoryService>().InstancePerLifetimeScope();

可以看到这个接口对应的实现为为CategoryService
下面我们来看看在网站启动是怎么调用这个DependencyRegistrar类呢?

在项目就是前台的起始项目有一个文件Global.asax里有一个函数Application_Start,这函数的意义这里就不用说了, 我相信学过ASP.NET同学都知道它的作用,下面是函数Application_Start的完整代码:

protected void Application_Start()
{ 
    //initialize engine context
    EngineContext.Initialize(false);

    //model binders
    ModelBinders.Binders.Add(typeof(BaseNopModel), new NopModelBinder());

    //Add some functionality on top of the default ModelMetadataProvider
    ModelMetadataProviders.Current = new NopMetadataProvider();

    //Registering some regular mvc stuff
    AreaRegistration.RegisterAllAreas();// 注册区域路由
    RegisterRoutes(RouteTable.Routes);// 注册项目路由
}

里面有第一行代码就调用了上下文引擎初始化。

//initialize engine context
EngineContext.Initialize(false);

下面我们来看看这个EngineContext的静态方法Initialize:

[MethodImpl(MethodImplOptions.Synchronized)]
public static IEngine Initialize(bool forceRecreate)
{
    if (Singleton<IEngine>.Instance == null || forceRecreate)
    {
        var config = ConfigurationManager.GetSection("LConfig") as LConfig;
        Singleton<IEngine>.Instance = CreateEngineInstance(config);
        Singleton<IEngine>.Instance.Initialize(config);

        Singleton<LclStartupConfiguration>.Instance.Initialize();
    }
    return Singleton<IEngine>.Instance;
}
protected static IEngine CreateEngineInstance(LConfig config)
{
    if (config != null && !string.IsNullOrEmpty(config.EngineType))
    {
        var engineType = Type.GetType(config.EngineType);
        if (engineType == null)
            throw new ConfigurationErrorsException("The type '" + config.EngineType + "' could not be found. Please check the configuration at /configuration/nop/engine[@engineType] or check for missing assemblies.");
        if (!typeof(IEngine).IsAssignableFrom(engineType))
            throw new ConfigurationErrorsException("The type '" + engineType + "' doesn't implement 'LCL.Core.Infrastructure.IEngine' and cannot be configured in /configuration/nop/engine[@engineType] for that purpose.");
        return Activator.CreateInstance(engineType) as IEngine;
    }
    return new LEngine();
}

从上面可以看到Initialize返回一个IEngine的实例,并调用其方法Initialize。 创建IEngine的实例是根据配置文件来获取哪一个IEngine的具体类,如果没有配置这个结点信息或者为空, 则返回默认的IEngine的实现LEngine。

下面我们来看看LCL.Infrastructure.LEngine里面的核心代码:

public void Initialize(LConfig config)
{
     //注册依赖
     RegisterDependencies(config);
 
     //startup tasks
     if (!config.IgnoreStartupTasks){
          RunStartupTasks();
     }
}
protected virtual void RegisterDependencies(NopConfig config)
{
     var builder = new ContainerBuilder();
     var container = builder.Build();
 
     //we create new instance of ContainerBuilder
     //because Build() or Update() method can only be called once on a ContainerBuilder.
 
 
     //dependencies<IEngine>
     var typeFinder = new WebAppTypeFinder(config);
     builder = new ContainerBuilder();
     builder.RegisterInstance(config).As<LConfi>().SingleInstance();
     builder.RegisterInstance(this).As<IEngine>().SingleInstance();
     builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
     builder.Update(container);
 
     //register dependencies provided by other assemblies
     builder = new ContainerBuilder();
     //查找所有实现了接口IDependencyRegistrar的类
     var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
     var drInstances = new List<IDependencyRegistrar>();
     foreach (var drType in drTypes)
          drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
     //排序
     drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
     //依次调用实现IDependencyRegistrar接口的类的方法Register
     foreach (var dependencyRegistrar in drInstances)
          dependencyRegistrar.Register(builder, typeFinder);
     builder.Update(container);
 
     this._containerManager = new ContainerManager(container);
 
     //set dependency resolver
     DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}