NopCommerce源码架构详解-自定义系统启动时执行任务Task相关源码分析

看过我之前写的AutoMapper在nop中的运用:NopCommerce源码架构详解-AutoMapper对象关联映射相关源码分析,对于Nop的任务Task并不陌生,因为之前就提到过IStartupTask接口和AutoMapperStartupTask。

NopCommerce源码架构详解概述

文章目录

概述

NopCommerce源码架构详解-自定义系统启动时执行任务Task相关源码分析。

内容

看过我之前写的AutoMapper在nop中的运用:NopCommerce源码架构详解-AutoMapper对象关联映射相关源码分析,对于Nop的任务Task并不陌生,因为之前就提到过IStartupTask接口和AutoMapperStartupTask。今天单独写篇文章来分析一下Nop中的自定义系统启动时执行任务Task相关源码。

相关功能主要用到的类或接口:

1、IStartupTask

2、AutoMapperStartupTask、EfStartUpTask

3、IEngine

4、NopEngine

5、EngineContext

6、Global.asax

1、IStartupTask

namespace Nop.Core.Infrastructure
{
    /// <summary>
    /// Interface which should be implemented by tasks run on startup
    /// </summary>
    public interface IStartupTask 
    {
        /// <summary>
        /// Execute task
        /// </summary>
        void Execute();

        /// <summary>
        /// Order
        /// </summary>
        int Order { get; }
    }
}

IStartupTask接口是所有的启动任务的抽象接口,所有的自定义启动任务都要实现这个接口。

2、AutoMapperStartupTask、EfStartUpTask

AutoMapperStartupTask和EfStartUpTask接口IStartupTask的真正实现,所有的逻辑都可以写在里面。如EfStartUpTask.cs:

using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Infrastructure;

namespace Nop.Data
{
    public class EfStartUpTask : IStartupTask
    {
        public void Execute()
        {
            var settings = EngineContext.Current.Resolve<DataSettings>();
            if (settings != null && settings.IsValid())
            {
                var provider = EngineContext.Current.Resolve<IDataProvider>();
                if (provider == null)
                    throw new NopException("No IDataProvider found");
                provider.SetDatabaseInitializer();
            }
        }

        public int Order
        {
            //ensure that this task is run first 
            get { return -1000; }
        }
    }
}

EfStartUpTask是初始化EF相关的数据库的操作。

3、IEngine

using System;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure.DependencyManagement;

namespace Nop.Core.Infrastructure
{
    /// <summary>
    /// Classes implementing this interface can serve as a portal for the 
    /// various services composing the Nop engine. Edit functionality, modules
    /// and implementations access most Nop functionality through this 
    /// interface.
    /// </summary>
    public interface IEngine
    {
        /// <summary>
        /// Container manager
        /// </summary>
        ContainerManager ContainerManager { get; }

        /// <summary>
        /// Initialize components and plugins in the nop environment.
        /// </summary>
        /// <param name="config">Config</param>
        void Initialize(NopConfig config);

        /// <summary>
        /// Resolve dependency
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <returns></returns>
        T Resolve<T>() where T : class;

        /// <summary>
        ///  Resolve dependency
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        object Resolve(Type type);

        /// <summary>
        /// Resolve dependencies
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <returns></returns>
        T[] ResolveAll<T>();
    }
}

IEngine是Nop的引擎的抽象接口,抽象提出了一些公共方法,如:设置IoC容器,从IoC容器中获取组件,以及初始化组件、插件到Nop环境。

4、NopEngine

NopEngine类实现了接口IEngine,真正的实现了接口的方法。我们可以在里面看到有两个相关于StartupTask的方法:

// <summary>
/// Run startup tasks
/// </summary>
protected virtual void RunStartupTasks()
{
    var typeFinder = _containerManager.Resolve<ITypeFinder>();
    var startUpTaskTypes = typeFinder.FindClassesOfType<IStartupTask>();
    var startUpTasks = new List<IStartupTask>();
    foreach (var startUpTaskType in startUpTaskTypes)
        startUpTasks.Add((IStartupTask)Activator.CreateInstance(startUpTaskType));
    //sort
    startUpTasks = startUpTasks.AsQueryable().OrderBy(st => st.Order).ToList();
    foreach (var startUpTask in startUpTasks)
        startUpTask.Execute();
}

 /// <summary>
/// Initialize components and plugins in the nop environment.
/// </summary>
/// <param name="config">Config</param>
public void Initialize(NopConfig config)
{
    //register dependencies
    RegisterDependencies(config);

    //startup tasks
    if (!config.IgnoreStartupTasks)
    {
        RunStartupTasks();
    }

}

可以看到上面通过typeFinder找到所有实现接口IStartupTask的组件,然后通过排序,最后依次调用其Execute()方法。

5、EngineContext

EngineContext提供了访问Nop engine的单例入口。

/// <summary>
/// Creates a factory instance and adds a http application injecting facility.
/// </summary>
/// <param name="config">Config</param>
/// <returns>New engine instance</returns>
protected static IEngine CreateEngineInstance(NopConfig 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 'Nop.Core.Infrastructure.IEngine' and cannot be configured in /configuration/nop/engine[@engineType] for that purpose.");
        return Activator.CreateInstance(engineType) as IEngine;
    }

    return new NopEngine();
}

/// <summary>
/// Initializes a static instance of the Nop factory.
/// </summary>
/// <param name="forceRecreate">Creates a new factory instance even though the factory has been previously initialized.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public static IEngine Initialize(bool forceRecreate)
{
    if (Singleton<IEngine>.Instance == null || forceRecreate)
    {
        var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
        Singleton<IEngine>.Instance = CreateEngineInstance(config);
        Singleton<IEngine>.Instance.Initialize(config);
    }
    return Singleton<IEngine>.Instance;
}

将方法Initialize用 [MethodImpl(MethodImplOptions.Synchronized)] 标识,表示该方法一次只能由一个线程执行,避免多线程创建多个IEngine实例。创建IEngine实例时调用方法CreateEngineInstance,根据Web.config的配置创建相应的IEngine实例。如果在Web.config没有指定Engine的类型,就创建默认的Engine,即NopEngine。由于Nop默认在配置文件中是没有指定Engine的类型的。如下图:

2020-04-24-00-08-38

从上图可以看到Engine结点属性Type的值为空,所以EngineContext的CreateEngineInstance会创建一个NopEngine的实例。当然你也可以自己定义一个类并实现接口IEngine,然后在Web.config中在Engine结点中为属性Type填上相应的值。

在创建了相应IEngine的实例之后,最后会调用其Initialize方法(Singleton.Instance.Initialize(config);),也就会执行到任务的startUpTask.Execute();

6、Global.asax

在程序启动时Global.asax的Application_Start方法会运行,我们可以看到在Application_Start中会有一行代码:

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

这行代码是启动时执行任务Task的最开始的地方,会一层层地往下执行,直到执行到AutoMapperStartupTask和EfStartUpTask的Execute()方法。

原文出处:蓝狐软件工作室【蓝狐】

原文链接:http://m.lanhusoft.com/Article/349.html

本文观点不代表 .Net中文网 立场,转载请联系原作者。

发表评论

登录后才能评论