摘要:我们知道在Enterprise Library1.1中对于每一个应用程序块都有一个对应的配置文件,而在Enterprise Library2.0中却把所有的配置信息都放在了应用程序配置文件(App.config或Web.config)中,在2.0下,我们如何使用外部配置文件?如何为每个应用程序块创建对应的配置文件?
主要内容
1
.不使用外部配置文件
2
.使用不同的ConfigurationSource
3
.使用多个ConfigurationSource
4
.使用.NET的configSource特性
一.不使用外部配置文件
我们先来看一个简单的使用Enterprise Library的例子,在这个示例中,使用了企业库的Data Access Application Block和 Excepiton Handling Application Block。
using
System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
namespace EntLibConfig
{
class Program
{
static void Main(string[] args)
{
try
{
Database db = DatabaseFactory.CreateDatabase("EntLibInstance");
db.ExecuteNonQuery("ProcName");
}
catch (Exception ex)
{
if (ExceptionPolicy.HandleException(ex, "Event Policy"))
throw;
}
}
}
}
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
namespace EntLibConfig
{
class Program
{
static void Main(string[] args)
{
try
{
Database db = DatabaseFactory.CreateDatabase("EntLibInstance");
db.ExecuteNonQuery("ProcName");
}
catch (Exception ex)
{
if (ExceptionPolicy.HandleException(ex, "Event Policy"))
throw;
}
}
}
}
使用
Enterprise Library Configuration配置之后,
App.config文件如下:
<?
xml version="1.0" encoding="utf-8"
?>
< configuration >
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
< configuration >
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
我们知道在
EL1.1下,对于不同的应用程序块是放在了不同的配置文件中,而到了
2.0中可以看到,所有的配置信息都放在了应用程序配置文件中(
App.config或者
Web.config)。但是很多时候配置文件中有很多的信息也是我们自己手动添加的,如果这些混合在一起会显得非常混乱,所以我们并不想把所有的配置信息都放在应用程序配置文件中,该如何实现呢?
Tom Hollander给了我们几种可行的方案。
二.使用不用的ConfigurationSource
Enterprise Library2.0
使用实现了IConfigurationSource接口的类来获取配置信息,默认情况下将获取SystemConfigurationSource,就像上面的例子,但是它允许我们配置应用程序来使用不同的ConfigurationSource,下面来看一下具体的使用。
用EntLibConfig.exe打开配置文件后,在配置文件节点上选择New | ConfigurationSources。
并新建一个File Configuration Source,指定文件的路径和文件名
在Configuration Source节点设置SelectSource为File Configuration Source
保存配置后,此时就有了两个配置文件,App.config和external.config,分别看一下这两个文件中的内容:
App.config
<?
xml version="1.0" encoding="utf-8"
?>
< configuration >
< configSections >
< section name ="enterpriseLibrary.ConfigurationSource" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< enterpriseLibrary .ConfigurationSource selectedSource ="File Configuration Source" >
< sources >
< add name ="File Configuration Source" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
filePath ="D:\Visual Studio2005 Project\EntLibConfig\EntLibConfig\external.config" />
< add name ="System Configuration Source" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ sources >
</ enterpriseLibrary.ConfigurationSource >
</ configuration >
< configuration >
< configSections >
< section name ="enterpriseLibrary.ConfigurationSource" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< enterpriseLibrary .ConfigurationSource selectedSource ="File Configuration Source" >
< sources >
< add name ="File Configuration Source" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
filePath ="D:\Visual Studio2005 Project\EntLibConfig\EntLibConfig\external.config" />
< add name ="System Configuration Source" type ="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ sources >
</ enterpriseLibrary.ConfigurationSource >
</ configuration >
external.config
<
configuration
>
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
三.使用多个ConfigurationSource
当然了上面的解决方案我们可以看到,还是存在一些问题,首先使用external.config仅仅是把应用程序配置文件中的一部分分割出去放在了external.config中,我们仍然需要App.config文件来指定使用的是哪一个ConfigurationSource;其次两个应用程序块的配置信息放在了同一个文件中。这样我们就考虑对每一个应用程序块都能有一个配置文件,并且不使用App.config文件来指定使用哪一个,这样就要用编程的方法,可以使用静态的DatabaseFactory和ExceptionPolicy,如下面的例子所示:
static
void
Main(
string
[] args)
{
try
{
FileConfigurationSource dataSource = new FileConfigurationSource("data-filesource.config");
DatabaseProviderFactory dbFactory = new DatabaseProviderFactory(dataSource);
Database db = dbFactory.Create("EntLibInstance");
db.ExecuteNonQuery("ProcName");
}
catch (Exception ex)
{
FileConfigurationSource exceptionsSource = new FileConfigurationSource("exceptions-filesource.config");
ExceptionPolicyFactory exceptionFactory = new ExceptionPolicyFactory(exceptionsSource);
ExceptionPolicyImpl exceptionPolicy = exceptionFactory.Create("Event Policy");
if (exceptionPolicy.HandleException(ex))
throw;
}
}
{
try
{
FileConfigurationSource dataSource = new FileConfigurationSource("data-filesource.config");
DatabaseProviderFactory dbFactory = new DatabaseProviderFactory(dataSource);
Database db = dbFactory.Create("EntLibInstance");
db.ExecuteNonQuery("ProcName");
}
catch (Exception ex)
{
FileConfigurationSource exceptionsSource = new FileConfigurationSource("exceptions-filesource.config");
ExceptionPolicyFactory exceptionFactory = new ExceptionPolicyFactory(exceptionsSource);
ExceptionPolicyImpl exceptionPolicy = exceptionFactory.Create("Event Policy");
if (exceptionPolicy.HandleException(ex))
throw;
}
}
data-filesource.config
<?
xml version="1.0" encoding="utf-8"
?>
< configuration >
< configSections >
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
< configuration >
< configSections >
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
</ configuration >
exceptions.filesource.config
<?
xml version="1.0" encoding="utf-8"
?>
< configuration >
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
</ configuration >
< configuration >
< configSections >
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
</ configuration >
这种解决方案其实也是存在了很多的问题:首先是把配置文件名硬编码到了程序了;第二,对于配置文件只能先在
App.config中做完配置后再手动分割到不同的文件中。
四.使用.NET的configSource特性
.NET Framework2.0
中System.Configuration允许对于应用程序配置文件中的每个配置区放到一个外部配置文件中,再用configSource的特性来指定各个配置区的外部文件。但是这种解决方案仍然是不能直接使用EntLibConfig.exe来配置,因为配置工具不能识别configSource。所以一个好的办法就是先使用EntLibConfig.exe在App.config中配置,最后再手动修改。这种方式对于使用Enterprise Library来说代码不变,如我们刚开始的例子所示,应用程序配置文件如下:
<?
xml version="1.0" encoding="utf-8"
?>
< configuration >
< configSections >
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling configSource ="exceptions.config" />
< connectionStrings configSource ="data.config" />
</ configuration >
< configuration >
< configSections >
< section name ="dataConfiguration" type ="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
< section name ="exceptionHandling" type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ configSections >
< exceptionHandling configSource ="exceptions.config" />
< connectionStrings configSource ="data.config" />
</ configuration >
data.config
<?
xml version="1.0" encoding="utf-8"
?>
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
< dataConfiguration defaultDatabase ="EntLibInstance" />
< connectionStrings >
< add name ="EntLibInstance" connectionString ="Server=.\SQLEXPRESS;Integrated Security=SSPI;Database=Northwind;"
providerName ="System.Data.SqlClient" />
</ connectionStrings >
exceptions.config
<?
xml version="1.0" encoding="utf-8"
?>
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
< exceptionHandling >
< exceptionPolicies >
< add name ="Event Policy" >
< exceptionTypes >
< add type ="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction ="ThrowNewException" name ="Exception" >
< exceptionHandlers >
< add exceptionMessage ="This is a test!" replaceExceptionType ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionHandlingException, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
type ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name ="Replace Handler" />
</ exceptionHandlers >
</ add >
</ exceptionTypes >
</ add >
</ exceptionPolicies >
</ exceptionHandling >
以上几种方案仅仅是给你一个参考,你可以在开发中根据实际情况选用其中的一种或者使用默认的方式。
[注:本系列很多可能来自于国外一些技术Blog,我将重新加以整理]
本文转自lihuijun51CTO博客,原文链接:
http://blog.51cto.com/terrylee/67625
,如需转载请自行联系原作者