这段时间又在研究AOP了,对各种动态注入原理的AOP已经不感兴趣了,想研究一下静态注入的AOP,首当其冲的是PostSharp。
PS:Routing 和ASP.NET MVC的文章暂时放一放了
所谓静态注入,指的是在编译好的程序集(最好叫装配集)中的类型或者某个方法里注入IL代码(而不是在程序集的运行时注入),注入的地方称为"Join-Point".
有好多工具都可以读写程序集,注入IL代码,如Reflector的一个插件。但是PostSharp是在你编译一个程序集的时候就把IL注入到程序集里去了。
PostSharp并不像ReSharp一样,它不是VS的一个插件,它也不是在编辑器里修改代码的。
那么,PostSharp是如何起作用的呢?
它是怎么把自己插入到编译器的编译生成过程的呢?
我们都知道VS是通过MSBiuld来执行生成过程的,所以其实PostSharp是把自己作为一系列的Build Task来插入到生成过程的。
然后它修改了VS调用MSBiuld的默认配置。从而使VS的Build命令执行了它所指定的Task。下面的图说明了PostSharp的原理:
但是要真正理解静态注入的原理,要理解IL读写,还需要深入了解.net程序集,了解CLI和IL。
要真正知道PostSharp是如何工作的就必须了解MSBuild,知道怎么执行自定义的Build Task.
有很多东西VS都给我们做了,所以我们不了解,有很多开发人员现在还认为.NET 的程序集就是一个托管DLL文件呢!
接下来我将要写一些关于这方面的文章。
不过大家可以在下面的两个链接找到MSBuild的文档:
http://msdn.microsoft.com/zh-cn/library/wea2sca5.aspx
http://msdn.microsoft.com/zh-cn/library/0k6kkbsd.aspx
引用一下PostSharp文档里的一段:
Difference between the PostSharp Code Object Model and System.Reflection
PostSharp uses the entities defined in the specifications of the Common Language Infrastructure (CLI). However, developers are more familiar with the concepts of
System.Reflection
. They should be aware thanSystem.Reflection
includes great simplifications with respect to CLI specifications. CLI is module oriented. A module is an atomic artifact that can bind to other modules to form complete applications. In order to refer to types defined outside the current module, one uses references. By contrast,System.Reflection
lives in the application universe where all references between modules are already resolved. In CLI and in PostSharp, references are explicitly represented as separate entities. But inSystem.Reflection
, there is simply no concept of reference.Modules
Modules (ModuleDeclaration) are atomic artifacts (i.e. they cannot be separated in smaller units). .NET modules are in fact Portable Executables (PE) just like native libraries and executables.
Assemblies
There is a common confusion about assemblies. An assembly, as indicated by its name, is a set of assembled modules and other files. So an assembly can be composed of many modules and even of unmanaged modules! It is a common mistake and misleading to consider that an assembly is composed of a single file.
What defines intrinsically the assembly is its assembly manifest (AssemblyManifestDeclaration). The manifest is composed of a list of references to modules and external assemblies, and of a list of exported types. The assembly manifest is contained in 'principal' managed module of the assembly (and not in a separate XML file, as claims another frequent mistake).
So the assembly manifest (AssemblyManifestDeclaration) is contained in a module (ModuleDeclaration); it contains references to external modules (ModuleRefDeclaration) and external assemblies (AssemblyRefDeclaration).
So let's summarize:
- Modules, not assemblies, are the real atoms.
- Assemblies are composed of many modules (managed or unmanaged executables).
- Assemblies are defined by an assembly manifest.
- The assembly manifest is stored in a managed module.
- A managed module may, but is not required to, contain an assembly manifest.
PostSharp makes a difference between an assembly and an assembly manifest. The AssemblyEnvelope class encapsulates the assembly understood as a collection of modules. The AssemblyManifestDeclaration class encapsulates the manifest; it does not contain modules but is contained by a module. Where AssemblyManifestDeclaration contains a collection of references to modules, AssemblyEnvelope contain modules in themselves.
Domains
PostSharp domains (Domain) are similar to the .NET class
AppDomain
. Domains are contexts in which references between assemblies are solved. Just as in .NET, PostSharp assemblies are always loaded in a domain. PostSharp allows many domains to be loaded paralelly, even in the sameAppDomain
.The base of the object tree is the ModuleDeclaration type. Since PostSharp is module-oriented, everything is contained in the module even the assembly manifest.