.net平台的AppDomain技术实现服务的重启功能
- 一直很好奇电脑上运行的服务重启是怎么实现的?
using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
namespace MyService
{
public partial class Form1 : Form
{
AppDomain serviceDomain = null;
public Form1()
{
InitializeComponent();
ThreadPool.QueueUserWorkItem(new WaitCallback(Run), "");//执行服务
textBox3.Text = @"服务启动和重启Demo,介绍:
(1)、借用.net平台的AppDomain技术实现服务的重启功能(本质:服务核心dll跑在程序域里,重启就是卸载再加载过程)
(2)、每次重启都新建程序域,故通过程序域名识别是否重新加载成功。";
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "";
}
/// <summary>
/// 重启
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click_1(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(Run), "");
}
#region MyRegion
private void Run(object v)
{
if (serviceDomain != null)
{
Action ac = () =>
{
textBox2.Text = "重启中...";
};
this.Invoke(ac);
AppDomain.Unload(serviceDomain);//卸载程序域
Thread.Sleep(3000);
Action ac2 = () =>
{
textBox2.Text = "重启成功";
};
this.Invoke(ac2);
}
serviceDomain = AppDomain.CreateDomain("AppDomain" + DateTime.Now.ToString("ddHHmmss"), null, null); //创建子Domain
ProxyObject myService = serviceDomain.CreateInstanceAndUnwrap(typeof(ProxyObject).Assembly.FullName, "MyService.ProxyObject") as ProxyObject;
myService.LoadAssembly();
myService.ReturnVal += EventAction;
myService.ExecWhile("AppDomainPlugin.MyTest", "Abc", "test");
}
/// <summary>
/// 在界面显示结果
/// </summary>
/// <param name="a"></param>
private void EventAction(object a)
{
Action ac = () =>
{
textBox1.Text += serviceDomain.FriendlyName + " = " + a.ToString() + "\r\n";
};
this.Invoke(ac);
}
#endregion
}
#region
// 该类的实例可跨越AppDomain的边界"按引用封送"
class ProxyObject : MarshalByRefObject
{
public event Action<object> ReturnVal;
Assembly assembly = null;
public void LoadAssembly()
{
assembly = Assembly.LoadFile(@"C:\Users\aj\Documents\Visual Studio 2015\Projects\MyService\AppDomainPlugin\bin\Debug\AppDomainPlugin.dll");
}
/// <summary>
/// 执行指定dll中方法
/// </summary>
/// <param name="fullClassName">类全名(命名空间.类名,如:AppDomainPlugin.MyTest)</param>
/// <param name="methodName">方法名</param>
/// <param name="args">方法入参</param>
/// <returns></returns>
public object ExecFun(string fullClassName, string methodName, params Object[] args)
{
if (assembly == null)
return false;
Type tp = assembly.GetType(fullClassName);
if (tp == null)
return false;
MethodInfo method = tp.GetMethod(methodName);
if (method == null)
return false;
object newObj = Activator.CreateInstance(tp);//反射new一个实例对象
return method.Invoke(newObj, args);//执行指定的方法并返回
}
/// <summary>
/// 轮询方式 执行指定dll中方法
/// </summary>
/// <param name="fullClassName">类全名(命名空间.类名,如:AppDomainPlugin.MyTest)</param>
/// <param name="methodName">方法名</param>
/// <param name="args">方法入参</param>
/// <returns></returns>
public void ExecWhile(string fullClassName, string methodName, params object[] args)
{
Type tp = assembly.GetType(fullClassName);
MethodInfo method = tp.GetMethod(methodName);
object newObj = Activator.CreateInstance(tp);//new一个实例对象
while (true)
{
//%5是0来模拟触发事件时机
if (DateTime.Now.Second % 5 == 0)
{
var a = method.Invoke(newObj, args);//执行指定的方法并返回
if (a != null)
{
ReturnVal(a);//执行事件
}
}
}
}
}
#endregion
}
- 用AppDomainPlugin模拟服务核心dll(重启就卸载和重载本dll)
using System;
namespace AppDomainPlugin
{
public class MyTest
{
public string Abc(string a)
{
return a + " " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
- Demo源码——下载
应用程序域,目的就是提供隔离性(一个域失败,其他不受影响)。借用此技术程序集可单独加载(加载相同程序集的不同版本)、动态卸载。
- .Net 进程中多个应用程序域(AppDomain)会影响性能吗? —— 反射加载dll不用停止进程,但是卸载、运行中替换的话也要停止进程。
1个进程 = n个应用程序域
、1个应用程序域 = n个线程
- 应用程序域原则上相互独立,用“socket、.net Remoting、MarshalByRefObject”等通信
- AppDomain实现程序集热插拔、异常隔离等等。但 AppDomain不好用,最大的问题就是跨 AppDomain 调用的性能,让人望而却步的。专门针对跨 AppDomain 通信的库JointCode.Shuttle
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?