潇's profile老肖的地盘PhotosBlogListsMore ![]() | Help |
|
November 06 死牛肉
October 20 (ZT)详细解读JVM中的对象生命周期也许我了解了,但是我没有了解,对知识的了解不可浅尝辄止啊,转帖一篇文章。 在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与释放阶段(Free)。上面的这7个阶段,构成了 JVM中对象的完整的生命周期。下面分别介绍对象在处于这7个阶段时的不同情形。 2.2.1 创建阶段在对象创建阶段,系统要通过下面的步骤,完成对象的创建过程: (1)为对象分配存储空间。 (2)开始构造对象。 (3)递归调用其超类的构造方法。 (4)进行对象实例初始化与变量初始化。 (5)执行构造方法体。 上面的5个步骤中的第3步就是指递归地调用该类所扩展的所有父类的构造方法,一个Java类(除Object类外)至少有一个父类(Object),这个规则既是强制的,也是隐式的。你可能已经注意到在创建一个Java类的时候,并没有显式地声明扩展(extends)一个Object父类。实际上,在 Java程序设计中,任何一个Java类都直接或间接的是Object类的子类。例如下面的代码: public class A { …
}
这个声明等同于下面的声明:
public class A extends java.lang.Object { …
}
上面讲解了对象处于创建阶段时,系统所做的一些处理工作,其中有些过程与应用的性能密切相关,因此在创建对象时,我们应该遵循一些基本的规则,以提高应用的性能。 下面是在创建对象时的几个关键应用规则: (1)避免在循环体中创建对象,即使该对象占用内存空间不大。 (2)尽量及时使对象符合垃圾回收标准。 (3)不要采用过深的继承层次。 (4)访问本地变量优于访问类中的变量。 关于规则(1)避免在循环体中创建对象,即使该对象占用内存空间不大,需要提示一下,这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: … …
for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= "+ obj);
}
… …
上面代码的书写方式相信对你来说不会陌生,也许在以前的应用开发中你也这样做过,尤其是在枚举一个Vector对象中的对象元素的操作中经常会这样书写,但这却违反了上述规则(1),因为这样会浪费较大的内存空间,正确的方法如下所示: … …
Object obj = null;
for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj);
}
… …
采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象应用,浪费大量的内存空间,而且增大了系统做垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 另外,不要对一个对象进行多次初始化,这同样会带来较大的内存开销,降低系统性能,如: public class A {
private Hashtable table = new Hashtable ();
public A() {
// 将Hashtable对象table初始化了两次
table = new Hashtable();
}
}
正确的方式为: public class B {
private Hashtable table = new Hashtable ();
public B() {
}
}
不要小看这个差别,它却使应用软件的性能相差甚远,如图2-5所示。 图2-5 初始化对象多次所带来的性能差别 看来在程序设计中也应该遵从“勿以恶小而为之”的古训,否则我们开发出来的应用也是低效的应用,有时应用软件中的一个极小的失误,就会大幅度地降低整个系统的性能。因此,我们在日常的应用开发中,应该认真对待每一行代码,采用最优化的编写方式,不要忽视细节,不要忽视潜在的问题。 当对象的创建阶段结束之后,该对象通常就会进入对象的应用阶段。这个阶段是对象得以表现自身能力的阶段。也就是说对象的应用阶段是对象整个生命周期中证明自身“存在价值”的时期。在对象的应用阶段,对象具备下列特征: — 系统至少维护着对象的一个强引用(Strong Reference); — 所有对该对象的引用全部是强引用(除非我们显式地使用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference))。 上面提到了几种不同的引用类型。可能一些读者对这几种引用的概念还不是很清楚,下面分别对之加以介绍。在讲解这几种不同类型的引用之前,我们必须先了解一下Java中对象引用的结构层次。 Java对象引用的结构层次示意如图2-6所示。 图2-6 对象引用的结构层次示意 由图2-6我们不难看出,上面所提到的几种引用的层次关系,其中强引用处于顶端,而虚引用则处于底端。下面分别予以介绍。 1.强引用 强引用(Strong Reference)是指JVM内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用。 2.软引用 软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。另外,这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null。它可以用于实现一些常用资源的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory。再者,软可到达对象的所有软引用都要保证在虚拟机抛出 … … import java.lang.ref.SoftReference; … A a = new A(); … // 使用 a … // 使用完了a,将它设置为soft 引用类型,并且释放强引用; SoftReference sr = new SoftReference(a); a = null; … // 下次使用时 if (sr!=null) { a = sr.get(); } else{ // GC由于内存资源不足,可能系统已回收了a的软引用, // 因此需要重新装载。 a = new A(); sr=new SoftReference(a); } … … 软引用技术的引进,使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃(crash)。因此在处理一些占用内存较大而且声明周期较长,但使用并不频繁的对象时应尽量应用该技术。正像上面的代码一样,我们可以在对象被回收之后重新创建(这里是指那些没有保留运行过程中状态的对象),提高应用对内存的使用效率,提高系统稳定性。但事物总是带有两面性的,有利亦有弊。在某些时候对软引用的使用会降低应用的运行效率与性能,例如:应用软引用的对象的初始化过程较为耗时,或者对象的状态在程序的运行过程中发生了变化,都会给重新创建对象与初始化对象带来不同程度的麻烦,有些时候我们要权衡利弊择时应用。 3.弱引用 弱引用(Weak Reference)对象与Soft引用对象的最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象, GC总是进行回收。因此Weak引用对象会更容易、更快被GC回收。虽然,GC在运行时一定回收Weak引用对象,但是复杂关系的Weak对象群常常需要好几次GC的运行才能完成。Weak引用对象常常用于Map数据结构中,引用占用内存空间较大的对象,一旦该对象的强引用为null时,对这个对象引用就不存在了,GC能够快速地回收该对象空间。与软引用类似我们也可以给出相应的应用代码: … …
import java.lang.ref.WeakReference;
…
A a = new A();
…
// 使用 a
…
// 使用完了a,将它设置为weak 引用类型,并且释放强引用;
WeakReference wr = new WeakReference (a);
a = null;
…
// 下次使用时
if (wr!=null) {
a = wr.get();
}
else{
a = new A();
wr = new WeakReference (a);
}
… …
弱引用技术主要适用于实现无法防止其键(或值)被回收的规范化映射。另外,弱引用分为“短弱引用(Short Week Reference)”和“长弱引用(Long Week Reference)”,其区别是长弱引用在对象的Finalize方法被GC调用后依然追踪对象。基于安全考虑,不推荐使用长弱引用。因此建议使用下面的方式创建对象的弱引用。 … … WeakReference wr = new WeakReference(obj); 或 WeakReference wr = new WeakReference(obj, false); … … 4.虚引用 虚引用(Phantom Reference)的用途较少,主要用于辅助finalize函数的使用。Phantom对象指一些执行完了finalize函数,并且为不可达对象,但是还没有被GC回收的对象。这种对象可以辅助finalize进行一些后期的回收工作,我们通过覆盖Reference的clear()方法,增强资源回收机制的灵活性。虚引用主要适用于以某种比 java 终结机制更灵活的方式调度 pre-mortem 清除操作。 &注意 在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。 2.2.3 不可视阶段在一个对象经历了应用阶段之后,那么该对象便处于不可视阶段,说明我们在其他区域的代码中已经不可以再引用它,其强引用已经消失,例如,本地变量超出了其可视范围,如下所示。 … …
public void process () {
try {
Object obj = new Object();
obj.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
while (isLoop) { // ... loops forever
// 这个区域对于obj对象来说已经是不可视的了
// 因此下面的代码在编译时会引发错误
obj.doSomething();
}
}
… …
如果一个对象已使用完,而且在其可视区域不再使用,此时应该主动将其设置为空(null)。可以在上面的代码行obj.doSomething();下添加代码行obj = null;,这样一行代码强制将obj对象置为空值。这样做的意义是,可以帮助JVM及时地发现这个垃圾对象,并且可以及时地回收该对象所占用的系统资源。 2.2.4 不可到达阶段处于不可到达阶段的对象,在虚拟机所管理的对象引用根集合中再也找不到直接或间接的强引用,这些对象通常是指所有线程栈中的临时变量,所有已装载的类的静态变量或者对本地代码接口(JNI)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。其实所有垃圾回收算法所面临的问题是相同的——找出由分配器分配的,但是用户程序不可到达的内存块。 2.2.5 可收集阶段、终结阶段与释放阶段对象生命周期的最后一个阶段是可收集阶段、终结阶段与释放阶段。当对象处于这个阶段的时候,可能处于下面三种情况: (1)垃圾回收器发现该对象已经不可到达。 (2)finalize方法已经被执行。 (3)对象空间已被重用。 当对象处于上面的三种情况时,该对象就处于可收集阶段、终结阶段与释放阶段了。虚拟机就可以直接将该对象回收了。 July 26 SOAP协议规范1. 简介 SOAP以XML形式提供了一个简单、轻量的用于在分散或分布环境中交换结构化和类型信息的机制。SOAP本身并没有定义任何应用程序语义,如编程模型或特定语义的实现;实际上它通过提供一个有标准组件的包模型和在模块中编码数据的机制,定义了一个简单的表示应用程序语义的机制。这使SOAP能够被用于从消息传递到RPC的各种系统。 SOAP包括三个部分
虽然这三个部分都作为SOAP的一部分一起描述,但它们在功能上是相交的。特别的,封装和编码规则是在不同的名域中定义的,这种模块性的定义方法增加了简单性在SOAP封装,SOAP编码规则和SOAPRPC协定之外,这个规范还定义了两个协议的绑定,描述了在有或没有HTTP扩展框架[6]的情况下,SOAP消息如何包含在HTTP消息[5]中被传送。 1.1 设计目标SOAP的主要设计目标是简单性和可扩展性,这意味着传统的消息系统和分布对象系统的某些性质不是SOAP规范的一部分。这些性质包括:
1.2 符号约定这篇文章中的关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT","SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和"OPTIONAL"的解释在RFC-2119 [2]中。这篇文章中用到的名域前缀 "SOAP-ENV" 和"SOAP-ENC"分别与"http://schemas.xmlsoap.org/soap/envelope/" 和"http://schemas.xmlsoap.org/soap/encoding/"关联。整篇文档中,名域前缀“xsi”被假定为与 URI"http://www.w3.org/1999/XMLSchema-instance“(在XMLSchema规范[11]定义)相连。类似的,名域前缀”xsd“被假定为与URI"http://www.w3.org/1999/XMLSchema"(在[10]中定义)相连。名域前缀 ”tns“用来表示任意名域。所有其它的名域前缀都只是例子。 1.3 SOAP消息举例在这个例子中,GetLastTradePrice SOAP 请求被发往StockQuote服务。这个请求携带一个字符串参数和ticker符号,在SOAP应答中返回一个浮点数。XML名域用来区分SOAP标志符和应用程序特定的标志符。这个例子说明了在第6节中定义的HTTP绑定。如果SOAP中管理XML负载的规则完全独立于HTTP是没有意义的,因为事实上该负载是由HTTP携带的。在Appendix A中有更多的例子。 例1 在HTTP请求中嵌入SOAP消息 POST /StockQuote HTTP/1.1 下面是一条应答消息,包括HTTP消息,SOAP消息是其具体内容 : 例2 在HTTP应答中嵌入SOAP消息 HTTP/1.1 200 OK 2. SOAP消息交换模型SOAP 消息从发送方到接收方是单向传送,但正如上面显示的,SOAP消息经常以请求/应答的方式实现。SOAP实现可以通过开发特定网络系统的特性来优化。例如,HTTP绑定(见第6节)使SOAP应答消息以HTTP应答的方式传输,并使用同一个连接返回请求。不管SOAP被绑定到哪个协议,SOAP消息采用所谓的”消息路径“发送,这使在终节点之外的中间节点可以处理消息。一个接收SOAP消息的SOAP应用程序必须按顺序执行以下的动作来处理消息:识别应用程序想要的SOAP消息的所有部分(见4.2.2节)检验应用程序是否支持第一步中识别的消息中所有必需部分并处理它。如果不支持,则丢弃消息(见4.4节)。在不影响处理结果的情况下,处理器可能忽略第一步中识别出的可选部分。如果这个SOAP应用程序不是这个消息的最终目的地,则在转发消息之前删除第一步中识别出来的所有部分。为了正确处理一条消息或者消息的一部分,SOAP处理器需要理解:所用的交换方式(单向,请求/应答,多路发送等等),这种方式下接收者的任务,RPC机制(如果有的话)的使用(如第7节中所述),数据的表现方法或编码,还有其它必需的语义。尽管属性(比如SOAP encodingstyle,见4.1.1节)可以用于描述一个消息的某些方面,但这个规范并不强制所有的接收方也必须有同样的属性并取同样的属性值。举个例子,某一特定的应用可能知道一个元素表示一条遵循第7节约定的RPC请求,但是另外一些应用可能认为指向该元素的所有消息都用单向传输,而不是类似第7节的请求应答模式。 3. 与XML的关系所有的SOAP消息都使用XML形式编码(更多有关XML的信息请见[7])一个SOAP应用程序产生的消息中,所有由SOAP定义的元素和属性中必须包括正确的名域。SOAP应用程序必须能够处理它接收到的消息中的SOAP名域(见4.4节),并且它可以处理没有SOAP名域的SOAP消息,就象它们有正确的名域一样。SOAP定义了两个名域(更多有关XML名域的信息请见[8])
SOAP 消息中不能包含文档类型声明,也不能包括消息处理指令。[7] SOAP使用"ID"类型"id"属性来指定一个元素的唯一的标志符,同时该属性是局部的和无需校验的。SOAP使用"uri-reference"类型的"href"属性指定对这个值的引用,同时该属性是局部的和无需校验的。这样就遵从了XML规范[7],XMLSchema规范[11]和XML连接语言规范[9]的风格。除了SOAP mustUnderstand 属性(见4.2.3节)和SOAPactor属性(见4.2.2节)之外,一般允许属性和它们的值出现在XML文档实例或Schema中(两者效果相同)。也就是说,在DTD或Schema中声明一个缺省值或固定值和在XML文档实例中设置它的值在语义上相同。 4. SOAP封装SOAP消息是一个XML文档,包括一个必需的SOAP封装,一个可选的SOAP头和一个必需的SOAP体。在这篇规范剩余部分中,提到SOAP消息时就是指这个XML文档。这一节中定义的元素和属性的名域标志符为: "http://schemas.xmlsoap.org/soap/envelope/" 。一个SOAP消息包括以下部分:1.在表示这个消息的XML文档中,封装是顶层元素。2.应用SOAP交换信息的各方是分散的且没有预先协定,SOAP 头提供了向SOAP消息中添加关于这条SOAP消息的某些要素(feature)的机制。SOAP定义了少量的属性用来表明这项要素(feature)是否可选以及由谁来处理。(见4.2节)3.SOAP体是包含消息的最终接收者想要的信息的容器(见4.3节)。SOAP为SOAP体定义了一个Fault 元素用来报告错误信息。语法规则如下所示: 封装
SOAP头 (见4.2节)
SOAP体 (见4.3节)
4.1.1 SOAP encodingStyle属性EncodingStyle 全局属性用来表示SOAP消息的序列化规则。这个属性可以在任何元素中出现,作用范围与名域声明的作用范围很相似,为这个元素的内容和它的所有没有重载此属性的子元素。SOAP消息没有定义缺省编码。属性值是一个或多个URI的顺序列表,每个URI确定了一种或多种序列化规则,用来不同程度反序列化 SOAP消息,举例如下: "http://schemas.xmlsoap.org/soap/encoding/" 第 5节中定义的序列化规则由URI"http://schemas.xmlsoap.org/soap/encoding/" 确定。使用这个特定序列化规则的消息应该用encodingStyle属性说明这一点。另外,所有以"http://schemas.xmlsoap.org/soap/encoding/"开头的URI中的序列化规则与第5节中定义的SOAP编码规则相一致。一个零长度的URI("")明确显示所含元素没有任何编码形式。这可以用来取消上一级元素的所有编码声明。 4.1.2 封装版本模型SOAP 没有定义常规的基于主版本号和辅版本号的版本形式。SOAP消息必须有一个封装元素与名域"http://schemas.xmlsoap.org /soap/envelope/"关联。如果SOAP应用程序接收到的SOAP消息中的SOAP封装元素与其他的名域关联,则视为版本错误,应用程序必须丢弃这个消息。如果消息是通过HTTP之类的请求/应答协议收到的,应用程序必须回答一个SOAP VersionMismatch 错误信息(见4.4节)。 4.2 SOAP头SOAP 为相互通信的团体之间提供了一种很灵活的机制:在无须预先协定的情况下,以分散但标准的方式扩展消息。可以在SOAP头中添加条目实现这种扩展,典型的例子有认证,事务管理,支付等等。头元素编码为SOAP封装元素的第一个直接子元素。头元素的所有直接子元素称作条目。条目的编码规则如下: 一个条目有它的完整的元素名(包括名域URI和局部名)确定。SOAP头的直接子元素必须有名域限制。 4.2.1 使用头属性这一节中定义的SOAP头属性确定了SOAP消息的接收者应该怎样按第2节中所述的方式处理消息。产生SOAP消息的SOAP应用程序,应该仅仅在SOAP 头元素的直接子元素中使用这些SOAP头属性。SOAP消息的接收者必须忽略所有不在SOAP头元素的直接子元素中SOAP头属性。下面的例子是一个 SOAP头,包括一个元素标志符"Transaction","mustUnderstand"取值为"1"和数值5。这应该以如下方式编码: <SOAP-ENV:Header> 4.2.2 SOAP actor属性一个SOAP消息从始节点到终节点的过程中,可能沿着消息路径经过一系列SOAP中间节点。一个SOAP中间节点是一个可以接收转发SOAP消息的应用程序。中间节点和终节点由URI区分。可能SOAP消息的终节点并不需要所有部分,而在消息路径上的一个和几个中间节点可能需要这些内容。头元素的接收者扮演的角色类似于一个过滤器,防止这些只发给本接受者的消息部分扩散到其它节点。即一个头元素的接收者必须不转发这些头元素到SOAP消息路径上的下一个应用程序。同样的,接收者可能插入一个相似的头元素。SOAP actor全局属性可以用于指示头元素的接收者。SOAP actor属性的值是一个URI。 URI "http://schemas.xmlsoap.org/soap/actor/next"指出了第一个处理这个消息的SOAP应用程序需要这个头元素。这类似于HTTP头中用Connection域表示hop-by-hop范围模型。省略SOAP actor属性表示接收者是SOAP消息的终节点。如果这个属性要生效,它必须出现在SOAP消息实例中。(见第3节和4.2.1节) 4.2.3 SOAP mustUnderstand属性SOAP mustUnderstand全局属性用来指示接受者在处理消息时这个条目是否必须处理。条目的接收者由SOAP actor属性定义(见4.2.2节)。MustUnderstand属性的值是"1" 或 "0"。缺少SOAP mustUnderstand属性在语义上等同于它的值为"0"。如果一个头元素的SOAP mustUnderstand属性的值是"1",那么条目的接受者必须或者遵守语义(如以元素的全名传送)并按照语义正确的处理,或者放弃处理消息(见4.4节)。SOAP mustUnderstand 属性考虑了消息演变的准确性(robust evolution)。必须假定包含SOAP mustUnderstand属性且值为"1"的元素以某种方式修改了它们的父元素或同层元素的语义。以这种方式连接元素确保了语义上的变化不会被那些不能完全理解它的接收者忽略。如果这个属性要生效,它必须出现在SOAP消息实例中。(见第3节和4.2.1节) 4.3 SOAP体SOAP 体元素提供了一个简单的机制,使消息的最终接收者能交换必要的信息。使用体元素的典型情况包括配置RPC请求和错误报告。体元素编码为SOAP封装元素的直接子元素。如果已经有一个头元素,那么体元素必须紧跟在头元素之后,否则它必须是SOAP封装元素的第一个直接子元素。体元素的所有直接子元素称作体条目,每个体条目在SOAP体元素中编码为一个独立的元素。条目的编码规则如下:
4.3.1 SOAP头和体的关系虽然头和体定义为独立的元素,它们实际上是有关系的。体条目和头条目的关系如下:体条目在语义上等同于actor属性为缺省值且mustUnderstand属性值为"1"的头条目。不使用actor属性则表示缺省的actor。(见4.2.2节) 4.4 SOAP错误SOAP错误元素用于在SOAP消息中携带错误和(或)状态信息。如果有SOAP错误元素,它必须以以体条目的方式出现,并且在一个体元素中最多出现一次。SOAP错误元素定义了以下四个子元素:
4.4.1 SOAP 错误代码在描述这个规范中定义的错误时,这一节中定义的Faultcode值必须用在faultcode元素中。这些faultcode值得名域标志符为"http://schemas.xmlsoap.org/soap/envelope/"。定义这个规范之外的方法时推荐(不要求)使用这个名域。缺省的SOAP faultcode值以可扩展的方式定义,允许定义新的SOAP faultcode值,并与现有的faultcode值向后兼容。使用的机制类似于HTTP中定义的1xx, 2xx,3xx等基本的状态类(见[5]第10节),不过,它们定义为XML合法名(见 [8] 第3节 ),而不是整数。字符"."(点)作为faultcode的分隔符,点左边的错误代码比右边的错误代码更为普通。如: Client.Authentication 这篇文档中定义的faultcode值是: 名称 VersionMismatch MustUnderstand mustUnderstand Client Client错误类表示消息的格式错误或者不包含适当的正确信息。例如,消息可能缺少正确的认证和支付信息。一般地,它表示消息不能不作修改就重发。参见4.4节 SOAP Fault detail子元素的描述。 Server Server错误类表示由于消息的处理过程而不是消息的内容本身使得消息消息不能正确的处理。例如,处理消息时可能要与其它处理器通信,但它没有响应。这个消息可能在迟一点的时间处理成功。 SOAP Fault子元素的详细信息参见4.4节 5. SOAP编码SOAP 编码格式基于一个简单的类型系统,概括了程序语言,数据库和半结构化数据等类型系统的共同特性。一个类型或者是一个简单的(标量的)类型,或者是由几个部分组合而成的复合类型,其中每个部分都有自己的类型。以下将详细描述这些类型。这一节定义了类型化对象的序列化规则。它分两个层次。首先,给定一个与类型系统的符号系统一致的Schema(译者注:这里的schema不是符合XML语法的schema,而仅仅表示广义的用于表示消息结构的定义方式),就构造了XML语法的Schema。然后,给定一个类型系统的Schema和与这个Schema一致的特定的值,就构造了一个XML文档实例。反之,给定一个依照这些规则产生的XML文档实例和初始的Schema,就可以构造初始值的一个副本。这一节中定义的元素和属性的名域标志符为"http://schemas.xmlsoap.org/soap/encoding/"。下面的例子都假定在上一层的元素中声明了名域。 5.1 XML中的编码类型规则XML允许非常灵活的数据编码方式。SOAP定义了一个较小的规则集合。这一节在总的层次上定义了这些编码规则,下一节将描述特定类型的编码规则的细节。这一节定义的编码规则可以与第7节中所述的RPC调用和应答映射结合使用。下面的术语用来描述编码规则:
在复合类型中,如果类型内的accessor名互不相同,但是可能与其他类型中的accessor名相同,即,accessor名加上类型名形成一个唯一的标志符,这个名叫作"局部范围名"。如果名是直接或间接的基于URI的一部分,那么不管它出现在什么类型中,这个名本身就可以唯一标志这个 accessor,这样的名叫作"全局范围名"。给定了schema中相关的值的序列化信息,就可能确定某些值只与某个accessor的一个实例有关。其它情况下则无法确定。当且仅当一个accessor引用一个值,这个值才能被视为"single-reference",如果有不止一个 accessor引用它,那么就将它视为"multi-reference"。注意,可能一个确定的值在一个schema中是"single- reference",而在另一个schema中是"multi-reference"。在语句构成上,一个元素可能是"independent" 或 "embedded"。一个独立的元素指出现在序列化最顶层的任何元素。所有其它元素都是嵌入元素。虽然用xsi:type属性可以使值的结构和类型变为自描述的,但是序列化规则允许值的类型仅仅参照schema而定。这样的schema可能使用"XML Schema Part 1: Structures" [10]和"XML Schema Part 2: Datatypes" [11]中描述的符号系统,也可能使用其它符号系统。注意,虽然序列化规则可以用于除了数组和结构之外的复合类型,但是许多schema仅仅包含数组和结构类型。序列化规则如下: 所有的值以元素内容的形式表示。一个multi-reference值必须表示为一个独立元素的内容,而一个single-reference值最好不要这样表示(也可以这样表示)。对于每个具有值的元素,值的类型时必须用下述三种方式之一描述:
一个简单值表示为字符数据,即没有任何子元素。每个简单值必须具有一个类型,这个类型或者是XML Schemas Specification, part 2 [11]有的类型,或者具有源类型(参见5.2节)。一个复合值编码成一个元素的序列,每个accessor用一个嵌入元素表示,该元素的元素名和 accessor的名一致。如果accessor的名是局部于其所属的类型的,则该元素的元素名不是合格的,否则对应的元素名是合格的。(参见5.4节) SOAP数组可以时一维或多维,它们的成员以序数位置相互区分。一个数组值表示为反映这个数组的一系列元素,数组成员按升序出现。对多维数组来说,右边的这一维变化最快。每个成员元素命名为一个独立元素。(见规则2)SOAP数组可以是single-reference 或multi-reference值,因此可以表示为嵌入元素或独立元素的内容。SOAP数组必须包含一个"SOAP-ENC:arrayType"属性,它的值指定了包含元素的类型和数组的维数。"SOAP-ENC:arrayType"属性的值定义如下: arrayTypeValue = atype asize
一个SOAP数组成员可能包含一个"SOAP-ENC:offset"属性表示这一项在整个数组中的位置偏移值。这被用来指示一个部分储值数组(见5.4.2.1节)的位置偏移值。同样,一个数组成员可能包含一个"SOAP- ENC:position"属性表示这一项在整个数组中的位置,这被用来描述稀疏数组(见5.4.2.2节)的成员。"SOAP-ENC:offset" 和"SOAP-ENC:position"属性值的定义如下: arrayPoint = "[" #length "]" 5.2 简单类型SOAP采用了"XML Schema Part 2: Datatypes"规范[11]"Built-in datatypes"节中的所有类型作为简单类型,包括值和取值范围。例如: 类型 int float negativeInteger string 在XML Schema规范中声明的数据类型可以直接用在元素schema中,也可以使用从这些类型衍生的新类型。一个schema和对应的具有这些类型的元素的数据实例的例子如下所示:
所有简单值必须编码为元素的内容,它的类型或者在"XML Schema Part 2: Datatypes"规范[11]中定义过,或者是基于一个用XML Schema规范提供的机制能推衍生出的类型。如果一个简单值编码为独立元素或异质数组成员,那么有一个对应于数据类型的元素声明将会很方便。因为"XML Schema Part 2: Datatypes"规范[11]包括了类型定义,但是不包括对应的元素声明,SOAP-ENC schema和名域为每个简单数据类型声明了一个元素,如<SOAP-ENC:int id="int1">45</SOAP-ENC:int> 5.2.1 字符串字符串数据类型的定义在"XML Schema Part 2: Datatypes"规范[11]中。注意,这不同于许多数据库和程序语言中的"string"类型,特别的,字符串数据类型可能禁止某些在那些语言中允许的字符。(这些值必须用xsd:string之外的数据类型表示)一个字符串可能编码为一个single-reference 或 multi-reference值。包含字符串值的元素可能有一个"id"属性。附加的accessor元素可能有对应的"href"属性。
但是,如果两个accessor参考同一字符串实例(或字符串的子类型),这不是一个实质问题,它们可以编码为两个single-reference值,如下所示:
这个例子的schema片断如下所示:
在这个例子中,SOAP-ENC:string类型用作元素的类型,这是声明数据类型是"xsd:string"且允许"id" 和"href"属性的元素的简便方法。精确定义参见SOAP编码schema。Schemas可以使用这些源自SOAP编码schema的声明,但也可以不这样做。 5.2.2 Enumerations"XML Schema Part 2: Datatypes"规范 [11] 定义了"enumeration."机制。SOAP数据模型直接采用了这种机制。但是,由于程序语言和其它语言在定义枚举时通常有些不同,所以我们在这里详细阐述了它的概念并描述了一个列表成员的可能取的值是如何编码的。"Enumeration"作为一个概念表示不同的名字的集合。一个特定的枚举就是对应于特定的基类型的不同的值的列表。例如,颜色集合("Green", "Blue", "Brown")可以定义为基于字符串类型的枚举,("1", "3", "5")可能是一个基于整型数的枚举,等等。"XML Schema Part 2: Datatypes" [11]支持除了布尔型以外所有简单类型的枚举。"XML Schema Part 1: Structures"规范[10]的语言可以用来定义枚举类型。如果schema由另一个没有特定基类型适用的符号系统生成,就使用"string"。在下面schema的例子中,"EyeColor"定义为字符串,可能的值是"Green", "Blue", 或"Brown"的枚举,数据实例按照schema显示如下。
5.2.3 字符数组一个字符数组可能编码为single-reference 或multi-reference值。字符数组的编码规则与字符串的编码规则类似。特别的,包含字符数组的元素值可能由一个"id"属性,附加的 accssor元素可能有相应的"href"属性。推荐使用定义在XML Schemas [10][11]中的'base64'编码(使用在2045 [13]中定义的base64编码算法)表示模糊字符数组。不过,由于行长度(line length)的限制,通常在MIME中应用base64编码,SOAP中一般不应用base64编码。但是提供了"SOAP-ENC:base64"子类型使之能用于SOAP。
5.3 多态accessor许多语言允许能够多态访问多种类型值的accessor,每种类型在运行时可用。一个多态accessor实例必须包含一个"xsi:type"属性描述实际值的类型。例如,一个名为"cost"类型值为"xsd:float"的多态accessor编码如下: <cost xsi:type="xsd:float">29.95</cost>与之对比,类型值不变的accessor编码如下: <cost>29.95</cost> 5.4 Compound types复合类型SOAP定义了与下列常在程序语言中出现的结构性模式对应的类型:
SOAP也允许结构和数组之外的其它数据的序列化,例如Directed-Labeled-Graph Data Model之类的数据中,单个节点有许多不同的accssor,有些不止出现一次。SOAP序列化规则不要求底层的数据模型在accssor之间区分次序,但如果有这样的次序的话,这些accssor必须按照这个顺序编码。 5.4.1 复合值,结构和值引用复合值的成员编码为accessor元素。当accessor由名区分时(如结构),accessor名即作为元素名。名局部于类型的accessor有不受限的名,其它的accessor则有受限的名。下面的例子是类型为"Book"的结构:
以下是描述上面结构的schema片断:
以下是一个同时具有简单和复杂成员类型的例子。它显示两层引用。注意"Author"accssor元素的"href"属性是对相应具有"id"属性的值的引用。"Address"与之类似。
当"Person"的值和"Address"的值是multi-reference时,上面的形式是正确的。如果它
如果添加一个限制,任意两个人都不会有相同的地址,并且地址可以是街道或Email地址,一本书可以有两个作者,编码如下:
序列化可以包含对不在同一个资源的值的引用:
以下是描述上面结构的schema片断:
5.4.2 数组SOAP 数组定义为具有"SOAP-ENC:Array"类型或一个从"SOAP-ENC:Array"衍生的类型(参见规则8)。数组表示为元素值,对元素的名没有特别的约束(正如元素值并不约束它们所属的元素)。数组可以包含任意类型的元素,包括嵌套数组。可以创建新的类型(受SOAP-ENC:Array
在这个例子中,数组"myFavoriteNumbers"包括几个成员,每个成员是一个类型为SOAP-ENC:int的值。注意SOAP- ENC:Array允许不受限制的元素名,它们不传达任何类型信息,所以在使用时,或者它们有xsi:type属性,或者它们所属的元素有SOAP- ENC:arrayType属性。自然,由SOAP-ENC:Array衍生的类型可以声明局部元素,但这种情况下要包括类型信息。上面已经提到,SOAP-ENC schema包含了元素的声明,元素名与"XML Schema Part 2: Datatypes"规范[11]中的简单类型一致。其中包括了对"Array"的声明。于是,我们可以这样写:
数组可以包含特定arrayType的任意子类型的实例。即,数组成员可以是arryType属性值指定的类型的任意子类型,这个类型对于 arrayType属性中指定的类型来说是可替换的(根据schema中的替换规则)。例如,一个整型数组可以包含从整型衍生的任意类型(如"int"或任意用户定义的从整型衍生的类型)。同样,一个"address"数组可能包含一个address的受限类型或扩展类型如"internationalAddress"。因为提供的SOAP-ENC:Array类型允许任意类型的成员,所以可以包含任意类型的混合除非使用 arrayType属性加以特别的限制。在实例中,可以使用xsi:type指定成员元素的类型,或通过schema中成员元素的声明来指定。下面是两个例子。
数组值可以是结构或其它复合值。例如"xyz:Order"结构数组:
数组成员值也可以是数组。下例是两个字符串数组组成的数组:
包含数组的元素无需命名为"SOAP-ENC:Array"。它可以有任意的名,只要元素的类型是SOAP-ENC:Array或由之衍生的类型。例如,下面是一个schema片断和与之一致的数组实例。
数组可能是多维的。在这种情况下,在arrayType属性的asize部分将不止有一个值:
虽然上面的例子把数组编码为独立的元素,但元素值也可以是嵌入形式,而且若元素值是single reference时,必须编码为嵌入形式。下例是一个schema片断,电话号码数组嵌入到一个类型为"Person"的结构中,并且通过accessor "phone-numbers"访问它:
下面的例子中,数组值为single-reference,被编码为嵌入元素,包含它的元素名即为入口名:
5.4.2.1 部分储值(partially transmitted)数组SOAP提供了对部分储值(partially transmitted)数组的支持,如某些上下文中的可变数组。一个partially transmitted 数组由一个"SOAP-ENC:offset"属性(从第一个transmitted的元素开始的偏移量,基于0)指示。如果省略,偏移量取0。下面的例子中数组的大小为5,但只有从0起,第三和第四个元素被储值。
5.4.2.2 稀疏数组Sparse ArraysSOAP提供了对稀疏数组的支持。每个表示成员值的元素包含一个"SOAP-ENC:position"属性,用来指示它在数组中的位置。下例是两维字符串稀疏数组的例子,数组大小是4,但只用到第2个。
如果对array-1的引用仅发生在数组内部,上例也可以编码如下:
5.4.3 一般复合类型在这里提到的编码规则不仅仅限于accessor名已知的情况,如果accessor名是运行环境下实时获得的,编码规则同样适用,也就是说 accessor编码成一个元素名与accessor名匹配的元素,同时accessor可能包含或者引用该元素的值。如果accessor包含类型不能事先确定的值,它必须包含一个合适的属性xsi:type 。类似地,上述引用的规则已经足够用于复合类型的序列化,这些复合类型可能包含用名区分的accessors(结构)和用名及序数位置区分的 accessors。(可能包含重复的accessor)实际上这并不要求任何schema模式包含这些类型,但更为准确的说法是:一个类型模型(type-model)schema如果有这些类型,就可以构造一个符合XML句法规则的schema和XML文档实例。
类似地,将一个结构上类似数组但实际上不是一个 SOAP-ENC:Array类型或者 SOAP-ENC:Array子类型的复合值序列化同样是允许的,例如:
5.5 缺省值省略accessor元素意味着或者有一个缺省值或者值不知道。具体细节依靠这个accessor,方法和上下文。例如,对于多态accessor,省略 accessor一般意味着一个Null值。同样,省略布尔accessor一般意味着False值或者值不知道,省略数字accessor一般意味着值为零或者值不知道。 5.6 SOAP root属性SOAP root 属性可用于标记一个序列化root,从而一个对象可以反序列化(deserialized),而实际上该root并不是真正的对象root。这个属性有两个可选值"1" or "0"。对象真正的roots属性值为“1” ,序列化root但不是真正的root属性值也为“1”,元素如果要显式地指定不能为序列化root,只需将该属性设置为“0” SOAP root属性可以出现在SOAP头和SOAP体元素的任意子元素中。(译者注:SOAP root属性为0的元素不是一个独立的实体,外部的应用不能访问到该元素,但该元素可以被SOAP文档本身的其它元素访问到)SOAP root属性可以出现在SOAP头和SOAP体元素的任意子元素中。这个属性没有缺省值。 6. 在HTTP中使用SOAP这一节讲述了如何在HTTP中使用SOAP。把SOAP绑定到HTTP,无论使用或不用HTTP扩展框架,都有很大的好处:在利用SOAP的形式化和灵活性的同时,使用HTTP种种丰富的特性。在HTTP中携带SOAP消息,并不意味着SOAP改写了HTTP已有的语义,而是将构建在HTTP之上SOAP语义自然地对应到HTTP语义。SOAP自然地遵循HTTP的请求/应答消息模型使得SOAP的请求和应答参数可以包含在HTTP请求和应答中。注意,SOAP的中间节点与HTTP的中间节点并不等同,即,不要期望一个根据HTTP连接头中的域寻址到的HTTP中间节点能够检查或处理HTTP请求中的SOAP消息。 6.1 SOAP HTTP请求虽然SOAP可能与各种HTTP请求方式相结合,但是绑定仅定义了在HTTP POST请求中包含SOAP消息。(第7节中描述了如何在RPC中使用SOAP,第6.3节描述了如何使用HTTP扩展框架) 6.1.1 HTTP头中SOAPAction域一个HTTP请求头中的SOAPAction域用来指出这是一个SOAP HTTP请求,它的值是所要的URI。在格式、URI的特性和可解析性上没有任何限制。当HTTP客户发出SOAP HTTP请求时必须使用在HTTP头中使用这个域。 soapaction = "SOAPAction" ":" [ <"> URI-reference <"> ] HTTP头中SOAPAction域使服务器(如防火墙)能正确的过滤HTTP中SOAP请求消息。如果这个域的值是空字符串(""),表示SOAP消息的目标就是HTTP请求的URI。这个域没有值表示没有SOAP消息的目标的信息。例子:
6.2 SOAP HTTP应答SOAP HTTP遵循HTTP 中表示通信状态信息的HTTP状态码的语义。例如,2xx状态码表示这个包含了SOAP组件的客户请求已经被成功的收到,理解和接受。在处理请求时如果发生错误,SOAP HTTP服务器必须发出应答HTTP 500 "Internal Server Error",并在这个应答中包含一个SOAP Fault元素(见4.4节)表示这个SOAP处理错误。 6.3 HTTP扩展框架一个SOAP消息可以与HTTP扩展框架 [6]一起使用以区分是否有SOAP HTTP请求和它的目标。是使用扩展框架或是普通的HTTP关系到通信各方的策略和能力。通过使用一个必需的扩展声明和"M-"HTTP方法名前缀,客户可以强制使用HTTP扩展框架。服务器可以使用HTTP状态码510 "Not Extended"强制使用HTTP扩展框架。也就是说,使用一个额外的来回,任何一方都可以发现另一方的策略并依照执行。用来表示SOAP使用了扩展框架的扩展标志符是:http://schemas.xmlsoap.org/soap/envelope/ 6.4 SOAP HTTP举例例3 使用POST的SOAP HTTP
例4 使用扩展框架的SOAP HTTP
7. 在RPC中使用SOAP设计SOAP的目的之一就是利用XML的扩展性和灵活性来封装和交换RPC调用。这一节定义了远程过程调用和应答的统一表示形式。虽然可以预计到这种表示形式最可能被用于与第5节中定义的编码方式相结合,但也可能有其它的表示形式。SOAP的encodingStyle属性(见4.3.2节)可以用来表明方法调用和应答都使用这一节所指定的表示方式。在RPC中使用SOAP和SOAP协议绑定(见第6节)是紧密相关的。在使用HTTP作为绑定协议时,一个 RPC调用自然地映射到一个HTTP请求,RPC应答同样映射到HTTP应答。但是,在RPC中使用SOAP并不限于绑定HTTP协议。
SOAP依靠协议绑定提供传送URI的机制。例如,对HTTP来说,请求的URI指出了调用的来源 。除了必须是一个合法的URI之外,SOAP对一个地址的格式没有任何限制。(更多URI的信息参见 [4]) 7.1 RPC和SOAP体RPC方法调用和应答都包含在SOAP Body元素中(见4.3节),它们使用如下的表示形式:
方法错误使用SOAP Fault元素(见4.4节)表示。如果绑定的协议有额外的规则表示错误,则这些规则也必须要遵从。正如上面所述,方法调用和应答结构可以按照第5节中规则编码,或者用encodingStyle属性(见4.1.1节)指定编码方式。应用程序可以处理缺少参数的请求,但是可能返回一个错误。因为返回结果表示调用成功,错误表示调用失败,所以,在方法应答中同时包含返回结果和错误是错误的。 7.2 RPC和SOAP头在 RPC编码中,可能会有与方法请求有关但不是正规的方法signature的附加信息。如果这样,它必须作为SOAP头元素的子元素。使用这种头元素的一个例子是在消息中传递事务ID。由于事务ID不是方法signature的一部分,通常由底层的组件而不是应用程序代码控制,所以没有一种直接的方法在调用中传递这个必要的信息。通过在头中添加一个给定名字的条目,接收方的事务管理器就可以析取这个事务ID,而且不影响远程过程调用的代码。 8. 安全性考虑这篇文档中没有涉及完整性和保密性,这些问题将在以后的版本中描述。 9. 参考文献
10。 附录A. SOAP封装举例 A.1 请求编码举例 例5 类似于例1,但有一个必要的头
例6 类似于例1,但有多个请求参数
A.2 应答编码举例 例7 与例2类似,但有必要的头部
例8 与例2类似,但有一个结构
例9 与例2类似,但处理必要的头出错
例10 与例2类似,但处理Body出错
July 17 Linux ACL1.甚么是ACL ACL就是Access Control List,一个文件/目录的访问控制列表,可以针对任意指定的用户/组分配RWX权限。Linux在2.6版内核开始支持ACL。 2.ACL条目 一个ACL包括了一个ACL条目的集合,一个ACL条目为一个用户或者一个组对某个对象的访问权限,包括读、写、执行。一个ACL条目包括了一个条目标签类型,一个可选的条目标签的准入者以及一个权限(permission)的集合。 条目标签类型如下: ACL_USER_OBJ ACL_USER_OBJ 条目标签表示文件所有者的访问权限。 ACL_USER ACL_USER条目标签表示该条目下准入者的访问权限。 ACL_GROUP_OBJ ACL_GROUP_OBJ条目标签表示文件所在组的访问权限。 ACL_GROUP ACL_GROUP条目标签表示该条目下准入者(特定的组组)的访问权限。 ACL_MASK ACL_MASK条目标签表示能给ACL_USER,ACL_GROUP,ACL_GROUP分配的最大权限。 ACL_OTHER ACL_OTHER条目标签表示不能满足其它条目中的准入者的访问权限。 3.合法的ACL 一个ACL必须符合以下规则才能叫做合法的ACL。 一个ACL必须包含一条且仅有一条ACL_USER_OBJ,ACL_GROUP_OBJ,ACL_OTHER标签类型。 一个ACL可以包含0个或者多个ACL_USER以及ACL_GROUP,如果有这样的条目,那么ACL中必须包含一个且仅有一个ACL_MASK标签类型。否则 ACL_MASK可以不出现 所有ACL_USER准入者中出现的user ID必须唯一,同样,在ACL_GROUP中出现的group ID必须唯一。 4.ACL与文件权限的联系 在昨天6点钟之前,肖囧同学只知道文件的权限用chmod管理,这对个人用户来说足够,然而对一些系统管理员来说,只用文件权限来管理访问安全性足够可以让他/她/它无语到极点,为了实现一些比较复杂的权限管理,往往不得不创建很多的组,并加以详细的记录和区分。所以ACL的出现让管理员看到了曙光,然而ACL不能够和已有的权限系统冲突,所以和文件权限就有如下联系: 1.ACL所规定的权限是文件权限的超集。 2.文件权限中的用户对应ACL中的ACL_USER_OBJ条目 3.如果木有ACL_MASK条目,则文件权限中的组权限对应ACL_GROUP_OBJ条目。反之,文件中的组权限对应ACL_MASK条目。 4.文件权限中的其他权限对应ACL_OTHER_OBJ条目, 5.文件权限中的任何改动将映射到ACL上,反之亦然。 5.对象的创建以及缺省ACL 当使用create() mkdir() mknod() mkfifo() open()等函数创建对象时,这些对象的ACL初始化。如果某一目录关联一个缺省的ACL,那末这些函数的mode参数以及该目录的缺省ACL决定了该对象的ACL。 1.新对象将继承该目录的缺省ACL。 2.修改文件权限相关的ACL条目,使得ACL中不存在mode参数中未指定的访问权限。 如果该目录没有缺省的ACL,那么mode参数以及文件创建的mask(这个东西我有讲过的,文件创建的掩码,不记得请上我公司网站查询)决定该对象的ACL 1.新建对象的ACL包括ACL_USER_OBJ,ACL_GROUP_OBJ以及ACL_OTHER,这些条目的权限又文件创建掩码决定。 2.与mode参数中指定的权限进行同步。 6.通过ACL访问的检查算法 每当一个进程要访问指定的对象时,ACL会进行如下检查: 1.If进程的有效uid与对象所有者一致,则。 if ACL_USER_OBJ中有相应的权限,那么允许访问。 else 拒绝访问。 2.else if如果进程的有效uid与某条ACL_USER条目中的准入者uid一致 if 满足ACL_USER条目以及ACL_MASK中有相应的权限,那么允许访问。 else 拒绝访问。 3.else if如果有效的gid与某条ACL_GROUP的准入者gid一致,则 if ACL中有ACL_MASK条目。则 if ACL_MASK或者ACL_GROUP_OBJ或者ACL_GROUP含有指定的访问权限,则允许访问。 else 拒绝访问。 else if ACL_GROUP_OBJ条目中有相应的权限,则允许访问。 else 拒绝访问 else 拒绝访问 4.else if ACL_OTHER条目中有相应的权限,则运行访问。 5.else拒绝访问。 7.查看ACL 查看一个对象的ACL,可以使用getfacl命令,比如getfacl ./somedir,其结果如下 1.# file: somedir/ 8.设置ACL 设置一个对象的ACL,要通过setfacl命令。不过我目前没有试验成功,需要ROOT权限,残念啊……请各位用man setfacl开传送门去看看。 9总结 ACL大大的方便了管理员对文件对象的管理,可以利用ACL的条目,轻松的添加一些访问例外,而用chmod实现同样的功能,则要添加很多组,然后把用户添加到组中间。无论多么复杂的系统中,文件系统的权限管理都是最基础的内容。而 Linux 对 ACL的支持,无疑是一把管理海量用户系统的利器,对 Linux 在大规模的企业级应用中更方便的发挥更大的作用添了一把火。注意:在单个文件的 ACL 条目的数量上,不同的文件系统有不同的限制。Ext2 和 Ext3 只能支持每个文件 25 个 ACL 条目。ReiserFS 和 JFS 可以支持超过 8,000 个条目。这个方面 Ext* 文件系统还需要加强。 June 25 谈论 再见同学,你好先生!
引用 再见同学,你好先生! 再见同学,你好先生!当去年的这个时候,我还觉得毕业是很遥远的事情。但是逝者如斯夫,抑或说How time flies. 转眼间,毕业的主角就成了我们。 说起毕业,多多少少有一些伤感啊,不安啊,对前途的憧憬或是迷茫啊。人最难受的时候莫过如此,心情百感交集,今天想着和某某同学吃喝一顿,明天想着去学校里办理一些毕业的事物,后天良心发现,翻个几页书,然后时间久这么混混沌沌的过去了。对于大多数人来说,这也是没办法的事情,几种想法纵横交错的时候,不总是能安下心来做事,不过毕业嘛,就要有毕业的样子,前几年的辛苦,能够得瑟着毕业,不为学分发愁,不为出路担忧,也是一大幸事。 大四这一年,我就没怎么在学校里呆过,中国最大两座城市各住个半年,为了以后的工作到处飘荡。在这个时候,还难免有那么点伤感的,总觉得有很多话没跟朋友们倾诉,然而时间有限,太多的话积累在一起,就像茶壶里装饺子一般,不知道从何说起,以致现在要把很多东西留在这里,希望我的朋友们能看到,能了解我对朋友们衷心感恩,对朋友美好的祝福。我是一个很普通的人,正因为有了这些朋友们,我的大学才丰富多彩,才趣味十足,我才是现在坐在电脑前写文章的我。 我总觉得自己是一个沉湎于过去的人,每当我回首大学走过的这段路,我都会带上一些骄傲——我的大学过得很充实,我在大学为未来的生活做了足够的准备。当我被命运安排到武汉大学的那个暑假,我就在思考,我的大学应该怎么度过。可能是上天的眷顾,我在大学期间遇到了很多志同道合的朋友,在他们的帮助下,我们拥有了很多精彩的瞬间。我很满意我的大学生涯,我的生活方式很规律,成绩也不错,动手能力也凑合,有那么几个可以推心置腹的朋友,找到一份不错的工作,最后老天大发慈悲,让高中我就喜欢上的那女孩陪着我……我觉得,这样的大学生活应该很知足了。很感谢我的父亲,在我入大学之前给我转了一贴《给大学生的81条金玉良言》虽然那81条我并没有全做到,不过也八九不离十。 今天,在拿到毕业证的那一瞬间,一个强烈的声音告诉我,得瑟的日子已经结束了。以后不会再有穿着拖鞋到处溜达,不会再有寡人今天不高兴不去上课,不会再有草坪哪背阴我躺哪,对于我的学生生涯,就像一桌宴席一般,散了,散了。虽然以后天还是那样的天,地也还是那样的地,人不会是那样的人了,一个无忧无虑的学生,马上要面对人世间纷纷扰扰。你应该准备好了吧,你应该是个成熟的成年人了吧,这两句话在这一年一直萦绕在我耳畔,不曾挥去。 我很庆幸有一年的实习期间来适应未来的生活,这一年里,多多少少还是觉得自己的知识储备,身体状况,心态还是学生时代的那个小屁孩。不过据说高校毕业生大多都是这种状态,那么好吧,大家都能做到,对我来说也是轻松的事情。 虽然学生生涯的结束,这并不意味学习的结束,这一句对我来说简直就是废话。 总觉得自己不是那种爱冒险的人,就像我在麻将桌上悲观且谨慎的表现一般,也许我做不成什么大事,也许我只是一个大千世界中的凡夫俗子,让我承担起什么历史社会使命,现在看来蛮不靠谱的。守住家中的一亩三分田,现在看起来倒是一个很现实而且很明晰的未来。好好工作,养家糊口。 还记得大学刚开学的时候,一个老外说Life is like a book. We finish one chapter after.大学的这一章节已经结束了,接着读下一章吗?当然。 当回忆与现实不断在混沌的大脑中交替,沉湎于过去固然能够回忆起太多的往事,高兴的、悲伤的、痛苦的、滑稽的,回忆不是过眼云烟,舍不得老师们精彩的讲解,舍不得珞珈山水旖旎的风光,舍不得朋友间亲密无间的扯淡,舍不得随心所欲的生活节奏。再多的不舍,随着那一章最后一页的翻过,都成了过去。迎接我的会是什么?未来是什么样的?平静的面对这一切吧。 再见了,肖同学,你的大学时代,学生生涯,就这么过去了。你好肖先生,以后好玩的事情多着呢。 June 12 谈论 C语言声明的优先级规则
引用 C语言声明的优先级规则 June 11 C语言声明的优先级规则
March 24 克隆表达式主要用于crontab的任务调度中 (1)、克隆表达式可以包括7个字段:秒、分、小时、月内日期、月、周内日期、年(可选字段) March 22 原则,你懂不最近看了《疯狂的赛车》,里面那两个杀手,抑或是贼,也许又是毒贩,或者说他们是全才,反正他们的台词相当搞笑,“干一行爱一行”,“多行不义必自毙”,“不专业啊”,其中还有一句话就是“原则,你懂不”。 其实我不怎么懂原则,我说的原则是软件设计中的原则,每次当我问那些有经验的前辈们,怎么设计才算是一个合理的设计方案,一般都会得到的回答就是,经验,当经历的项目多了,自然就会有一套自己设计的套路。这种回答也实在是无可奈何,毕竟软件设计没有一套验证合理性的数学模型,所以对于一个设计方案,我遇到很多设计评审就是,合理就可以,但没有人可以肯定,这个设计不会造成一些后果。尤其是对于我这种菜鸟来说,设计一个模块都让我战战兢兢,如履薄冰。所以嘛,不知道点原则,那么做出来的事情肯定就不专业了。虽然现在的经验不能保证我能够吃透这些原则,但完全不知道原则,那就像是拿着菜刀去和鬼子搏斗一般,也许一转身,发现还有AK47,迫击炮,火箭筒之类的,虽然现在不会用,但也得学,虽说有时候杀鸡用牛刀,偏偏用牛刀可以把鸡杀了,但反过来杀牛用鸡刀,只怕是牛占据格斗的优势。 废话到此,先看伟大的wiki上对软件设计7条原则的描述: 1.开闭原则(Open/closed principle)
2.里氏代换原则(Liskov Substitution Principle,常缩写为.LSP)
3.依赖倒置原则(Dependence Inversion Principle)
4.接口隔离原则(Interface Segregation Principle, ISP)
5.合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
6.迪米特法则(Law of Demeter LoD)又叫做最少知识原则(Least Knowledge Principle,LKP)
7.单一职责原则(Simple responsibility principle SRP)
恩~说了这些原则,不过很多原则还必须通过实际项目去加深理解,原则为何在设计中起着作用,以及原则和具体的设计模式直接有什么联系,我还要慢慢体会。如果不知道这些原则,那么就是做软件不专业……多行不义必自毙。(满嘴顺口溜,你考研啊) March 14 字符集的一些点滴字符集一直是我的噩梦……从我很小的时候就开始了,那个时候我几乎不懂什么编程,但我知道我国古代有一位伟大的军事家、政治家、文学家变巨。当然,你可能没听说过变巨,但你肯定听说过曹操。是的,BIG5码中的曹操转到国标码那就是变巨。记得当时没少咒骂那些不肯把文字简体中文化的游戏代理商,也没少咒骂那些所谓的内码转换工具。好吧,废话少说,今天上了课,基本上消除了90%对字符串的恐惧,以下随便说一些,主要说说几种双字节和多字节编码:
GB2312-80,传说中的中华人民共和国国家标准汉字信息交换用编码,该编码为双字节编码,高字节的范围位0xA0-0xFE,低字节为0xA0-0xFE,编码空间为……额,94*94=8836,(其中0xB0-0xF7是汉字区)该编码又通过高低位分为94个区与94个位,就成了传说中的区位码,除去了数字啊,符号啊以及空白编码,给汉字留下的,只有6000多个。我天朝文化博大精深,汉字岂是这6000多个编码能够包罗的,所以可以看出,这个编码的确不怎么能满足需要,甚至我国前总理朱镕基的镕字都不在这个字符集中。
GB13000,又叫GBK,K的意思是扩展,再怎么说,我们也不能打不出总理的名字,所以在1995年,信息技术化技术委员会又制定了GBK编码,其编码空间有了大幅度的扩充,单字节编码空间是0x00-0x7F,和ASCII码兼容。双字节编码中,高字节是0x81-0xFE,低字节是0x40-0x7E以及0x80-0xFE,以低字节7F为界,以上的都是与GB2312兼容,以下则是生僻字。GBK一共收入了21886个汉字符号,其分布如下图: 汉字区: GBK/2:OXBOA1-F7FE, 收录 GB2312 汉字 6763 个 GBK/3:OX8140-AOFE,收录 CJK 汉字 6080 个 GBK/4:OXAA40-FEAO,收录 CJK 汉字和增补的汉字 8160 个 图形符号区: GBK/1:OXA1A1-A9FE,GB2312 符号+增补其它符号 GBK/5:OXA840-A9AO,扩除非汉字区 用户自定义区 : 即 GBK 区域中的空白区,用户可以自己定义字符
在2000年,我天朝又高瞻远瞩的扩充了编码,考虑到民族团结,将少数民族文字加入,也考虑到曾经的几个属国,所以把日语,韩语符号加入到了编码,于是GB18030-2000应运而生,考虑到囊括内容众多,所以编码最多为四字节……其规则为单字节:0x0~0x7F,双字节:高字节:0x81~0xFE 低字节:0x40~0x7E 0x80~0xFE(兼容GBK),四字节:第1、3字节:0X81~0XFE 第2、4字节:0X30~0X39 unicode,这个东西是我们听的最多的了,也是国际推荐的编码方式,其产生就不再多说,unicode有多种使用方式,也就是我们尝尝听说的UTF-8 UTF-16 UTF-32,这类的。 所谓UTF-32,就是用32位去表示一个编码……试想就一串英文也要用每个字母32位去编码,那么存储空间就凭空变成原来的四倍,用张指导的话说,那就是不合理。 UTF-16嘛,这个编码的方法是,如果编码U小于0x10000,则直接用16位来表示,如果编码U大于0x10000,由于unicode编码最大范围为0x10FFFF,从0x10000到0x10FFFF直接共有0xFFFFF个编码,也就是要20个bit就可以表示这些编码。一个编码U,将其前10bit作为低位和0xD800进行或操作,将后10bit作为低位和0xDC做或操作。这样就组成了4个BYTE的编码。这个东西的好处嘛……大部分编码都以固定长度存储,但无法相容于ASCII编码。 UTF-8,也是一个变长的编码,用1~4个Byte来表示一个编码,当长度位1Byte时,和ASCII对应,当是两个Byte时,表示拉丁文,希伯来文,3个时,表示CJK中的字符,当4个,表示其它的字符。其编码规则如下表:
以上,把国内几个主流的编码简述了一下……至于其它的编码BIG5啊,之类的,需要使用的时候再去查查资料,unicode真是一种好的解决方案。 March 05 (zt)session和cookie的最深刻理解 很多概念,略微了解那么一点,但是稍微细节的东西,就很模糊了,当然……作为一个挨踢人士来说这是不专业的,从网上转了一篇有关session和cookie的认识,贴在这里,没事可以来这里看看。 --------------------我是分割线--------------------------------------- 以下是正文哟 先说session 对SESSION的争论好象一直没有停止过,不过幺麽能理解SESSION的人应该占90以上。 但还是讲讲,别嫌老~ 有一些人赞成用SESSION,有一些人不赞成。但这个问题到底要怎么说。不妨听听我的看法 如果有错误请不要朝丢东西,金条和硬币除外。 有些人应该知道我是做江湖程序的,而江湖程序做看中的就是效率,但这里不谈设计,而 从一些比较实际的角度看SESSION。 首先要先说SESSION是干什么的,SESSION是可以存储针对与某一个用户的IE以及通过其当 前窗口打开的任何窗口具有针对性的用户信息存储机制。为什么要这样说。看下边 先研究SESSION是如何启动的,当打开IE以后浏览网站后会发出一个指令请求SESSIONID以 及对各个类型数据的下载许可,如图片,声音以及FLASH。 数据实际传输内容:IE到服务器 GET / HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */* Accept-Language0: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) Host: www.jh521.com Connection: Keep-Alive 服务器会返回一个没有被使用的SESSIONID让IE使用,当时IE就对返回SESSIONID做存储 并同时返回相关页面的下载数据,如下:服务器到IE HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Sun, 30 Nov 2003 16:41:51 GMT Content-Length: 21174..Content-Type: text/html Set-Cookie: ASPSESSIONIDCACBBBRT=IBOMFONAOJFEEBHBPIENJFFC; path=/ Cache-control: private 然后就是页面HTML代码 此时这个IE程序(不是客户机)的SESSIONID就为IBOMFONAOJFEEBHBPIENJFFC 而当IE在访问任何这个站点的ASP程序的时候,就会把IBOMFONAOJFEEBHBPIENJFFC发送 给服务器,服务器就会知道IBOMFONAOJFEEBHBPIENJFFC是表示你 而在服务器上设置SESSION("name")="name" 完全可以看成是 SESSION("IBOMFONAOJFEEBHBPIENJFFC")("name")="name" 或者 SESSION(SESSIONID)("name")="name" 这样,SESSION就区分开用户了。 而当服务器反馈这个ID的时候会看这个ID有没有被使用。如果有在换一个 反正不会让你重复,如果想模拟某人的SESSION的ID来进行欺骗是可以的。不过要获取到 对方IE传输信号,并且在保证当时这个SESSIONID没有被取消的情况下才可能实施。 不过要是我有那时间直接通过POST信号找他NAME和PASS了。我可不费这个劲 想必一些人明白了了SESSIONID到底是如何工作的 那么就在看看COOKIE,有人说SESSIONID就是COOKIE,按照技术上来讲他们不属于同类 但是属于一种工作模式,用户和服务器传输私有数据 当我设置COOKIE的时候,服务器会反馈给IE一个指令。IE通过这个网络指令生成COOKIE并 存放,在特定的时候会取得这个这个信息如在访问这个站点并且COOKID有效的时候。 那么为什么要用COOKIE而不用SESSION呢 看下区别 有效时间以及存储方式 传输内容 COOKIE 可设置并在本地保留 明码信息 SESSION 在IE不关闭并服务器不超时 只有SESSIONID 当如果想让用户下次登入网站不需要输入用户名或者密码的时候就只能用COOKIE, 因为他可以保留相当长的时间(在COOKIE记录被删除或者失效日期之前) 而SESSION就不可以,他不会保留太长时间,而且IE在关闭后就自动清除了SESSIONID记录 在下次登入的时候会请求新的SESSIONID 而服务器想通过用户个人变量校验用户的状态的时候,就不能用COOKIE 如果用设置用户权限是USER。而IE访问的时候就把USER的明码传输到服务器。 那么如果我通过一定手段,比如直接修改COOKIE记录,把USER修改成ADMIN呢~~ 就麻烦了。 但存储用户名和密码或者网站的配色方案这样的信息,用COOKIE是最好的 好,有点累了,在说说这个东西 Request.ServerVariables("HTTP_REFERER") 我想有一些人通过这个Request.ServerVariables("HTTP_REFERER") 来进行一些关键性限制,特别是对付远程提交以及非法侵入。 那么我就要提醒下服务器取得的HTTP_REFERER信息完全是IE传输给服务器的,可以模拟 而且难度不大,用不到半个小时就可以用VB做出一个针对HTTP_REFERER入侵程序。 December 15 IT人士群聚喝酒的讲究大家喝的是啤酒,这时你入座了…… 人到齐了,酒席开始了。 菜过三巡,你就不跟他们客气了。 酒是一样的,可是喝法是不同的。 酒过三巡,你也该活动活动了。 喝酒喝到最后的结果都一样。
December 07 【zt】99%的人不了解的真实中国历史99%的人不了解的真实中国历史 November 04 并不凄凉的OT昨天一个不小心,居然OT到两点才回家,本想下班后立即回去,看会书然后好好睡个觉,但是现实是残酷的。临时任务一来,马上开始投入战斗,在被同学K陷害几次后,成功的在9点左右结束了战斗。此时同学K开始抱怨今天晚上搞不定任务了,此时本想一走了之,但是把同学K丢在这里,不仁不义,于是劝他慢慢工作,大不了一起去挤我的小黑屋。于是事情如预料中发展,大约2点,我们终于把事情处理完了。然后两人如同孤魂野鬼般匆匆回家,其实我发现凌晨的上海浦东更加魔幻,雾气笼罩,烟云缥缈,然后这时候如果来几个鬼怪,马上可以就地拍摄一部不错的鬼片。可惜浦东这边乃上海郊外,不要说鬼,一路上连人影子都没见到过。进了小黑屋,稍作调整,便倒头大睡,同学K甚至在第二天说自己睡的像死猪般。不过还好,没听见鼾声。 实际上OT到这种程度也不算什么,稍微给几个同学抱怨了一下,什么蛮夷的时差啊,什么机器故障啊,很惨很凄凉啊,等等。不过结合到最近的形势,的确颇有感触,自从金融危机发生后,外国企业如同宰猪一般的裁员,一时间搞得人人自危,本科生今年的就业形势相当不好。不过也有在风雨中稳坐钓鱼台的人,反正牛人不愁找不到工作。自己的前途是比较确定了,但这似乎并没有减轻自己的压力,小学想初中,初中想着考高中,高中想着考大学,大学里面想着找工作,真有了工作,又一大堆问题也来了,自己是否为职业做好了准备啊,什么职业生涯的规划啊,什么找老婆啊,怎么养家糊口啊。以前总觉得这些问题还离自己很遥远。现在兵临城下了,却还没有对策。不过这也是当然的,刚开始嘛,有对策才奇怪呢……不过最近一个月来,这些问题如同幽灵般在我周围萦绕。有的时候,也感觉自己很无助,平时可以带着一种自信去面对很多事情,但安静下来想想,还真不知道这种自信来自何方。总以为自己能处理很多事情,结果仔细想想,还不是在家靠父母,出门靠兄弟。自己的学生生涯即将结束,在学校时很想出来见见世面,现在却无比怀念学校里泡自习室的时光,可以不顾周围一切的看书,然后累了摆开睡一会。现在听见电话想就知道自己又有事情做了,学的东西零零散散,浅尝辄止,不成体系。这一切,构筑了少年老肖的烦恼。不知道这算不算是成长中的一些轨迹,也许是自己对自己要求太高了,总对自己的现状不满足吧。好吧,根据自己的历史状况来看,面对的问题都是解决了的,这回也照旧吧。 也许这些是我职业生涯即将开始的一些思考吧。再过上10年,到时候是满足于过着猪一般的生活,还是意气风发,指点江山。我现在每天对自己说,I have a dream,这句话究竟是受了刺激后所发出的歇斯底里的吼叫,还是蕴藏在自己内心的声音?也许很多人都可以在某种作用力的激发下说出这句话,但是最终很多人都随波逐流。我是一个很平凡的人,但平凡的人也可以改变这个世界,也能有自己的梦想。也许自己现在对这些压力感觉到有点压抑,但是千里之行,还是得始于足下的。我希望10年后,告诉自己,I have a dream这句话是我心里最珍贵的东西。 October 21 Factory Method终于遇到一个比较熟悉的模式了,先上一段代码,根据书上类图实现的: class Product }; class ConcreteProduct : Product class Creator class ConcreteProduct : Creator 适用性: 当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由它的子类来指定它所创建的对象的时候。 当类将创建对象的职责委托给多个帮组子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。 自然,工厂方法还有很多其他的实现方式,比如模板: class Creator { public: virtual Product* CreateProduct() = 0; }; template <class TheProduct> class StandardCreator: public Creator { public: virtual Product* CreateProduct() { return new TheProduct; } }; Builder老肖的脑残实现如下: class Product }; class Builder class ConcreteBuilder1 : Builder class ConcreteBuilder2 : Builder class Director for(int i=0;i<2;i++) 很显然,我觉得书上的类图和书上的代码实现有出入,既然是Builder对象的聚合,那么为何只作为Director的构造函数的参数进行传入。如果完全按照类图的实现,就像上面的代码那样脑残,在一个循环创建后,根本无法保留创建后的状态,难道类图中隐藏了Dirctor对于Product的聚合?抑或是根据每个Builder对象进行操作,但每个Builder对象对于Product只是个弱引用而已,不解! --------------------过了一天,我是分割线------------------------------------------------------------- 书上的图,很令我迷茫,但是在今天和同学K讨论后又似乎有那么点开窍。 首先,关于聚合的概念需要进一步更新,聚合意味着一个对象拥有另一个对象或对另一个对象负责。并且聚合对象和其拥有者具有相同的生命周期。于是乎写出如下代码: 老肖的非脑残实现如下: class Product }; class Builder class ConcreteBuilder : Builder class Director 适用性: 当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时。 当构造过程必须允许被构造的对象有不同的表示时。 October 20 Abstract Factory老肖的简单代码实现如下: class AbstractProductA class ProductA1 : public AbstractProductA class ProductA2 : public AbstractProductA class AbstractProductB class ProductB1 : public AbstractProductB class ProductB2 : public AbstractProductB class AbstractFactory class ConcreteFactoryA : public AbstractFactory class ConcreteFactoryB : public AbstractFactory 适用性: 一个系统要独立于它的产品的创建、组合和表示时。 一个系统要由多个产品系列中的一个来配置时。 当你要强调一系列相关的产品对象的设计一边进行联合使用时。 点你提供一个产品类库,而只想现实他们的接口而不是实现时。 October 03 无锡轻松游无锡是个好地方。当年江泽民书记在我绵阳逛了一圈后,随口说了句“绵阳是个好地方”,于是这句话迅速走红,进而衍生出上有天堂,下有苏杭,除了美国,就是绵阳。因为“绵阳是个好地方”。无锡是个好地方,在火车站附近随处可以看见有这样标语的广告牌,难免让人猜测,当年是不是也是某个名人在这里逛了圈,然后下了个这个结论。虽然我不算个名人,不过就逛了这3天来看,无锡的确是个适合居住的地方。 当然,我这样下结论会败掉很多人品,事实上我这次出行,人品确实不好。早上坐的动车,因为不明原因故障,晚点了1个小时,但是去无锡也只需要45分钟左右,基本晚点100%。但是我觉得无锡是个好地方,自然是有理由的。虽然如同全国很多城市一般,无锡也是那种大楼林立的城市,和我预期的江南水乡有很大的差距。也许在某些城市的角落中,依稀可以看到一条河,河边几户人家,人家边一两条船歪着。这时同学会告诉我,这里属于没拆完的地带,还有那条河也基本是死水了……所以理想和现实总是有不可调和的矛盾。抱怨如此多,依然无法掩盖这座城市其独特的魅力,以下我随便写写在这里的见闻,也许以后去无锡的机会不多,但是每当我翻开这里,我还可以从记忆的碎片中去搜索那轻松的3天。
崇安寺步行街 虽然我说,无锡和全国很多城市没太多的区别,也就是说,把一个住在上海的四川人绑架了,然后扔到无锡,也许他还以为自己在上海。不过呢,无锡的崇安寺步行街的确浓缩了无锡的民俗风情。古色古香的建筑,可以让人感觉一下江南特有的建筑美学。亭子边有咿咿呀呀的锡剧,就如同外地人不明白四川为何到处是麻将声,我也不明白锡剧唱的是什么,听同学说,无锡方言如同天书,不可意会更不可言传,然后再变点调子唱出来,我能听懂那才是奇怪。步行街上不缺少坑人的奸商,不过那些商品对我来说的确缺少了点吸引力,反正全国到处都买得到。步行街的地下别有洞天,虽然也是众多奸商的聚集地,但是布置非常的精巧,一面墙壁上有飞流而下的瀑布,墙上用我能看懂的字体写着王羲之的兰亭集序。就如同上海的南京路上有众多的老上海建筑,反映了上海一个世纪的变迁。崇安寺步行街上的建筑和人文风情,也向世人展示着无锡的民俗。 水路九连环 所谓江南水乡,必然是要水路开道。无锡的水多,一会又是什么湖,一会又是什么河。只能说,我可以通过这些河湖想象一下当年江南水乡的味道……一个美丽的江南姑娘,撑船采菱角,或者采个莲蓬什么的。然而同学的一句“一旦蓝藻爆发……”将这些想象撕得粉碎。于是感叹一下当代的发展,产生了丰富的磷资源,不和谐,不环保。突然同学告诉我,那就是传说中的京杭大运河。只见一条大河,涪江一般宽。只不过涪江可以淌过去,这里还是船只来来往往,非常热闹。由于只是乘车路过,没有时间去凭吊运河。不过也还是有点奇怪的想法。京杭大运河是隋炀帝为了驾临江都游江南所挖造,当年他游江都也是极尽奢华,两岸尽种柳树,一路美女拉纤。虽然隋炀帝最后不得好死,但是他主持挖造的运河却流淌到了现在,而且还有很好的经济效益。不得不说,人家连腐败都这样有水平。 无锡三国城 我是个铁杆三国迷。所以三国城是不得不去游览的地方。无锡三国城背负着我朝廷台的影视基地,以及其他无数头衔,最后只证明了一句话,盛名之下,其实难副。首先国庆期间人山人海这就不说了,我觉得这种地方还是比较适合少一点的人,然后去真正的感受一下曹操骊酒临江,横槊赋诗的那种情怀。三国城中,蜀国被华丽的无视掉了,当然,这里到处是水,蜀国又是在四川那种难于上青天的地方,这样无视倒也说得过去。于是三国演艺就成了双城记。一路上有很多景点,比如曹操点将台,曹操书房,曹操寝室,曹操XXX,搞得成了曹操故居那样……以及吴王宫,里面是烧香的地方。凤仪亭,里面不见吕布与貂蝉,反而是一个丢沙包拿奖品的地方,也许是想让人扮演董卓,当年董卓用画戟丢吕布不中,现在给游客一个机会,还有什么孙尚香酒家,自然是园内宰人的地方。由于城中主题是赤壁之战,所以我也体会了一下坐战船的滋味。然而,战船毕竟是给当兵的人坐的,自然不可能像给曹操那样舒服,挤了一船的人后,然后船缓缓从水寨开出,一旁的同学不断的提醒我远方飘荡的蓝藻,战船的舵手自然也不想让士兵们看到太多的蓝藻而恶心,于是10分钟左右边匆匆鸣金收兵。所以我说其实难副,也是有道理的。三国城中还有两场表演,一场是服装展示,只是让我产生了,刘备,西门庆,李隆基,贾宝玉是同一时代人物这样的幻觉。另一场表演则相对不错,三英战吕布,其实并不是战斗场面多么壮观,甚至在冲锋时刻,一个攻城的车辆当众抛锚。参加演出的演员,表演都很专业,能在马上做出各种有难度的动作,仿佛为了证明奥运会他们没有出现在鞍马场上是一种浪费,有演员从马上摔下来,然后连打几个滚,最后扮作尸体,直到被杂兵抬出,栩栩如生。一阵喧嚣过后,我也情愿的被人群冲出了三国城。同学的最大体会是,“等我到时候出名了,要合影,可以,10块钱一人”。 蠡园 很难想象,在搜狗拼音中居然有这个现成的词组。我的确孤陋寡闻,在来无锡之前并不知道这么个园。这个蠡,还真是伟大的那个范蠡,陶朱公,商圣,也许还有其它头衔无数,范蠡大人是聪明人,他深知兔死狗烹,鸟尽弓藏,得鱼忘筌,过河拆桥,卸磨杀驴的道理,帮助勾践搞定夫差后,就和西施妹妹隐居于五湖了。这个蠡园,据说就是当年范蠡大人和西施隐居之处……当然,也许是后人强加上去的。这噱头并不重要。园林的风格,我很难说清,因为自己对园林艺术了解不多。不过依仗着周围的湖泊,风景不算太差,而且林中的一座假山,还是让人体会到了什么叫曲径通幽和峰回路转。一路上,我都和同学讨论,如果自己有这样一个园,该有多好,苔痕上阶绿,草色入帘青,来往有鸿儒,往来无白丁。这就不叫简陋了,而叫做档次。出则俯仰湖山,入则读书修身。神仙般的日子,不过如此。不过买下一个园,还是需要点钱的…… 无锡美食 到了21世纪,我们能够很轻松的吃到其他地方的美食。当然,能够吃到当地的特产,那自然更好,以后看到别人吃那些,还可以稍微摆一下谱:我当年吃的那个才是正宗的……在无锡,我第一次吃到了菱角。菱角本不是什么无锡特产,但是在菱角前加上太湖二字,便摇身一变了。菱角这东西,板栗一般吃法,稍微吃几个,感觉还是不错,吃多了就感觉不舒服了。此外,王兴记的馄饨我也品尝了,都快两点了,还排着一字长蛇阵,足见其名气。馄饨味道不错,就是甜了一点,不过能感受一下,也就知足了。 以上,就是无锡轻松游的一些点滴。还是那句话,理想虽然和现实有巨大的差距,但是现实中也有美,我要做的,只是去发现他们,感受他们。 September 15 你能行的恩,这几天,很多人对我说了这句话,尽管这是句客套话,但我还是很惊奇,曾经的我,做事是那么令人不放心。自从进入大学,仿佛自己做事情变得稳重了,也会思考了,几个朋友曾经说过,感觉我在任何时候都有办法,永远不会不知所措。也许是我真的成熟了,遇到大部分问题都可以迎刃而解了。很欣慰,也为以后一段时间所面临的困难,有了更多应对的勇气。
今年中秋,大雨,没有月亮,赏月计划自然搁浅。于是给故人打了一个电话,两年多没听见她的声音,居然一点没变,跟记忆中那个温和甜美的声音一模一样。很久没有聊了,自然是口若悬河,滔滔不绝,互相说说自己的近况,对未来的打算啊,这类的。她惊讶于我家庭主男般的生活,我敬佩她考研冲击3%概率的勇气,谈话持续了接近一个小时,并在友好的氛围中结束……我刚充的话费基本没有了,囧。现在的大学生可真是不容易,无论是找工作,考研还是出国,都是千军万马,好不壮观,一将功成万骨枯。社会让我们分出一个高下,我们只有去接受这些竞争。但现在的努力又能说明什么呢?正如我一个同学聊天时说起,过个10年20年不都是抱着孩子打麻将。哈哈,也许是我太消极了。但是我还是想在年轻时做一些有成就感的事情,还是 那句话,不要因为虚度年华而悔恨,不因碌碌无为而羞耻……
生存的压力总是会有的,而且有的时候会很大,于是几乎每个男人都有不同程度的失眠。这个时候,我会想起某个人,想把他拉过来奚落一顿,如果那人在旁边,就直接施加暴力。当然,这只是玩笑话,我只是觉得,现在已经能很好的控制这种压力了,考虑到毕业以后,工作和生活的问题,总让人感觉到头疼。不过我相信车到山前必有路,我会一一处理这些问题的。哈,朋友们说我对任何问题都有办法处理,从大学以后,的确是真的,自然,对于马上要面临的挑战,我也能行的。 |
|
|