안녕하세요, .NET 개발자 여러분!
오늘은 .NET의 중심부에서 작동하는 신비한 섬, 바로 AppDomain에 대해 깊이 들어가볼 생각입니다.
지금부터 여러분은 이 작은 섬에서 어떻게 여행을 즐길 수 있는지 알게 될 겁니다.
준비됐나요? 🚀
쉽게 말해, AppDomain은 .NET 프로세스 내에서 코드를 실행하고 관리하는 작은 ‘섬’입니다.
이 섬은 완전히 독립적인 세계를 형성하며, 각 섬은 나름의 법률과 규칙, 자원을 갖고 있습니다.
즉, 어셈블리, 변수, 보안 설정 등이 각각의 AppDomain 내에서 격리됩니다.
“격리되었다”는 AppDomain 내에서 코드가 실행되는 동안 해당 코드가 다른 AppDomain의 리소스나 상태에 영향을 미치지 않는다는 것을 의미합니다.
이것이 가능한 이유는 각 AppDomain이 독립적인 메모리 공간, 로딩된 어셈블리, 설정, 그리고 보안 규칙을 가지고 있기 때문입니다.
AppDomain에서 실행되는 코드가 다른 AppDomain의 리소스에 접근하는 것을 제한할 수 있습니다.AppDomain에서 문제가 발생하더라도 다른 AppDomain에는 영향을 미치지 않습니다.AppDomain을 언로드하면 그 안에서 사용되던 리소스를 효과적으로 해제할 수 있습니다.웹 서버에서 여러 사용자의 코드를 동적으로 로드하고 실행하는 상황을 생각해보세요.
각 사용자의 코드를 별도의 AppDomain에 로드하면, 한 사용자의 코드에서 문제가 발생해도 다른 사용자에게는 영향을 미치지 않습니다.
또한, 보안을 강화하여 특정 사용자의 코드가 시스템에 무분별하게 접근하는 것을 제한할 수 있습니다.
AppDomain.CurrentDomain은 현재 코드가 실행되고 있는 AppDomain 객체에 대한 참조를 반환합니다.
대부분의 .NET 애플리케이션은 기본적으로 하나의 AppDomain에서 시작되므로, 따로 설정하지 않으면 AppDomain.CurrentDomain은 그 시작되는 AppDomain을 참조하게 됩니다.
예를 들어 현재 AppDomain의 정보와 어셈블리 목록을 출력하려면 다음과 같이 할 수 있습니다.
// 현재 AppDomain의 정보 출력
Console.WriteLine($"Current AppDomain: {AppDomain.CurrentDomain.FriendlyName}");
// 현재 AppDomain에 로드된 어셈블리 목록 출력
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
Console.WriteLine(assembly.FullName);
}
AppDomain.CurrentDomain.Load를 사용하면 특정 어셈블리를 명시적으로 로드할 수 있습니다. 마치 섬에 특별한 손님을 초대하는 것과 같아요!
Assembly loadedAssembly = AppDomain.CurrentDomain.Load("SpecialGuest");
어떤 손님이 섬에 와 있는지 궁금하다면, AppDomain.CurrentDomain.GetAssemblies를 사용해 확인할 수 있습니다.
Assembly[] currentGuests = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly guest in currentGuests)
{
Console.WriteLine(guest.FullName);
}
새로운 섬을 만들려면 어떻게 해야 할까요? AppDomain.CreateDomain을 사용하면 새로운 AppDomain을 생성할 수 있습니다.
AppDomain newIsland = AppDomain.CreateDomain("NewIsland");
섬 간에 메시지를 전달하려면 어떻게 해야 할까요? 이것도 가능합니다!
newIsland.DoCallBack(() => Console.WriteLine("Hello from the New Island!"));
AppDomain pluginDomain = AppDomain.CreateDomain("PluginDomain");
pluginDomain.Load("MyPlugin");
AppDomain testDomain = AppDomain.CreateDomain("TestDomain");
testDomain.ExecuteAssembly("MyTestAssembly.dll");
AppDomain.Unload(unwantedDomain);
AppDomain 간의 관계를 시각화하면, 각각은 독립적인 ‘섬’처럼 생각할 수 있습니다.
이 ‘섬들’은 같은 ‘대양’ (프로세스) 내에 위치해 있지만, 각기 다른 자원과 규칙을 가지고 있습니다.
+---------------+ +---------------+ +---------------+
| AppDomain 1 |-------------| AppDomain 2 |-------------| AppDomain 3 |
| | | | | |
| + Assembly A | | + Assembly B | | + Assembly C |
| + Assembly B | | + Assembly D | | + Assembly A |
+---------------+ +---------------+ +---------------+
AppDomain 간에 직접적인 메시지 교환이 일반적으로는 어렵습니다. 그러나 .NET은 몇 가지 방법을 제공합니다.
객체를 직렬화하여 바이트 스트림으로 만든 다음, 그 스트림을 다른 AppDomain에 전달하여 역직렬화할 수 있습니다.
이 클래스를 상속받은 객체를 다른 AppDomain으로 전달할 수 있습니다. 이렇게 하면 원격 프로시를 통해 메시지를 교환할 수 있습니다.
// MarshalByRefObject를 상속받는 클래스
public class Messenger : MarshalByRefObject
{
public void SendMessage(string message)
{
Console.WriteLine($"Received message: {message}");
}
}
// 메인 코드
class Program
{
static void Main(string[] args)
{
// 새로운 AppDomain 생성
AppDomain newDomain = AppDomain.CreateDomain("NewDomain");
// Messenger 객체를 새로운 AppDomain에 생성
Messenger messenger = (Messenger)newDomain.CreateInstanceAndUnwrap(
typeof(Messenger).Assembly.FullName,
typeof(Messenger).FullName);
// 메시지 전송
messenger.SendMessage("Hello from the default AppDomain!");
// AppDomain 언로드
AppDomain.Unload(newDomain);
}
}
이 예시에서는 MarshalByRefObject를 상속받은 Messenger 클래스를 사용하여 메시지를 전송합니다.
이를 통해 다른 AppDomain에 있는 객체와 통신이 가능합니다.
.NET에서는 AppDomain.DoCallBack 메서드를 통해 다른 AppDomain에서 코드를 실행할 수 있습니다.
이 방법은 특히, 코드가 존재하는 AppDomain을 변경해야 할 때 유용합니다.
DoCallBack은 해당 AppDomain의 컨텍스트에서 지정한 delegate를 실행합니다.
아래 예시 코드는 새로운 AppDomain을 생성하고, DoCallBack을 사용하여 그 AppDomain에서 메시지를 출력합니다.
// 메인 코드
class Program
{
static void Main(string[] args)
{
// 새로운 AppDomain 생성
AppDomain newIsland = AppDomain.CreateDomain("NewIsland");
// DoCallBack을 이용하여 새로운 AppDomain에서 코드 실행
newIsland.DoCallBack(() => Console.WriteLine("Hello from the New Island!"));
// AppDomain 언로드
AppDomain.Unload(newIsland);
}
}
이 코드를 실행하면 “Hello from the New Island!”라는 메시지가 출력됩니다.
이 메시지는 newIsland라는 이름의 새로운 AppDomain에서 실행되었습니다.
DoCallBack 메서드를 사용하면, 쉽게 다른 AppDomain에서 코드를 실행할 수 있습니다.
이 기능은 다른 AppDomain에서 어떤 초기화 작업을 수행하거나 상태를 확인해야 할 때 유용하게 사용될 수 있습니다.
이와 같이 AppDomain은 격리된 실행 공간을 제공하지만, 몇 가지 방법으로 이 공간을 넘어 다른 AppDomain과 통신할 수 있습니다.
오늘 여러분은 AppDomain이라는 작은 섬에서 어떻게 큰 여행을 즐길 수 있는지 배웠습니다.
이런 신비한 섬들은 .NET의 세계를 더욱 풍요롭게 만들어 주며, 여러분의 코드도 마찬가지로 더욱 안정적이고 확장 가능하게 만들어 줄 것입니다.
다음 여행에서 뵙겠습니다, 여행자 여러분! 🚀🏝️👋