Tony Huang's profileSouline PLUS planBlogListsNetwork Tools Help

Blog


    21 December

    一些常用组件的用法

    今天要用一些常用的组件,但是却忘记了具体的做法,在网上找了好久才,找到,就干脆在自己博客上记录一下,以后用起来方便一点吧。
     
    1) Log4net 的配置和使用
    配置:
    <?xml version="1.0" encoding="utf-8" ?>
    <log4net>
      <root>
      </root>
      <logger name="CallLog">
        <level value="ALL" />
        <appender-ref ref="CallLogAppender" />
      </logger>
      <appender name="CallLogAppender" type="log4net.Appender.FileAppender">
        <param name="File" value="E:\logs\World\CallLog.log" />
        <param name="AppendToFile" value="true" />
        <param name="RollingStyle" value="Date" />
        <param name="DatePattern" value="yyyy-MM-dd HH:mm:ss" />
        <param name="StaticLogFileName" value="false" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%d [%t] %-5p %c - %m%n" />
        </layout>
      </appender>
    </log4net>
    具体的内容我也不解释,大家就将就着看吧,参考类的东西,就不用那么详尽了,呵呵
     
    初始化:
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "log4net.config.xml");
            log4net.Config.XmlConfigurator.Configure(doc.DocumentElement);
    使用:
            var log = log4net.LogManager.GetLogger("CallLogger");
            log.DebugFormat("{0}.{1} called", className, methodName);
     
    2、Castle.Windsor.WindsorContainer
    常用的轻量级IoC容器。
    配置:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <components>
        <!-- WebServiceManager -->
        <component id="WebServiceManager"
                   service="Souline.Basic.Facility.WebServiceManager, Souline.Basic.Facility"
                   type="Souline.Basic.Facility.WebServiceManager, Souline.Basic.Facility">
          <parameters>
            <services>
              <item type="System.String">
                <item>Souline.World.WebService.LoginService, Souline.World.WebService</item>
              </item>
            </services>
          </parameters>
        </component>
       
        <!-- Logger -->
        <component id="CallLogger"
                   service="Souline.Basic.Contract.ILogService, Souline.Basic.Contract"
                   type="Souline.Basic.Facility.Log4netLogService, Souline.Basic.Facility">
          <parameters>
            <loggerName>CallLog</loggerName>
          </parameters>
        </component>
        <component id="CallLoggerInterceptor"
                   type="Souline.Basic.Facility.Interceptor.LogServiceInterceptor, Souline.Basic.Facility">
          <parameters>
            <logService>${CallLogger}</logService>
            <logLevel>Debug</logLevel>
            <format>{datetime} [{pid}:{tid}] {class} : {method} > {message}</format>
          </parameters>
        </component>
       
        <!-- LoginService -->
        <component id="LoginServiceCache"
                   service="Souline.Basic.Contract.ICacheService`2[[System.String], [System.Object]], Souline.Basic.Contract"
                   type="Souline.Basic.Facility.LocalMemoryCacheService`2[[System.String], [System.Object]], Souline.Basic.Facility">
        </component>
        <component id="LoginService"
                   service="Souline.Basic.Contract.ILoginService, Souline.Basic.Contract"
                   type="Souline.Basic.LoginService, Souline.Basic">
          <parameters>
            <userCache>${LoginServiceCache}</userCache>
          </parameters>
          <interceptors>
            <interceptor>${CallLoggerInterceptor}</interceptor>
          </interceptors>
        </component>
                  
      </components>
      <facilities>
        <facility id="factorysupport" type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
      </facilities>
    </configuration>
     
    初始化:
            _container = new WindsorContainer(new Castle.Windsor.Configuration.Interpreters.XmlInterpreter(containerConfig));
    使用:
            var loginService = _container.GetService<Souline.Basic.Contract.ILoginService>();
     
    3、Castle.ActiveRecord
    配置:
    <?xml version="1.0" encoding="utf-8" ?>
    <activerecord>
      <config>
        <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
        <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
        <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
        <add key="hibernate.connection.connection_string" value="Data Source=.;Initial Catalog=World;Integrated Security=True;" />
      </config>
    </activerecord>
     
    初始化:
            Castle.ActiveRecord.ActiveRecordStarter.Initialize(
                new Castle.ActiveRecord.Framework.Config.XmlConfigurationSource(
                    AppDomain.CurrentDomain.BaseDirectory + "Castle.ActiveRecord.config.xml"),
                typeof(Souline.Basic.Entity.User));
    实体类:
    namespace Souline.Basic.Entity
    {
        [ActiveRecord("Basic_Login_User")]
        public class User : ActiveRecordBase<User>
        {
            [PrimaryKey]
            public virtual int Id
            {
                get;
                set;
            }
            [Property]
            public virtual string Username
            {
                get;
                set;
            }
            [Property]
            public virtual string PasswordHash
            {
                get;
                set;
            }
            [Property]
            public virtual string Type
            {
                get;
                set;
            }
            [Property]
            public virtual string Status
            {
                get;
                set;
            }
            public static Entity.User FindByUsername(string username)
            {
                Entity.User[] users = FindAllByProperty("Username", username);
                if (users.Length == 0)
                    return null;
                else
                    return users[0];
            }
        }
    }
    用法:
        直接使用 Entity.User类就好了
     
    19 December

    关于AOP和IoC

    AOP是最近非常热门的词,全称叫作Aspect-oriented Programming,一直以来,我对这个名词的理解就是模模糊糊的。
     
    知道最近在一个项目中,思考Log模块和Cache模块的设计的时候,才使我恍然大悟,原来AOP就是这么简单、自然的概念。
     
    所谓的AOP就是希望程序员在编写程序的时候,能够完全关注在应用逻辑本身,而不用去考虑与逻辑本身无关的Facility的东西。我们拿那个经典的取钱的例子为例:
     
    假设现在有一个
    Account类,它保存的是用户帐户的余额:
     
    Account

    <<property>>Balance:decimal
    Deposit(money:decimal)
    Withdraw(money:decimal)

     

    这时,程序员关注的流程是,Deposit和Withdraw本身,诸如校验余额啦,修改余额啦什么的。

    这时项目经理过来跟架构师说,我们的客户是银行,需要将所有的调用记录都保存下来备案,保证数据的安全。 但是现在的架构如果需要添加这个功能,则必须在每个方法的开头、结束等处加上日志相关的代码,但这势必造成工作量快速变大。那么AOP是如何解决这个矛盾的呢?

    那么让我们回头来思考这个问题:

    我们分析一下项目经理的要求是:

    所有操作,都要记录日志,能够反映程序中的热点代码、瓶颈和发生的错误

    关键就是所有和操作两个词,让我们回想一下Dynamic Proxy的功能:

    拦截某类的所有方法调用,并插入执行代码

    是不是刚好和我们的需求有匹配的地方呢?

    经过修改的Account类变成了这个样子:

    Account

    <<property>>Balance:decimal
    <<virtual>>Deposit(money:decimal)
    <<virtual>>Withdraw(money:decimal)

     

    利用DynamicProxy类动态的生成一个继承自Account 类的类,并重写(override)它的所有方法,加入拦截的函数。再编写LogIntercepter类,记录所有的调用信息。

    这就是AOP。我们没有修改原有的代码(基本没有,除了virtual关键字),但是却加入了某一方面(aspect)的功能。

     

    那么我为什么要把AOP和IoC一起讲呢,因为他们之间有着密不可分的联系,我以.Net平台下的Castle库中的Windsor/MicroKernel容器为例。它提供了一个轻量级的IoC容器,提供了一种方便的方式配置组建和拦截器,基于配置的实现AOP的功能。具体的做法,我在下一篇文章中再写吧,有点晚了,去睡觉咯~

    01 December

    一种有关锁的设计模式

    今天看了一个ThreadSafeDictionary的代码,从里面看到了一个很好的使用锁的设计模式,首先从使用开始说:
     
    public void Set(TKey key, TKey value)
    {
        using(new WriterLock(this._lock))
        {
            // do something
        }
    }
     
    然后再看看WriterLock的实现:
    class WriterLock : IDispose
    {
        private ReaderWriterLockSlim _lock;
        public WriterLock(ReaderWriterLockSlim lock)
        {
            _lock = lock;
            _lock.GetWriterLock(lock);
        }
        public Dispose()
        {
            _lock.ReleaseWriterLock(_lock);
        }
    }
     
    他的作用机理是什么呢?
    首先我们从using开始看,using语句中包含了一个new语句,这就调用了WriterLock中的ctor,也就是给目标加锁,而当需要保护的代码结束的时候,也就是using块之外的时候,这个新创建的对象已经不再生存期内,所以就自动调用了WriterLock中的Dispose方法。
     
    这是非常值得借鉴的一种设计模式,在NHibernate和Castle.ActiveRecord中也有广泛的应用,比如:
    using(new SessionScope())
    {
        // do something
    }
     
    using(new Transaction())
    {
        // do something
    }