一个基于Spring.Net AOP,实现的一个关于应用程序配置文件的加载和回写的解决方案。通过简单的设置,可以再特定的方法调用前加载配置,方法调用后保存参数。
项目地址:https://gitcafe.com/atskyline/ZConfig
你需要一个基本的配置对象,例如如下 ProgramConfig.cs
1: using System;
2:
3: namespace Sample.Config
4: {
5: public class ProgramConfig
6: {
7: public String ProgramPath { get; set; }
8: }
9: }
2.你需要一个继承于ZConfig.IUseConfig的接口,并在接口中声明配置对象的属性,实现这个接口的所有类将支持由ZConfig自动加载和回写接口中的所有属性(通过反射实现)。例如IUseProgramConfig.cs
1: using ZConfig;
2: namespace Sample.Config
3: {
4: public interface IUseProgramConfig : IUseConfig
5: {
6: ProgramConfig ProgramConfig { get; set; }
7: }
8: }
3.在你程序中需要配置对象的类中实现自定义的ZConfig.IUseConfig的子接口,并且在有修改配置对象的方法上标记上ModifyConfig特性,例如Program.cs
1: using System;
2: using Sample.Config;
3: using Spring.Context.Support;
4: using ZConfig.Attribute;
5:
6: namespace Sample
7: {
8: public interface IProgram
9: {
10: void UpdatePath();
11: void PrintPath();
12: }
13: public class Program : IUseProgramConfig, IProgram
14: {
15: public ProgramConfig ProgramConfig { get; set; }
16:
17: [ModifyConfig]
18: public virtual void UpdatePath()
19: {
20: ProgramConfig.ProgramPath = "../" + ProgramConfig.ProgramPath;
21: }
22:
23: public virtual void PrintPath()
24: {
25: Console.WriteLine(ProgramConfig.ProgramPath);
26: }
27: }
28: }
4.在你应用程序的Spring配置中中导入ZConfig配置
1: <import resource="assembly://ZConfig/ZConfig/ZConfig.xml" />
5.最后给一个使用的例子
1: static void Main(string[] args)
2: {
3: var appContext = ContextRegistry.GetContext();
4: IProgram program = (IProgram)appContext["Program"];
5: program.PrintPath();
6: program.UpdatePath();
7: program.PrintPath();
8: Console.ReadLine();
9: }
除了一个约定用的ZConfig.IUseConfig以外还有以下几个部分
指定AOP的切入点,现在又三个实现
1.ConfigInterfacePointcut
这是另外两个Pointcut的基类,拦截所有实现了IUseConfig的类
2.ModifyConfigPointcut
不仅类要实现IUseConfig,而且方法必须标记[ModifyConfig]
3.NeedConfigPointcut
不仅类要实现IUseConfig,而且方法必须标记[NeedConfig]
定义了ModifyConfigAttribute和NeedConfigAttribute用于丰富切入点的选择。
加载和保存的配置的实现。现在提供了三个Advice
实现的思路是获取所有实现的IUseConfig的实例,反射迭代IUseConfig中定义的属性,使用ConfigPersistance 加载 或 保存 配置对象。
定义了一个接口IConfigPersistance,用于加载和保存配置
1: namespace ZConfig.Persistance
2: {
3: public interface IConfigPersistance
4: {
5: void LoadTo(object config);
6: void Save(object config);
7: }
8: }
还有一个XmlPersistance,使用XML序列化方式保存和加载配置对象
默认配置的行为是,在所有实现了IUseConfig,的类的任何方法调用前加载配置,仅在标记了[ModifyConfig]特性的方法调用后才执行回写配置。默认配置文件如下
1: <?xml version="1.0" encoding="utf-8" ?>
2: <objects xmlns="http://www.springframework.net"
3: xmlns:aop="http://www.springframework.net/aop">
4:
5: <object id="ProxyCreator"
6: type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>
7:
8: <!--Pointcut-->
9: <object id="ConfigInterfacePointcut"
10: type="ZConfig.Pointcut.ConfigInterfacePointcut, ZConfig" />
11:
12: <object id="ModifyConfigPointcut"
13: type="ZConfig.Pointcut.ModifyConfigPointcut, ZConfig" />
14:
15: <!--Persistance-->
16: <object id="XmlPersistance"
17: type="ZConfig.Persistance.XmlPersistance, ZConfig" />
18:
19: <!--Advice-->
20: <object id="LoadConfigAdvice"
21: type="ZConfig.Advice.LoadConfigAdvice, ZConfig">
22: <property name="ConfigPersistance" ref="XmlPersistance" />
23: </object>
24:
25: <object id="SaveConfigAdvice"
26: type="ZConfig.Advice.SaveConfigAdvice, ZConfig">
27: <property name="ConfigPersistance" ref="XmlPersistance" />
28: </object>
29:
30: <!--Advisor-->
31: <object type="Spring.Aop.Support.DefaultPointcutAdvisor,Spring.Aop">
32: <property name="Pointcut" ref="ConfigInterfacePointcut" />
33: <property name="Advice" ref="LoadConfigAdvice" />
34: </object>
35:
36: <object type="Spring.Aop.Support.DefaultPointcutAdvisor,Spring.Aop">
37: <property name="Pointcut" ref="ModifyConfigPointcut" />
38: <property name="Advice" ref="SaveConfigAdvice" />
39: </object>
40:
41: </objects>
通过修改Advice的ConfigPersistance可以改变配置持久化的方式。修改Advisor中Pointcut和Advice可以改变加载和回写的时间和行为。比如所有方法调用前加载调用后回写,或者必须标记[NeedConfig]才去读取配置
现在配置文件名的规则为config.GetType().Name + ".xml"
这个导致同类型的配置实例都会存储到同一个文件中去。
不能使用GetHashCode,作为文件名称的一部分,因为默认的HashCode在每次运行时都不同。
可以考虑采用一个维护一个缓存加上更复杂的文件名管理方式,或者强制要求config有一个唯一标示符