技术篇(1)--QPG容器的基本用法
http://www.cnblogs.com/QPG2006/articles/246105.html
如果你已经对Castle有一定了解,可以参看:
http://www.cnblogs.com/QPG2006/articles/245667.html
或者直接看下文:
静静的夜晚并非一切都已睡去……
QPG希望借助大家已有的成果,来达到快速开发高质量软件的目的。当然我们也不相信有银弹存在,因为软件开发中最困难的是要面对人的无形的期望,而将说不清楚的事情表达出来,也许才是软件开发的真正困难所在。尤其是在什么所谓的管理系统上,也许没有多少人能看到目标前就已经耗尽了体力!
废话少说,那么QPG平台到底为程序员提供了什么呢?回答是QPG不是包罗万象的框架,他借助castle的IoC\AOP、log4net、NHibernate等提供的强大功能来帮助程序员简化开发任务。QPG本身提供了端到端的服务负载均衡,任何程序在这个世界里都可以提供服务,当然也可以消费服务!当然这肯定对某些人来说还不够,随着今后的需求增加,我们会再集成一些轻量级的有用组件。
下面以一个简单的例子来介绍QPG平台的基本功能:正确高效使用组件、日志、加密压缩。
首先请下载开发演示文件,把它解压到一个目录,你可以看到如下的Basic项目。
们编写了一个产品组件,还有一个销售管理组件。不过那个组件会在今后的AOP里再演示了。现看看产品组件,是否很简单:
{
using System;
public class Product
{
private int _price;
private int _stocks;
private string _name;
public Product()
{
_name="";
_price=0;
_stocks=0;
Console.WriteLine("call Product()");//用来查看容器是否自动初始化对象
}
public Product(string name,int price,int num) {
_name=name;
_price=price;
_stocks=num;
Console.WriteLine(string.Format("Product({0},{1},{2})",name,price,num));
}
public virtual string Name{
get{return _name;}
}
public virtual int Price{
get{return _price;}
}
public virtual int Stocks{
get{return _stocks;}
}
public virtual void setPrice(int newPrice) {
_price=newPrice;
}
public virtual void outStock(int num) {
int temp=_stocks-num;
if(temp<0) throw new Exception("stock lack!");
_stocks=temp;
}
}
}
打开bin\Debug\config\app_config.xml,这个文件用来配置您自己编写的组件。本例中的配置如下:
<configuration>
<components>
<component id="p1" type="QPG.Demo.Components.Product,Basic" lifestyle="Singleton" >
<parameters>
<name>P1</name>
<price>333</price>
<num>33</num>
</parameters>
</component>
<component id="p2" type="QPG.Demo.Components.Product,Basic" lifestyle="Pooled" initialPoolSize="2" maxPoolSize="4" />
<component id="p3" type="QPG.Demo.Components.Product,Basic" lifestyle="Transient" />
</components>
</configuration>
我们配置了三个Product对象:
p1就只会存在一个,并且不会被容器释放;
p2会存在至少两个实例,当内存池不够时容器会创建时新的并且加入到实例池,但是最多只有4个。是否比较难理解?我们拿孙悟空为例,虽然可以变出许多猴子,但是都是他的替身罢了。
p 3则总是新人,但愿谈恋爱的弟弟妹妹不要这样:-)
看看我们的测试片断:
public class LisfCycleTester {
private SimpleContainer container;
[SetUp]
public void Init() {
Hashtable ht=new Hashtable();
//ht.Add("qpg.email_sender",typeof(EmailSender));
container = new SimpleContainer(ht);
}
[TearDown]
public void Finish() {
container.Dispose();
}
private void visitProduct(string key,int num) {
Product p;
ArrayList ps=new ArrayList();
int i;
for( i=0;i<num;i++) {
p=container[key] as Product;
Console.WriteLine("{0}--{1}",i+1,p.Price);
p.setPrice((i+1)*10);//看看是否实用了新对象
ps.Add(p);
}
for(i=0;i<ps.Count;i++) {
container.Release(ps[i]);
}
ps.Clear();
}
private void visitPooledProduct(string key,int num) {
Product p;
int i;
for( i=0;i<num;i++) {
p=container[key] as Product;
Console.WriteLine("{0}--{1}",i+1,p.Price);
p.setPrice((i+1)*10);
container.Release(p);
}
}
private void runTest(string key) {
long t1=System.Environment.TickCount;
visitProduct(key,4);
if(key!="p2") visitProduct(key,10000);
else visitPooledProduct(key,10000);
long t2=System.Environment.TickCount-t1;
Console.WriteLine("{0}ms",t2);
}
[Test]
public void tesSingleton() {
runTest("p1");
}
[Test]
public void testPool() {
runTest("p2");
}
[Test]
public void testMany() {
runTest("p3");
}
让我们来看看执行的结果如何吧:
先运行tesSingleton
call Product()
call Product()
Product(P1,333,33)
1--333
2—10 //哈哈:第二次使用的还是那个对象,我们在前次给他的价格已经设置为10元了
3--20
4--30
1--40
2--10
3—20
。。。。。。
您可以看到系统先产生了2个Product,那是因为p2最少有两个,平台已经知道我们的期望,自动帮我们做了!
P1只被产生一次:Product(P1,333,33),这些初始值就是我们在配置文件里写的,不是吗?
在我的机器上运行10004次访问花费了1610ms
再看看testPool()
call Product()
1--0
2--0
call Product()
3--0
call Product()
4--0
1--40
2--10
3--20
4--30
5--40
6--50
7--60
8--70
9--80
。。。。。。
您可以看到虽然系统先产生了2个Product,但是在访问并且不释放情况下第三、四次访问时,系统调用了缺省构造函数来产生一个新的实例。以后使用访问并释放的方法,这四个实例满足了我们一万次的访问。在我的机器上,这个TestCase用了1687ms,也证明尽管有缓存,但是毕竟构造两次也花了些时间。所以没有Singleton快。
最后再看看每次都来个新的:
call Product()
call Product()
call Product()
1--0
call Product()
2--0
call Product()
3--0
call Product()
4--0
call Product()
1--0
call Product()
2--0
call Product()
3--0
call Product()
4--0
call Product()
。。。。。。
您可以看到确是每次都会产生新的,这样肯定最慢了,在我机器上用了4031ms。
测试程序里还演示了两个常用的功能,写日志和加密压缩。演示结果您可以在LOG\下发现一个log.txt,打开看看应该如下:
[DEBUG][2005-09-27 21:23:09,484]--hello world! SO SIMPLE!
是否太过简单?如果您了解log4net ,您可以配置成您想要的日志方式,比如写系统日志、谢数据库、远程对象、UDP广播等。
在看看加密压缩吧:
Zip:UEsDBBQAAAAIAEi0OzMnz+xKCgAAAAgAAAAHAAAARFRPLnhtbAsMcNcrSS0uAQBQSwECFAAUAAgACABItDszJ8/sSgoAAAAIAAAABwAAAAAAAAAAAAAAAAAAAAAARFRPLnhtbFBLBQYAAAAAAQABADUAAAAvAAAAAAA=
Encrypt:cvvPjAY7PxOBywAak7KOw6b5J157cRpVLm4pUWDJIc+i3ihSvn5OMahF1sFDrkckMxvLod78maAQppESMCKa0x9pJxvrZbN5i/rMMNSTfF6ffA57JhyhZSgNMrufC0daVX
Decrypt:UEsDBBQAAAAIAEi0OzMnz+xKCgAAAAgAAAAHAAAARFRPLnhtbAsMcNcrSS0uAQBQSwECFAAUAAgACABItDszJ8/sSgoAAAAIAAAABwAAAAAAAAAAAAAAAAAAAAAARFRPLnhtbFBLBQYAAAAAAQABADUAAAAvAAAAAAA=
UnZip:QPG.test
这就是我们要的,是很简单,基本够用就好!
另外心细的读者会发现SimpleContainer.MessageQueue,这是干什么的呢?那是我们分布式处理的消息队列代理,且听下回分解......
(在没有正确配置时使用会报错喔!)