posts - 195, comments - 34, trackbacks - 0, articles - 1

          jndi全局注冊表和enc的基本概念
             通俗的將jndi就是對ejb容器中所有的資源和組件進行管理的花名冊,通過該服務,可以很方便的找到希望使用的資源。當組件被部署到服務器上后,該組件就會被自動注冊到花名冊上,以便用戶使用,如果組件被卸載,花名冊上的記錄就會自動消失。
              jndi中注冊的所有的資源和組件可以被服務器內外的各種程序請求或者訪問,是一種全局性的資源!但是ejb中不同的組件通過全局性的jndi服務器形成依賴關系,則會給系統造成不穩定的因素!因此就引入了enc(ejb組件的企業名稱上下文)的概念!通過她來實現不同組件之間的引用關系!!??!
          在上一篇文章中寫到了通過標注的方式實現方向依賴注入!還以上篇為例:
          有接口:HelloWordRemote  HelloWordLocal ICal(Remote)
          而HelloWordBean實現了分別實現了他們
          另外又有了個遠程接口:
          @Remote
          public Interface MyService{
          public String helloWord();
          public int add(int a,int b);
          }
          一個類想實現這個接口并且在這個類中引用了...如下:
          @Stateless
          public class FacedServcie implements MyService{
          private HelloWordLocal myserv1;
          private ICal ical;
          .....
          ....
          }
          可以通過配置文件實現反向依賴注入:
          <ejb-jar
                 xmlns="http://java.sun.com/xml/ns/javaee"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                     http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
                 version="3.0">
             <enterprise-beans>
                <session>
                   <ejb-name>FacedServcie</ejb-name>
                   <ejb-ref>
                     <ejb-ref-name>abc1</ejb-ref-name>
                     <ejb-ref-type>Session</ejb-ref-type>
                     <remote>com.ICal</remote>
                     <mapped-name>HelloWordBean1/remote</mapped-name>
                     <injection-target>
                        <injection-target-class>
                           xiaoxiao.FacedService
                        </injection-target-class>
                        <injection-target-name>
                           ical
                        </injection-target-name>
                     </injection-target>
                   </ejb-ref>
          .........(對于另一個組件的配置)
                </session>
             </enterprise-beans>
          </ejb-jar>
          還可以通過檢索的方式來實現:
          @Stateless

          public class FacedServcie implements MyService{
          private HelloWordLocal myserv1;
          private ICal ical;
          public String helloWord(){
          try{
          InitialContext ctx=new InitalContext();
          ical=(ICal)ctx.lookup("java:comp/env/abc1");
          //其中java:comp/env是組件局部enc所有記錄的根路徑而abc1是在配置文件中注冊的名字!
          }catch(NamingException e){}
          if(ical!=null){
          return ical.helloWord();
          }else{
          return "error!";
          }
          }
          ....
          }
          配置文件如下:
          <ejb-jar
                 xmlns="http://java.sun.com/xml/ns/javaee"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                     http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
                 version="3.0">
             <enterprise-beans>
                <session>
                   <ejb-name>FacedServcie</ejb-name>
                   <ejb-ref>
                     <ejb-ref-name>abc1</ejb-ref-name>
                     <ejb-ref-type>Session</ejb-ref-type>
                     <remote>com.ICal</remote>
                     <mapped-name>HelloWordBean1/remote</mapped-name>         
                   </ejb-ref>
          .........(對于另一個組件的配置)
                </session>
             </enterprise-beans>
          </ejb-jar>
          本人建議使用第一種反向依賴注入的方式!
          還有其他的一些注入:如持久化單元注入,資源型注入 數據源類型的注入。。。

          posted @ 2009-03-24 10:26 小強摩羯座 閱讀(430) | 評論 (0)編輯 收藏

          EJB事務
          在ejb組件設計中,組件行為有時需要具備事務特征,即使用事務保證組件行為的完整性,使組件要么執行成功,要么回到起點.等價沒有執行!
          討論事務時要明確兩個概念:
          事務范圍
          算法的可恢復性與事務性:如果事務中的算法動作結果受事務提交或者回滾影響,則該算法具有事務可恢復性,否則就不具備事務可恢復性.
          事務在本質上就是一個管理系列算法動作一致性的對象!ejb提供了兩種事務類型:聲明性和程序性事務
          聲明性事務:由ejb容器負責事務對象的 生成,管理,銷毀;具體算法在事務上的注冊,事務的提交和回滾等
          主要介紹聲明性的事務:
             ejb容器為其中的所有的ejb組件提供了一種默認的事務模式:Requires
          在該模式下面,組件中的方法如果在事務環境下被調用(即客戶端調用了該組件的方法),則方法中的邏輯會被添加到客戶端的事務環境中,和客戶端的程序使用相同的事務控制對象.如果不在事務環境中調用(在客戶端沒有調用該組件中的方法),ejb容器就創建新的事務對象,管理該方法中的所有邏輯.
          例如:
          ejb組件:
             @Statefull
          public class personmanager inplements IPersonAdmin{
          @PersistenceContext(unitName="mydb")
          private EntityManager manager;
          @EJB(mappedName="MySession/remote")
          private IPersonAdmin mytools;
          public List<person> QueryAll(){
          ....
          }
          public void createPerson(Person p){
          Person pobj=new Person();
          pobj.setName("ziaoxioa");
          #1 manager.persist(pobj);
          #2 mytools.createPerson(p);
          #3 manager.persist(null);
          }
          客戶代碼:
          ...
          myinf.createPerson(p);
          ...
          默認情況下,ejb讀物起會為ejb組件中的所有方法配置一中requires型的事務服務.在這種事務模式下面,如果方法被在事務環境下調用,方法就使用客戶端事務對象和事務環境ruguo不在事務環境中被調用,則ejb容器就會創建新的事務對象和環境來負責管理該方法的邏輯完整性!由于上面的#3錯誤,所以數據庫中不會添加任何記錄!
          ejb容器為ejb組件添加的默認的事務策略能夠滿足多數情況下的算法要求,特殊情況下,可以通過@TransactionAttribute和<container-transaction>標記修改組件的默認事務策略!如下:
          <ejb-jar
                 xmlns="http://java.sun.com/xml/ns/javaee"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                     http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
                 version="3.0">
          <assembly-descriptor>
             <container-transaction>
                <method>
                  <ejb-name>MySession</ejb-name>
                  <method-name>createPerson</method-name>
                </method>
                <trans-attribute>RequiresNew</trans-attribute>
             </container-transaction>
          </assembly-descriptor>
          </ejb-jar>
          @TransactionAttribute(REQUIRES_NEW)
          public void createPerson(Person p){
          manager.persist(p);
          }
          這樣MySession中的createPerson方法事務修改成了RequiesNew模式,在這種模式下,ejb容器不論客戶端是否具有事務特征,為createPerson創建一個新的事務對象,此時兩個createPerson在完全不同的事務對象控制下,所以#2可以提交到數據庫中,#1,#3則回滾
          聲明性事務模式:
           Required  ejb容器為ejb組件方法提供的默認事務模式,在這種模式下,如果調用程序具備自身的事務對象,則組件方法就和客戶程序使用相同的事務對象,否則ejb容器就會創建新的事務對象來管理組件方法邏輯
           Supports  在這種模式下,如果調用程序具備事務特征,則組件方法就會調用調用程序事務對象管理自身邏輯,如果調用程序不包含任何的事務對象,則組件方法也處于無事務管理狀態
           NotSupported  這種模式下,組件方法不支持事務,同時也會忽略掉調用程序中的事務對象,組件方法中的邏輯不受客戶程序事務的提交或回滾的影響
           RequiresNew  在這種模式下,忽略調用程序具備的事務特征,ejb容器會新創建一個新的事務對象管理組件方法邏輯
           Mandatory  ejb容器不會為該方法創建新的事務管理對象。該組件方法的調用程序必須提供事務對象,處于事務環境中,否則程序將產生異常javax.ejb.EJBTransactionRequiredException
           Never  這種模式下,該方法不會被ejb容器提供事務對象服務,并且調用程序也不能處于事務環境中,否則將產生EJBException異常

          下面的程序首先清楚組件上的默認事務模式,然后在為方法設定具體事務屬性:
          <assembly-descriptor>
             <container-transaction>
                <method>
                  <ejb-name>MySession</ejb-name>
                  <method-name>*</method-name>
                </method>
                <trans-attribute>NotSupported</trans-attribute>
             </container-transaction>
             <container-transaction>
                <method>
                  <ejb-name>MySession</ejb-name>
                  <method-name>createPerson</method-name>
                </method>
                <trans-attribute>Required</trans-attribute>
             </container-transaction>
          </assembly-descriptor>
          聲明性事務的控制:
          @Stateless
          /*10*/public class PersonManager implements IPersonAdmin
          /*11*/{
          /*12*/     @Resource
          /*13*/     private EJBContext ctx;
          /*14*/     @PersistenceContext(unitName="mydb")     
          /*15*/   private EntityManager manager;
          /*16*/   @EJB(mappedName="MySession/remote")
          /*17*/   private IPersonAdmin mytools;
          /*18*/   public List<Person> QueryAll()
          /*19*/   {     
          /*20*/         Query q=manager.createQuery("from Person c");
          /*21*/         List results=q.getResultList();
          /*22*/                 List<Person> result=(List<Person>)results;
          /*23*/                 return result;
          /*24*/   }
          /*25*/   public void createPerson(Person p)
          /*26*/   {
          /*27*/         Person pobj=new Person();     
          /*28*/             pobj.setName("zhanghao");     
          /*29*/             pobj.setAge(new Integer(32)); 
          /*30*/             pobj.setSex("male");          
          /*31*/         manager.persist(pobj);
          /*32*/         boolean result=ctx.getRollbackOnly();
          /*33*/         if(!result)
          /*34*/         {
          /*35*/            ctx.setRollbackOnly();                 
          /*36*/         }
          /*37*/   }
          /*38*/}
          該方法使用gejb容器提供的默認的事務模式,事務會在方法結束時自動提交。
          getRollbackOnly()返回房前事務的狀態,true表示已經回滾,false表示沒有回滾。

          posted @ 2009-03-24 10:25 小強摩羯座 閱讀(1272) | 評論 (0)編輯 收藏

          視頻總結-jndi
          jndi:java命名和目錄接口
               jndi把object和context(還可以有subcontext)組織成一個jndi樹
          這樣object就可一被綁定到不同的context上面
          jndi是一種查找服務,用于查找:
              web應用環境變量
              EJB和他們的環境變量
              通過DataSource的數據庫連接池
              JMS沒有表和連接工廠
              其他服務
          不要將jndi當做數據庫使用
              jndi對象存儲在內存中
              訪問jndi對象與網絡性能有關
          jndi樹:
          InitialContext是JNDI樹所有搜索的起點
          對象綁定到jndi樹上,java對象是樹葉,context是節點
          一個綁定把對象與一個邏輯名和一個context關聯起來
          創建Initial Context
          從服務器端對象連接到jndi
          //創建一個InitialContext
          context ctx=new InitialContext();//鏈接到當前的jndi樹上
          從任何一個地方連接到jndi
            .創建Environment對象
             weblogic.jndi.Enviroment env=new Weblogix.jndi.Enviroment();
             填寫Enviroment
             env.setProviderurl("t3://127.0.0.1:7001");//weblogic server的位置
             env.setSecurityPrincipal("system");//安全信息
             env.setSecurityCredentiais("password");
             //使用Environment對象創建InitialContext
             context ctx=env.getInitialContext();
            .hashtable的用法....
          創建subcontext
            創建一個用于綁定對象的subcontext
            創建Environment對象
            context ctx=env.getInitialContext();//首先獲得已經存在的subcontext或者initialcontext
            填寫Environment
            context subcontext=ctx.createSubcontext("newSubcontext");
            subcontext.rebind("boundobject",object);
            subcontext.close();
            ctx.close();
          其他鏈接到jndi的方法:
           
          使用ConstantProperties名和hashtable類:
           HashTable env=new HashTable();
           env.put(Context.initial_context_factory,"weblogic.jndi.WLInitialContextFactory");
           env.put(Context.procider_url,"t3://localhost:7001");
           env.put(Context.security_principal,"system");
           env.put(Context.crrdentials,"password");
           Context ctx=new InitialContext(env);
          另一個例子:使用hardcoded名和properties類
           Properties env=new Properties();
           env.setProperties("java.naming.factory.initial","weblogic.jndi.WLInitialContextFactory");
           env.setProperties("java.naming.provider.url","t3://localhost:7001")
           env.setProperties("java.naming.security.principal","system");
           env.setProperties("java.naming.security.credentials","password");
           Context ctx=new InitialContext(env);
          jndi.properties
          .jndi.properties文件為所有的Initial Contexts設置默認的屬性
          .jndi.properties文件的搜索順序
              .classpath
              .$JAVA_HOME/lib
          實例:
           java.naming.factoyr.initial=weblogic.jndi.WLInitialContextFactory
           java.naming.security.url=t3://localhost:7001
           java.naming.security.pricipal=system
           java.naming.security.credentials=password
           使用默認值:
           Context ctx=new InitialContext();
          從jndi查找:
          .lookup()從jndi樹獲得對象
          .通過lookup()返回的對象必須映射到他們合適的類型
          try{
          //先獲得InitialContext
          //Context ic=new Context();
          Object obj;
          obj=ic.lookup("javax.transation.UserTransaction");
          UserTransaction ut=(UserTransaction)obj;
          ut.begin();
          .....
          ic.close();
          }catch(NamingEcxeption e){....}
          遠程綁定對象:
          .遠程綁定到遠程命名服務的對象必須是序列化的
          .訪問命名服務時,對象是采用復制機制
          查找的對象是序列化到客戶端的
          一個binding實例:
          public static Context getInitialContext()throws NamingException{
             創建Environment對象
             weblogic.jndi.Environment env=new Weblogix.jndi.Environment();
             填寫Enviroment
             env.setProviderurl("t3://127.0.0.1:7001");//weblogic server的位置
             env.setSecurityPrincipal("system");//安全信息
             env.setSecurityCredentiais("password");
             //使用Environment對象創建InitialContext
             context ctx=env.getInitialContext();
             return ctx;
          }
          //獲得Initial Context
          Context ctx=getInitialContext();
          //創建名為band的對象
          Bank myBank=new Bank();
          //把對象綁定到jndi樹
          ctx.rebind("theBank",myBank);
          ctx.close();

          posted @ 2009-03-24 10:22 小強摩羯座 閱讀(323) | 評論 (0)編輯 收藏

          EJB3.0中的依賴注入,截獲器及其在WebLogic Server 10中的擴展2007-09-05 來自:lizhe1985  [收藏到我的網摘]



          1 前言

            與EJB2.1相比,EJB3.0規范引入了兩個重要概念:依賴注入(DI:Dependency Injection)和截獲器(Interceptor),本文首先介紹了這兩個概念并給出相關示例,然后分析了EJB3.0規范在這兩方面的不足之處,最終深入探討了WebLogic Server 10對它們的支持和擴展。

          2 依賴注入

            2.1 基本概念

            依賴注入是從開源社區的一些著名輕量級容器(如Spring、Pico container)中所發展出來的概念,其主要思想就是由容器而不是對象本身來負責處理對象之間的依賴關系。與傳統的服務定位器相比,依賴注入具有易測試、弱侵入性等優點,這也就是為什么在最新的Java EE 5規范中引入它的原因。

            對于EJB3.0來說,依賴注入就是由容器負責查找被依賴的對象并注入到依賴bean中,而bean本身不再需要進行JNDI或者context查詢。此外,依賴注入發生在任何業務方法被調用之前,而且支持setter方法注入和域注入兩種方式。

            通過與標注結合使用,在bean類中聲明依賴注入是非常簡單的(當然,也可以在部署描述符文件中聲明依賴注入):

              @EJB用于注入EJB業務對象
              @PersistenceUnit 用于注入EntityManagerFactory
              @PersistenceContext 用于注入EntityManager
              @Resource 用于注入其它資源對象,如連接工廠、消息目標等

            2.2 示例

          @Stateless
          public class ServiceBean implements Service {
          private javax.sql.DataSource myDS;
          @Resource(mappedName=“LocalDataSource")
          public void setMyDS(javax.sql.DataSource ds) {this.myDS = ds; }
          @EJB(beanName=“AccountBean")
          private Account account;
          }

            在無狀態會話bean ServiceBean中,聲明了兩個依賴:一個是數據源,一個是業務接口。在運行期間,EJB3.0容器一旦創建了ServiceBean的實例,就會分別通過方法注入和域注入將數據源對象和業務對象注入到ServiceBean中。

          3 截獲器

            3.1 基本概念

            作為EJB3.0中提出的新概念,截獲器是可以對bean的業務方法和生命周期事件進行攔截的組件。截獲器需要由@Interceptors 或發布描述符文件中相關的標簽指定。截獲器可以帶有狀態而且可以進行依賴注入,其生命周期與其所綁定的EJB bean實例的生命周期一致。

            定義在截獲器中用于攔截目的的方法被稱為截獲器方法,其中,針對業務方法的截獲器方法通過@AroundInvoke標注或發布描述符文件中相關的標簽指定;針對生命周期回調的截獲器方法通過@PostConstruct, @PreDestroy等標注或發布描述符文件中對應的標簽指定。

            截獲器分為四類:

              缺省截獲器:可作用于ejb-jar中定義的所有EJB bean。缺省截獲器只能定義在DD中,不存在相應的標注
              類級截獲器:只能作用于所指定的EJB bean
              方法級截獲器:只能作用于所指定的某個EJB bean業務方法,方法級截獲器不能用于攔截bean的生命周期事件
              bean 級截獲器:又被稱為自我截獲器,因為截獲器同時就是EJB bean本身,此時相關的截獲器方法只能作用于該EJB

            3.2 截獲器鏈的調用順序

            因為可以為EJB定義多個截獲器,所以存在截獲器鏈的調用順序問題,缺省情況下,以下原則被遵循:

              調用順序依次是缺省截獲器、類級截獲器、方法級截獲器以及bean級截獲器
              對于同類別的截獲器,按照聲明的順序調用
              總是優先調用父類的截獲器方法。

            此外,EJB3.0規范還提供了更靈活的選項,詳細信息請參考EJB3.0規范中“截獲器”一節:

              在發布描述符文件中設置“exclude-default-interceptors” 可以取消對缺省截獲器的調用,而應用“exclude-class-interceptors”則取消對類級截獲器的調用
              為了替換缺省的截獲器鏈調用順序,可以設置發布描述符文件的“interceptor-order”。

            3.3 示例

          @Stateless(name="Trader")
          @Interceptors(ClassInterceptor.class)
          public class TraderBean implements Trader {
          @Interceptors(MethodInterceptor.class)
          public String sell(String stockSymbol) {

          }
          @AroundInvoke
          public Object selfInterceptor(InvocationContext) throws Exception {

          }
          }

            在無狀態會話bean TraderBean中,聲明了兩個截獲器:一個類級截獲器,一個方法級截獲器,此外,通過使用@AroundInvoke標注,TraderBean的方法selfInterceptor被聲明為截獲器方法,所以TraderBean就是bean級截獲器。

          4 EJB3.0規范在依賴注入和截獲器方面的不足

            從依賴注入方面來說,EJB3.0目前支持的注入類型是非常有限的,諸如List、Map之類的集合類型都不能被注入。

            另一方面,EJB3.0的截獲器可被看作是一種AOP模型,截獲器類相當于方面(Aspect),而截獲器方法相當于通知(Advice),但這種AOP是非常簡單的:

              不支持引入(Introduction);
              不支持切入點(Pointcut)模式
              通過標注告訴容器某個EJB需要使用截獲器,從而使得這種AOP模型具有一定的侵入性

          5 WebLogic Server 10 EJB3.0容器簡介

             5.1 Pitchfork 簡介

            Pitchfork是由Interface21與BEA合作開發的一個具有Apache License的開源項目,作為Spring的“增值”項目,開發Pitchfork有兩個目的:

              當前應用服務器可使用Pitchfork實現Java EE 5中的依賴注入,標注處理以及EJB3.0中的截獲器。
              在Spring容器中支持Java EE 5的標注

            5.2 WebLogic Server 10 EJB3.0容器的架構

            WebLogic Server 10完全支持Java EE 5和EJB3.0,其EJB3.0 容器是基于Pitchfork來實現依賴注入與截獲器的,而Pitchfork又利用了Spring的依賴注入和AOP。此時,WebLogic Server 10的用戶有兩種選擇:

              使用EJB3.0標準模型: EJB bean實例由EJB容器創建,然后由Pitchfork實施Java EE 5 的依賴注入和截獲器,這是WebLogic Server 10的缺省配置。
              使用Spring擴展模型:EJB bean實例由Spring容器創建并實施Spring的依賴注入,然后由Pitchfork實施Java EE 5的依賴注入,EJB3.0截獲器和Spring AOP。

          6 Spring擴展模型

            6.1 使用Spring擴展模型的主要開發步驟

              下載某個版本的Spring類庫(最好是由BEA指定的版本),至少需要包括以下jar文件:spring.jar, aspectjweaver.jar, commons-logging.jar, log4j-1.2.14.jar,如果需要,還可以增加其它jar文件。
              將這些jar文件加入到WebLogic Server 10的類路徑中。
              創建文本文件Weblogic.application.ComponentFacotry以標識當前應用將使用Spring擴展模型,其內容只有一行:    Weblogic.application.SpringComponentFactory。
              創建/META-INF/services子目錄,然后放入前面創建的文件Weblogic.application.ComponentFacotry
              建立Spring 配置文件,并放入到/META-INF目錄下,如果是EJB應用程序,Spring配置文件的名字應該是spring-ejb-jar.xml,如果是Web應用程序,Spring配置文件的名字則是spring-web.xml.
              為了使EJB bean能利用Spring的依賴注入與AOP,需要同時將其定義在spring-ejb-jar.xml(或spring-web.xml)中,從Spring角度來看,這就是一個普通的Spring bean,只不過它的id或name必須與對應的EJB name相同。
              將上述目錄文件、相關的Java類、部署描述符等打包成標準的jar文件、war文件或ear文件。

            需要注意的是,在Spring配置文件中定義的bean,如果它也是一個EJB bean,則該Spring bean的class屬性會被忽略以避免潛在的沖突。

            6.2 示例

            示例一:利用Spring的依賴注入。本例將演示兩點,(1) 注入一個集合類型,(2) 注入一個Spring POJO對象

            (1) 開發一個bean類

          @Stateless(name="AccountManagementBean")
          @Remote({examples.AccountManagement.class})
          public class AccountManagementBean
          {
          private List accountList;
          private BusinessObject businessObject;
          public boolean doBusiness(String account) {
          if (accountList.contains(account)) {
          businessObject.doBusiness();
          return true;
          }
          return false;
          }
          public BusinessObject getBusinessObject() {
          return businessObject;
          }
          public void setBusinessObject(BusinessObject businessObject) {
          this.businessObject = businessObject;
          }

          public List getAccountList() {
          return accountList;
          }
          public void setAccountList(List accountList) {
          this.accountList = accountList;
          }
          }
            (2) 一個POJO

          public class BusinessObjectImpl implements BusinessObject
          {
          private String result;

          public void doBusiness() {
          System.out.println("I am doing business, the result is: " + result);
          }

          public String getResult() {
          return result;
          }

          public void setResult(String result) {
          this.result = result;
          }
          }
            (3) Spring-ejb-jar.xml


          <beans>
          <bean name="BusinessObject" class="examples.BusinessObjectImpl">
          <property name="result" value="success" />
          </bean>
          <bean id="AccountManagementBean">
          <property name="businessObject" ref="BusinessObject" />
          <property name="accountList">
          <list>
          <value>Safin</value>
          <value>Amy</value>
          <value>Albert</value>
          <value>Yang</value>
          </list>
          </property>
          </bean>
          </beans>

            示例二:利用Spring 的AOP。本例演示了混合使用JEE interceptor、基于代理的Spring AOP以及AspectJ的Aspect

            (1) 開發一個bean類

          @Stateless(name="AccountManagementBean")
          @Remote({examples.AccountManagement.class})
          public class AccountManagementBean
          {
          public AccountManagementBean() {}
          @Interceptors({examples.JEEInterceptor.class})
          public boolean doBusiness(String account) {
          System.out.println("I am doing business " + account);
          return true;
          }
          }

            (2) 開發一個JEE interceptor

          public class JEEInterceptor {
          @AroundInvoke
          private Object intercept(InvocationContext inv) throws Exception{
          System.out.println("I am in JEEInterceptor.intercept()");
          return inv.proceed();
          }
          }

            (3) 開發一個Advice

          public class SimpleAdvice implements MethodInterceptor{
          public Object invoke(MethodInvocation invocation) throws Throwable {
          System.out.println("I am in Spring AOP interceptor");
          return invocation.proceed();
          }
          }

            (4) 開發一個Pointcut

          public class SimpleStaticPointcut extends StaticMethodMatcherPointcut {
          public boolean matches(Method method, Class cls) {
          return "doBusiness".equals(method.getName());
          }
          public ClassFilter getClassFilter() {
          return new ClassFilter() {
          public boolean matches(Class cls) {
          return AccountManagementBean.class.isAssignableFrom(cls);
          }
          };
          }
          }

            (5) 開發一個AspectJ Aspect

          @Aspect
          public class Aspects {
          @Around("execution(* examples.AccountManagementBean.doBusiness(..))")
          public Object around(ProceedingJoinPoint pjp) {
          System.out.println(“I am in AspectJ aspect);
          Object retVal = null;
          try {
          retVal = pjp.proceed();
          } catch (Throwable e) {
          e.printStackTrace();
          }
          return retVal;
          }
          }

            (5) Spring-ejb-jar.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
          http://www.springframework.org/schema/aop
          http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
          <bean id="AccountManagementBean" />
          <bean id="myAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <property name="advice">
          <bean class=”examples.SimpleAdvice” />
          </property>
          <property name="pointcut">
          <bean class="examples.SimpleStaticPointcut" />
          </property>
          </bean>
          <bean id="MyAspect" class="examples.Aspects" />
          </beans>

            6.3 優點

            提供Spring擴展模型具有如下好處:

              可以在同一個發布單元中混合使用EJB bean和Spring POJO,而且一個EJB bean可以同時是一個Spring POJO,因此被EJB容器和Spring容器同時管理
              有效地克服了EJB3.0 規范在依賴注入和截獲器方面的一些缺陷
              為用戶提供更靈活的選擇:
                如果標準的EJB 依賴注入以及截獲器可以滿足應用需求,或者可移植性是優先考慮的因素,則選用標準模型
                如果標準的EJB依賴注入以及截獲器不能滿足應用需求,或者不用考慮可移植性,或者需要集成一些Spring應用,則應選用Spring擴展模型

          7 Spring AOP在WebLogic Server 10 Spring擴展模型中的使用限制及說明

            7.1 代理生成方式

            Spring AOP采用的是一種基于代理的框架,目前有兩種生成代理的方式:JDK動態代理和CGLIB。在WebLogic Server 10的Spring擴展模型中,目前不支持CGLIB方式,這主要是因為生成的EJB類都是final的

            7.2 代理創建

            在Spring中,代理或者是通過諸如ProxyFactoryBean之類的工廠bean明確創建,或者是通過“自動代理”創建器隱含創建。

            在WebLogic Server 10中,Pitchfork已經隱含提供了類似的“自動代理”機制,所以原有的Spring代理創建方式是無效的,換句話說,用戶只需要在Spring配置文件中定義目標bean以及對應的Spring Advisor和AspectJ Aspect, 不需要再定義ProxyFactoryBean和“自動代理”創建器,Pitchfork會自動為我們創建AOP代理

            7.3 截獲的順序問題

            在Spring擴展模型中,可以混合使用JEE截獲器、Spring Advisor以及AspectJ Aspect,此時的調用順序為JEE截獲器、Spring Advisor以及AspectJ Aspect。

            7.4 bean的實例化模式

            缺省方式下,Spring bean是Singleton的,即Spring容器總是返回同一個bean實例,在Spring擴展模型中,這意味著同一個Spring Advisor或AspectJ Aspect實例將被應用到不同的EJB bean實例上,如果Advisor或Aspect實例是有狀態的,這可能會產生問題,為此我們推薦如下的使用方式:

             SLSB & MDB
              帶有狀態的Advisor或Aspect
               不推薦用帶有狀態的Advisor或Aspect,除非用戶意識到相關的后果并認為這種后果是可以接收的,此時的實例化模式取決于具體應用
              沒有狀態的Advisor或Aspect
               采用Singleton實例化模式
             SFSB
              帶有狀態的Advisor或Aspect
               正常情況下應該采用的實例化模式是Prototype,除非用戶意識到采用Singletong的后果并認為這種后果是可以接收的
              沒有狀態的Advisor或Aspect
               采用Singleton實例化模式

          8 結束語

            依賴注入和截獲器的引入,使得EJB3.0克服了很多EJB2.1的缺點,但與開源社區中流行的輕量級容器相比,EJB3.0無論是在依賴注入的范圍還是在AOP的易用性方面都還存在一定的不足。而最近BEA所推出的WebLogic Server 10不但完全支持EJB3.0,而且對其進行了有效擴展,這使得一方面可以充分利用在開源社區中出于領導地位的Spring在依賴注入和AOP方面的強大能力,另一方面又緊密依托WebLogic Server 10在事務、安全、集群方面領先的技術,從而為EJB3.0用戶開發出易維護、可擴展、高效率的企業應用程序打下堅實的基礎。

          作者簡介

            李鋼 dev2devid: cc_masterli ,BEA研發中心WebLogic Server 研發團隊成員,西安交通大學計算機專業博士,一直從事java中間件領域的研發,2005年加入BEA,現為EJB3 中國研發小組的負責人。

          posted @ 2009-03-23 18:49 小強摩羯座 閱讀(1033) | 評論 (0)編輯 收藏

          為什么要讀博ZZ
           
           
          宇.凡
               
            首先,談談為什么要讀博?

            1、如果你壓根就沒想好這個問題,完全是隨波逐流,或者證明自己是一個"好學生",或者認為考博可以帶來生活的翻天復地的變化,或者認為讀博就是混個學位,為了以后好提升,那么,請你謹慎考慮。
            首先,博士并不一定意味著高收入。收入更多的是與行業與職位相關,而不是與學位相關的。

            其次,既便為了想進高校而讀博,也要事先考慮一下是不是喜歡那種生活方式,能否接受那種清苦?能不能坐冷板凳?不然,高校的日子也不好過,競爭一樣激烈。而考博只不過是"多米諾骨牌"的第一個環節。等你博士畢業之后,不繼續自己的科研,可是又已經付出那么多青春、熱情和心血,放棄是否舍得?如果繼續從事科研,就要考慮自己是否熱愛這種寂寞的無人喝彩的工作,并且身邊都是精英,你能否承受那種壓力?要知道,真正的名專家名學者畢竟是少數,大多數人是要默默無聞、平平淡淡過一生的。你也可以有更好的未來,但那意味著加倍的付出和努力。

            2、如果已經想好了,比如就是為了提高自己的科研能力,擴大自己的知識面,或者僅僅是體驗一下這種生活,或者證明一下自己,或者臨時沒有更好的出路,想過渡一下,或者干脆就是喜歡從事科研,那么,無論任何理由,只要是堅定的,能說服自己的,那么你就可以選擇自己的活法。祝賀你,你就可以嘗試。

            接下來,我們看一下讀博士可能需要什么?

            1、高智商就不要說了,還要有高的情商。這樣才能保證自己高處能勝寒,或者寂寞的時候依然美麗著。

            但凡讀到博士的人,總是一些人群中的佼佼者。要么是絕頂聰明,要么是極端有毅力,要么就是非常靈活,總之,可謂八仙過海、各顯神通。我在讀博期間的感受之一就是,周圍的人的確不簡單,都有令人非常佩服的一面,可能再"混"日子的人,跟一般人相比也有一份自律和堅持。所以這是一個可以相互約束、相互見證、共同進步的群體。高智商基本是讀博的第一要素。

            但是不要以為光有高智商就有好的生活。高情商也很重要,比如你要經常想一下自己是什么樣的人?想過和適合過什么樣的生活?你怎樣讓自己在紛繁的亂世中保持一份清醒,遠離物質誘惑?你怎樣讓自己保持快樂?因為,的確是有一些人沒想好就進來了,所以學得很累,日子過得很牽強,時不時可能還覺得"活著沒勁"。如果這樣的話,倒不如及早融入社會洪流更讓你能安靜下來。既能出世也能入世是最好的,如果壓根做不到出世,就絕對入世一些,讓自己實際"生活"起來,也就運轉自如了。

            因為如果沒有高情商,那么讀博不但可能不會給你帶來更多的快樂,而且會帶來很多負累。因為你可能會跟社會上的人比物質,跟潛心做學問的人比成果,跟那些滋潤的"小家庭"比幸福,等等。那就比較麻煩。因為老天爺畢竟不會把所有的好事都給一個人。你得到了一些,就要坦然面對可能因此失去的。

            2、讀博需要有點毅力,沉得住氣,至少一段時間內是這樣。

            讀博可不是說著玩的。如果只是想混混,也不是那么好混的?,F在的畢業論文盲審制度,還是能卡住不少沒下功夫或者功夫下得不到,或者下了功夫但沒下到當處的人的。而且,平時博士還有論文發表的數量和檔次的要求,動不動就是國家核心期刊幾篇,理工科的可能還需要在國際刊物上發表。雖然大多數博士都完成任務,拿到了學位,但那是付出了很多焦慮、睡不著覺、掉頭發等等代價的。當然,視個人天資和基礎不同,可能各有差異,但不努力就可以完成任務的還真沒聽說過。

            平時上課、讀書的要求就不要說了。為了完成博士論文,或者在那樣一個氛圍中,為了自己至少像個博士,理工科的人要無數次地做實驗,甚至通宵達旦,而文科的學生則要天天泡在書堆里,基本上3年下來,看小說的時間是沒有的。大家都比較訓練有素,就是自己浪費了時間會自責。所以為了逃避自責的痛苦和外在的壓力,大家一般還是要選擇一點點的去面對和積累。沒有點做冷板凳的功夫是不行的,至少在一段時間內是這樣。

            博士同學中已經是碩導的,在博士論文的沖刺階段,也會形容枯槁,也有老師們形容"做完博士論文就像扒層皮",畢竟拋卻客觀要求不說,就自身而言,大家也知道專心在學校搞點研究不容易,所以基本上博士論文就是一段時間內的最高水平。何況博士論文的最高要求,也是最基本的,就是"創新"。這兩個字,可是會把人折磨壞的。結果是,做博士論文的時候,大多數同學都"自然減肥"。一個抱著僥幸心理,本來以為混混就可以過關的同學,在博士論文寫完之后,說了這樣一句深刻的推翻自己以前邏輯的話——"以后,誰要再說博士是混出來的,我跟他急!"  

            接下來看一下讀博可能帶來的一些負面影響。

            1、讀博可能會改變一個人的生活節奏和軌跡。比如戀愛、婚姻和家庭。

            說這個好象是廢話。但是我們可以算筆賬,一個人中間一直不停地讀書,等博士畢業也是接近30的人了。這時候的社會工作經驗還可能是零。如果不是足夠幸運地在讀書期間遇到合適的另一半并且已經成家的話,那么就要在畢業之后不但面臨找工作,適應新環境的問題,也要面對建立一個小家,適應婚姻和家庭的問題,還要考慮是先在工作上干出點成績還是抓緊要孩子的問題。這時候大多數小家庭都是無產階級,可能早先工作的同齡人已經擁有了自己的房子、車子和孩子,心理上的落差需要自己擺平。

            也有很大一部分人是有了一定的工作、家庭、孩子之后又去讀博的,這種辛苦就不要說了。面對家庭和自己的前途之間的不調和,需要自己判斷、選擇。有時候,有所選擇是痛苦的。所以有很多人說,早知如此,寧愿不要選擇的機會??墒菚r光是無法倒流的。校園里有不少帶著孩子讀書的母親,有的將孩子放在周邊的幼兒園或者學校里,自己面對多重壓力,孩子也跟著受苦。精力、財力和愛心、責任之間的沖突和壓力,讓很多母親說:"等我拿到學位的那一天,我可能最想做的就是找個沒人的地方大哭一場。"

            有的時候,魚和熊掌的確不可得兼,這是事實。所以大多數博士在畢業后都會多多少少有些尷尬,來自情感的、家庭的、工作的,等等。

            2、讀博可能會加重取舍之間的難度。

            有人認為,讀完博士,工作等等可選擇的余地更大了。實際上不是這樣的。博士階段著重培養的是在某一領域具有獨立進行研究和解決問題的能力的人。它不是一個通才教育,只會將人的研究領域和學習領域越限越窄。所以,除非是在高?;蜃隹蒲?,不然,博士并不是最好的選擇。

            而且,讀博可能多多少少還會產生這樣的效應,就是你在長期的研究和投入中已經多多少少對這些研究產生興趣。明知繼續研究可能熱情和動力不足,但是放棄卻著實可惜,那時該怎么辦?其實周圍很多同學都是這樣的。最后選擇的未必是最初想選擇的生活道路。我學的是文科,我的很多同學,本來想進新聞媒體,或者出版單位,或者機關等等,機會并不是沒有,但是真正抉擇的時候,卻又割舍不下對專業培養起來的感情,最終繼續選了高校進行教學科研,也有的雖然進了新聞出版,卻做的并不開心,有點后悔的意思。不得不搞學術的時候不覺得熱愛,反倒是真正離開了覺得自己"還是有點"喜歡學術的。這是一種悖論。會帶來很多困惑和尷尬,這些問題的解決需要智慧、對自己的了解,還需要決斷能力。一旦上了這賊船就必須面對,由不得你了。

            說了這些,有人可能退縮了,覺得后脊梁骨嗖嗖發涼。其實,運用最簡單的邏輯想想,如果真的讀博就像地獄,哪還有現在的趨之若騖呢?不否認有一些頭腦發昏,沒想明白就混進來的人,但是一定也是有人是真正考慮好了并認可這種方式的。權且說其一二:

            1、讀博是人的一種生活方式,而且很奢侈,不是每個人都可以享受的。

            相比于錢來說,讀博的機會顯得更是一種稀缺資源。有機會讀博的人可能不覺得,但是有很多人是壓根沒有機會考慮和嘗試的,他們的羨慕和憧憬可能不是你讀博的理由,但是至少有一點是肯定的,你可以體會跟別人不一樣的人生。這也是一種生活方式。而且這種生活體驗是非常奢侈的,有限的,難得的,所以自然也是有價值的有意義的。如果說有人選擇冒險、挑戰生命極限是一種生活方式,那么讀博也是。讀博完成和實現的是一種精神追求。享受這種方式本身就是一種經歷、一種財富、一種收獲。

            有一個同事,我在博客中提到過的,海歸,放棄了原來在外企的高薪工作,跑到國外讀博士,最后回到高校。就是因為她覺得在外企的工作,使人變得沒有時間思考,人像機器。所以為了進高校,她選擇了讀博并為這個目標奮斗了10幾年。她說,人是要有點追求的。斯夫!當人們解決了基本的生存問題之后,對精神的渴望和寄托就會浮出水面,而讀博是使人更接近思想本身的一種方式。

            2、讀博可以有機會接近和聆聽大師的聲音,并與最聰明的人相處。想不提高都難!

            有博士點的地方,大都是師資力量相當強的地方,各種資源也很多。讀博士可以使人輕而易舉地就接近原來只聞其名、不見其人的一些大家,聆聽他們在學術、做人等等方面的一些感受和教誨。這將是受益終生的。這種視界的打開和融合對一個人的提升來說至關重要。因為這些學者的點撥,可能會使人少走很多彎路,并在一些領域迅速接近國內或國外同行。某種意義上,這有"鯉魚跳龍門"之效。特別是在一些綜合性的名牌大學,這種優勢就更加明顯。用原來碩導的話說:"就像從省隊進了國家隊"。各種講座、交流以及圖書等等資源,使人進步飛快。  

          再說周圍的同學,都是來自各地的人中龍鳳。依我的經驗,每個讀到博士的人,都是有一些品質可能是一般的老百姓沒有的,比如那種悟性、那種天資、那種刻苦、那種執著、那種毅力,等等。所以,與這樣的一群聰明人交往,無論別人是不是有一些很難容忍的缺點,但也總是有一些優點是值得學習的,在這樣的一種碰撞和交流中,無論是對學術的,還是對生活的看法,都會讓人獲益匪淺。真的是想不提高都難!

          3、讀博可以積累一些資源。

            博士期間會遇到很多名師,也會有很多優秀的同學,這些都是一些潛在的資源。就算日后你的同學里出不了王侯將相,但至少以他們的起點,在各行各業上都會是不錯的骨干。至少就我而言,很多同學遍布在很多城市的很多高校,無論對搞研究,還是作為了解風土人情的交流,都是頗有助益的。博士期間的師生關系有助于建立廣泛的學術聯系。

            畢業之后,如果選擇一個中等城市或者發展中的學?;騿挝?,那么可能意味著你會瞬間擁有別人奮斗10幾年才能擁有的東西,比如各種津貼補助、比如房子,或者配偶的工作,都能得到解決。生活會有明顯提高。從這個意義上,用原來同事的話說,讀博就是賺錢?;蛘撸x博還極有可能在畢業后進入一個博士成群的工作團體。這樣,你就有可能使自己一直處于一個不斷學習不斷上升不斷進步的狀態。與智者的交流畢竟是令人愉快的。對此我受益良多。

            另外,比較重要的一點,也是一個老教授曾經說過的,做研究工作,所有的科研成果的發表,名利都是自己的,不象在機關等單位工作,在年輕的時候多是為別人做嫁衣,而到了退休,往往是人一走茶就涼。而現在看來,讀博直接地與以后是否有機會搞科研密切相關。

            4、讀博可以愉悅身心,是難得的生命體驗。

            因為博士不象本科生那樣有天天上不完的課程,有各種各樣的活動的約束,有各種檢查和評比,所以基本上屬于比較天馬行空的、自由的一群。而高校大都有優美的環境和小資的氣氛,博士生里面,大家基本上要么是有收入的,要么是可以自己賺些外快的,思想相對比較成熟了,各方面處于學校和社會的結合帶,并可以暫時脫離家庭的束縛,做一些自由自在的個性的事情,是難得的生命體驗。對于工作多年的人來說,這是一種放松、調整和休憩,而對于從未走上工作崗位的人來說,也從別人那里直接間接得到一些啟迪。

            我的博士生活就是豐富多彩的。有一幫朋友,大家經常輪流坐莊,出去吃飯、喝茶、野餐,或者就在校園里散散步、打打球,或者在學校的食堂里進行"學術午餐"和"學術晚餐",關于學術的、人生的、社會的,無所不談?,F在回想起來,我的同學和朋友都頗為留戀那段時光。我們都曾說過這樣的類似"癡人說夢"之類的話,"如果條件允許的話,真想一輩子當學生,一輩子在校園里待下去。讓讀書變成一種生活方式。"

            ......

            我想說了這么多,不知那些想了解些什么的人是更清醒了還是更暈乎了?其實,大家都是時而清醒時而糊涂的,這都正常。關鍵是,主要問題想明白了就行,小事不妨糊涂一點。某一時間和地點,我們只能有一次選擇人生的機會。是否讀博?這本身就是一個考卷。想好了再下筆,一旦下筆就堅持下去。相信,你會看到傳說中的彩虹

          相關回復:

          作者: zhangtikun   發布日期: 2008-11-16
          說的不錯
          想考博的人應該仔細權衡自己到底適不適合讀博,已讀博的人應該再多些自律和堅持,既然選擇了這種生活方式就沒有必要后悔。
          抵制些誘惑,抗拒些浮躁,忙碌的同時也要學會享受生活,在小天地里也要活得精彩。自勉!;)

          作者: sunnybrucelee   發布日期: 2008-11-16
          說的很好啊:D:D

          作者: 康熙來了   發布日期: 2008-11-16
          共勉?。。?/div>
          作者: kumu   發布日期: 2008-11-16
          非常好,借鑒中。。。

          作者: 無鋒   發布日期: 2008-11-16
          :P學習!

          作者: luzzy   發布日期: 2008-11-16
          贊這種生活方式,一直想提高自己,但實在沒有那樣的毅力,也許過慣了這種懶散的生活了.

          作者: pigeon0411   發布日期: 2008-11-16
          樓主寫的很好,很實際,幫助很大!謝謝

          作者: 紅冰2009   發布日期: 2008-11-17
          很中肯也很實在的體驗

          作者: hanbin618   發布日期: 2008-11-17
          很中肯,學習!

          作者: shtjww   發布日期: 2008-11-17
          是啊 每月不到2000的生活方式 哈哈

          作者: tent1215   發布日期: 2008-11-17
          有相同的觀點

          作者: jinlchen   發布日期: 2008-11-17
          現在有時間體驗這樣的生活,單身一人不用考慮太多的問題。 就是怕堅持不下來啊

          作者: xuht   發布日期: 2008-11-17
          一語中的,說得太好了,就是一種生活方式

          作者: pengyuan209   發布日期: 2008-11-17
          很中肯也很實在的體驗

          作者: wuyan9537   發布日期: 2008-11-18
          學習了:)

          作者: hitwyb1538   發布日期: 2008-11-19
          "讀博是一種生活方式"!

          作者: 姆粒   發布日期: 2008-11-21
          嗯:)同意

          作者: cnzxy   發布日期: 2008-11-21
          要是三年前就看到這篇文章,我想我會義無反顧放棄讀博進入社會。

          作者: 臨淵者慕魚   發布日期: 2008-11-21
          :o我還打算直博呢!
          可以借鑒一下哎!

          作者: 大雪人   發布日期: 2008-11-21
          說的很好,我想讀博,很有幫助,謝謝了

          作者: xiebin6592   發布日期: 2008-11-22
          :P:P:P

          作者: zhaoyan198   發布日期: 2008-11-28
          是寫的很好,就是倒數第二段哪些說的可能比較不切理工學生的實際,我們可沒有那個精力去喝茶聊天瀟灑去,學術討論好像也不太能形容成晚餐那么美好,也許等我畢業了會懷念,但是現在肯定還是想盡快畢業。

          作者: bsklwwy   發布日期: 2008-11-28
          說的不錯,很實際,也不偏激。
          和別的看待博士的文章不同,真正寫出了讀博的感受。

          想要讀博或正在讀博的人可以看看,有很大的啟迪!

          作者: xjlk0000   發布日期: 2008-11-28
          我也贊一下,一直在為自己的考博尋找合適的理由,心中總有那么一些文中談到的體會,卻不能明確的表達出來,謝謝樓主

          作者: tsingo   發布日期: 2008-11-28
          hao學習學習

          作者: qingqingcao288   發布日期: 2008-11-30
          很好,值得借鑒。

          posted @ 2009-02-27 02:26 小強摩羯座 閱讀(236) | 評論 (1)編輯 收藏

          dy @ 2005-12-06 20:02
          我們不逾法,但我們張揚,每一種性感都尖叫嘶喊.
          我們不色情,但我們激蕩,每一種宣泄都淋漓酣暢.
          我們不畸形,但我們包容,每一種存在都值得尊重.
          我們原創  我們獨特  我們精髓  我們唯美               ------------rock



          dy @ 2007-10-14 18:07

          一輩子有多少的來不及
          發現已經失去最重要的東西
          恍然大悟早已遠去
          為何總是在犯錯之後
          才肯相信錯的是自己.
          他們說這就是人生.試著體會
          試著忍住眼淚還是躲不開應該有的情緒

          我不會奢求世界停止轉動
          我知道逃避一點都沒有用
          只是這段時間裡尤其在夜裡
          還是會想起難忘的事情
          我想我的思念是一種病
          久久不能痊癒

          當你在穿山越領的另一邊
          我在孤獨的路上沒有盡頭
          時常感覺你在耳後的呼吸
          卻未曾感覺你在心口鼻息

          汲汲營營忘記身邊的人需要愛的關心
          藉口總是拉遠了距離不知不覺地無聲無息
          我們總是在抱怨事與願違卻願意回頭看看自己
          想想自己到底做了甚麼蠢事情.

          也許是上帝給我一個試煉
          只是這傷口需要花點時間
          只是會想念過去的一切
          那些人事物會離我遠去
          而我們終究也會遠離變成回憶

          當你在穿山越領的另一邊
          我在孤獨的路上沒有盡頭
          時常感覺你在耳後的呼吸
          卻未曾感覺你在心口的鼻息
          oh思念是一種病

          多久沒有說愛你
          多久沒有擁抱你所愛的人
          當這個世界不再那麼美好
          只有愛可以讓他更好
          我相信一切都來得及
          別管那些紛紛擾擾
          別讓不開心的事停下了腳步
          就怕你不說.就怕你不做
          別讓遺憾繼續一切都來得及

          posted @ 2009-02-27 01:43 小強摩羯座 閱讀(152) | 評論 (0)編輯 收藏

          dy @ 2008-12-01 22:50

          能做多少就做多少
          不卑 不抗 不扯淡
          多和別人交流
          多傾聽別人的想法

          堅持下去一定會有收獲

          看情況形勢  看場合說話
          不清楚的不能瞎說
          清楚的點到為止
          討論的時候  拿小本記好

          堅持下去一定會有收獲

          時常提醒自己  你還剛剛上路
          別剛會走 就要輪滑
          盡量減少抱怨 避免攀比
          不在別人耳后說三道四

          堅持下去一定會有收獲

          一天一個蘋果
          睡前讀一個小時書
          早上醒后 想想一天的計劃
          努力 讓自個保持清醒

          堅持下去一定會有收獲

          posted @ 2009-01-04 00:29 小強摩羯座 閱讀(183) | 評論 (1)編輯 收藏

          泛型編程:源起、實現與意義
           By 劉未鵬 C++的羅浮宮(http://blog.csdn.net/pongba)(去年12月《程序員》的約稿)
          (以前也寫過一篇相關的文章:Generic Programming - What Are You, anyway? )
           為什么泛型
          泛型編程(Generic Programming)最初提出時的動機很簡單直接:發明一種語言機制,能夠幫助實現一個通用的標準容器庫。所謂通用的標準容器庫,就是要能夠做到,比如用一個List類存放所有可能類型的對象,這樣的事情;熟悉一些其它面向對象的語言的人應該知道,如Java里面這是通過在List里面存放Object引用來實現的。Java的單根繼承在這里起到了關鍵的作用。然而單根繼承對C++這樣的處在語言鏈底層的語言卻是不能承受之重。此外使用單根繼承來實現通用容器也會帶來效率和類型安全方面的問題,兩者都與C++的理念不相吻合。
           
          于是C++另謀他法——除了單根繼承之外,另一個實現通用容器的方案就是使用“參數化類型”。一個容器需要能夠存放任何類型的對象,那干脆就把這個對象的類型“抽”出來,參數化它[1]
           
          template<class T> class vector {
           T* v;
           int sz;
          public:
           vector(int);
           T& operator[](int);
           T& elem(int i) { return v[i]; }
           // ...
          };
           
          一般來說看到這個定義的時候,每個人都會想到C的宏。的確,模板和宏在精神上的確有相仿之處。而且的確,也有人使用C的宏來實現通用容器。模板是將一個定義里面的類型參數化出來,而宏也可以做到參數化類型。甚至某種意義上可以說宏是模板的超集——因為宏不僅可以參數化類型,宏實質上可以參數化一切文本,因為它本來就是一個文本替換工具。然而,跟模板相比,宏的最大的缺點就是它并不工作在C++的語法解析層面,宏是由預處理器來處理的,而在預處理器的眼里沒有C++,只有一堆文本,因此C++的類型檢查根本不起作用。比如上面的定義如果用宏來實現,那么就算你傳進去的T不是一個類型,預處理器也不會報錯;只有等到文本替換完了,到C++編譯器工作的時候才會發現一堆莫名其妙的類型錯誤,但那個時候錯誤就已經到處都是了。往往最后會拋出一堆嚇人的編譯錯誤。更何況宏基本無法調試。
           
          1
          實際上,還有一種實現通用容器的辦法。只不過它更糟糕:它要求任何能存放在容器內的類型都繼承自一個NodeBase,NodeBase里面有pre和next指針,通過這種方式,就可以將任意類型鏈入一個鏈表內了。但這種方式的致命缺點是(1)它是侵入性的,每個能夠放在該容器內的類型都必須繼承自NodeBase基類。(2)它不支持基本內建類型(int、double等),因為內建類型并不,也不能繼承自NodeBase。這還姑且不說它是類型不安全的,以及效率問題。
           
          我們再來看一看通用算法,這是泛型的另一個動機。比如我們熟悉的Cqsort
           
          void qsort(void *base, size_t nmemb, size_t size,
          int (*compar)(const void *, const void *));
           
          這個算法有如下幾個問題:
           
          1.      類型安全性:使用者必須自行保證base指向的數組的元素類型和compar的兩個參數的類型是一致的;使用者必須自行保證size必須是數組元素類型的大小。
          2.      通用性:qsort對參數數組的二進制接口有嚴格要求——它必須是一個內存連續的數組。如果你實現了一個巧妙的、分段連續的自定義數組,就沒法使用qsort了。
          3.      接口直觀性:如果你有一個數組char* arr = new arr[10];那么該數組的元素類型其實就已經“透露”了它自己的大小。然而qsort把數組的元素類型給“void”掉了(void *base),于是丟失掉了這一信息,而只能讓調用方手動提供一個size。為什么要把數組類型聲明為void*?因為除此之外別無它法,聲明為任意一個類型的指針都不妥(compar的參數類型也是如此)。qsort為了通用性,把類型信息丟掉了,進而導致了必須用額外的參數來提供類型大小信息。在這個特定的算法里問題還不明顯,畢竟只多一個size參數而已,但一旦涉及的類型信息多了起來,其接口的可伸縮性(scalability)問題和直觀性問題就會逐漸顯現。
          4.      效率:compar是通過函數指針調用的,這帶來了一定的開銷。但跟上面的其它問題比起來這個問題還不是最嚴重的。
           
          泛型編程
          泛型編程最初誕生于C++中,由Alexander Stepanov[2]David Musser[3]創立。目的是為了實現C++STL(標準模板庫)。其語言支持機制就是模板(Templates)。模板的精神其實很簡單:參數化類型。換句話說,把一個原本特定于某個類型的算法或類當中的類型信息抽掉,抽出來做成模板參數T。比如qsort泛化之后就變成了:
           
          template<class RandomAccessIterator, class Compare>
          void sort(RandomAccessIterator first, RandomAccessIterator last,
                  Compare comp);
          其中first,last這一對迭代器代表一個前閉后開區間,迭代器和前開后閉區間都是STL的核心概念。迭代器建模的是內建指針的接口(解引用、遞增、遞減等)、前開后閉區間是一個簡單的數學概念,表示從first(含first)到last(不含last)的區間內的所有元素。此外,comp是一個仿函數(functor)。仿函數也是STL的核心概念,仿函數是建模的內建函數的接口,一個仿函數可以是一個內建的函數,也可以是一個重載了operator()的類對象,只要是支持函數調用的語法形式就可成為一個仿函數。
           
          通過操作符重載,C++允許了自定義類型具有跟內建類型同樣的使用接口;又通過模板這樣的參數化類型機制,C++允許了一個算法或類定義,能夠利用這樣的接口一致性來對自身進行泛化。例如,一個原本操作內建指針的算法,被泛化為操縱一切迭代器的算法。一個原本使用內建函數指針的算法,被泛化為能夠接受一切重載了函數調用操作符(operator())的類對象的算法。
           
          讓我們來看一看模板是如何解決上面所說的qsort的各個問題的:
           
          1.      類型安全性:如果你調用std::sort(arr, arr + n, comp);那么comp的類型就必須要和arr的數組元素類型一致,否則編譯器就會幫你檢查出來。而且comp的參數類型再也不用const void*這種不直觀的表示了,而是可以直接聲明為對應的數組元素的類型。
          2.      通用性:這個剛才已經說過了。泛型的核心目的之一就是通用性。std::sort可以用于一切迭代器,其compare函數可以是一切支持函數調用語法的對象。如果你想要將std::sort用在你自己的容器上的話,你只要定義一個自己的迭代器類(嚴格來說是一個隨機訪問迭代器,STL對迭代器的訪問能力有一些分類,隨機訪問迭代器具有建模的內建指針的訪問能力),如果需要的話,再定義一個自己的仿函數類即可。
          3.      接口直觀性:跟qsort相比,std::sort的使用接口上沒有多余的東西,也沒有不直觀的size參數。一個有待排序的區間,一個代表比較標準的仿函數,僅此而已[4]。
          4.      效率:如果你傳給std::sortcompare函數是一個自定義了operator()的仿函數。那么編譯器就能夠利用類型信息,將對該仿函數的operatpr()調用直接內聯。消除函數調用開銷。
           
          動態多態與靜態多態
          泛型編程的核心活動是抽象:將一個特定于某些類型的算法中那些類型無關的共性抽象出來,比如,在STL的概念體系里面,管你是一個數組還是一個鏈表,反正都是一個區間,這就是一層抽象。管你是一個內建函數還是一個自定義類,反正都是一個Callable(可調用)的對象(在C++里面通過仿函數來表示),這就是一層抽象。泛型編程的過程就是一個不斷將這些抽象提升(lift)出來的過程,最終的目的是形成一個最大程度上通用的算法或類。
           
          有人肯定會問,既然同是抽象,那為什么不用基于多態的面向對象抽象呢?比如STLstd::for_each,用Java的多態機制也可以解決:
           
          interface IUnaryFun
          {
          void invoke(Object o);
          }
           
          interface IInputIter
          {
          IInputIter preIncrement();
          boolean equals(IInputIter otherIter);
          … // other methods
          }
           
          IUnaryFun for_each(IInputIter first, IInputIter last, IUnaryFun func)
          {
           for(;!first.equals(last); first.preIncrement())
          func.invoke(*first);
           return func;
          }
           
          其實,這里最主要的原因很簡單,效率。面向對象的多態引入了間接調用。當然,并不是說間接調用不好,有些時候,比如確實需要運行期多態的時候,只能訴諸繼承這樣的手段。但當能夠利用編譯期類型信息的時候,為什么要付出不必要的間接調用開銷呢?比如這里的for_each,利用接口來實現其通用性,就付出了所謂的“抽象懲罰”(abstraction penalty)。而C++的模板,就是為了消除這樣的抽象懲罰。利用模板編寫的std::for_each,對于每一個特定的參數類型組合都有一個獨立的,最高效的實例化版本,就跟你手寫一個特定于這些類型的專門的for_each算法一樣[5]。于是抽象懲罰消失了,而這也正是C++模板庫能夠真正被工業界廣泛用在C++最擅長的領域(重視效率的領域)的重要原因之一。
           
          另一方面,對于每一組參數類型組合實例化一個版本出來的做法增加了代碼空間,這是一個典型的以空間換時間的例子,不過對于一門靜態并追求效率的語言來說,這個代碼空間的開銷反正也是必不可少的,因為即便你手動為各種不同的參數類型組合編寫特定的算法版本的話,也是付出一樣的代碼空間開銷,而且還順便違反了DRY原則[6]。此外,由于在抽象的時候不用總想著要建立的接口,所以泛型算法編寫起來也更為直觀。
           
          C++泛型的另一個好處就是,跟面向對象編程的基于繼承和虛函數的運行時多態機制不同,C++模板是非侵入性的。你不需要讓你的類繼承自某個特定的接口才能用于某個算法,只要支持特定的語法接口就行了(比如只要支持begin()調用)。這也被稱為結構一致性(Structural Conformance),意即只要語法結構一致即可。而另一方面,基于接口繼承的面向對象多態則必須要顯式地聲明繼承自一個接口,這就是所謂的名字一致性(Named Conformance)。
           
          當然,泛型支持的靜態多態和虛函數支持的動態多態并沒有任何程度上絕對的優劣之分。它們適用于不同的場合。當類型信息可得的時候,利用編譯期多態能夠獲得最大的效率和靈活性。當具體的類型信息不可得,就必須訴諸運行期多態了。Bjarne Stroustrup曾經用了一個典型的例子來澄清這個區別:
           
          std::vector<Shape*> v;
          … // fill v
          std::for_each(v.begin(), v.end(), std::mem_fun(&Shape::draw));
           
          這里,v里面到底將來會存放什么類型的Shape,編譯期無法知道,因而必須求助于動態多態。另一方面,編譯器倒的確知道它們都繼承自Shape,利用這僅有的靜態類型信息,我們使用了泛型算法std::for_each和泛型容器std::vector。這里尤其值得注意的是for_each的靜態多態行為:for_each只有一份模板實現,然而根據傳給它的第三個參數(本例中是std::mem_fun(&Shape::draw))的不同,for_each的行為也不同(這里最終被for_each調用的是Shape::draw,但實際上你可以包裝任何函數,只要這個函數接受一個Shape*型的參數),for_each這種“行為不同”是發生在編譯期的,所以是靜態多態。
           
          前面說過,模板與接口繼承比較,模板是非侵入的。這是C++泛型與面向對象的多態機制的本質區別之一。但實際上,面向對象未必就意味著一定要用接口來實現動態的多態。一些動態類型的腳本語言,如Ruby,它的多態機制就既是運行期(動態)的,又是非傾入性的(不用通過繼承自某個特定的接口來達到復用)。人們把這個叫做Duck Typing[7]。如果不是因為效率問題,其實這樣的多態機制才是最直觀的,從使用方面來說,它既有非侵入性,又沒有只能工作在編譯期的限制。但效率至少在可見的將來、在某些領域仍是一個顧慮。因此像C++這種區分編譯期和運行期多態的語言,仍有其獨特的優勢。
           
          此外,泛型編程的類型安全優勢也讓它從C++走入了其它主流的靜態類型語言當中,尤其是C家族的JavaC#,在前幾年相繼接納泛型。
           
          特化,圖靈完備性,元編程
          C++的模板是支持特化的,這就給了它實現編譯期控制結構的可能性,進而帶來了一個圖靈完備的子語言。模板特化的引入原本只是為了效率目的——針對不同的類型提供不同的實現。但后來卻被發現能夠實現編譯期的if/else和遞歸等控制結構。
           
          模板元編程最初由Erwin Unruh1994年的一次會議上提出;當時他寫了一個程序,在編譯錯誤里面打印出一個素數序列。這個事件在C++歷史上的地位就仿佛哥倫布發現新大陸。用Bjarne Stroustrup的話來說就是當時他當時和其他幾個人覺得太神奇了。實際上,這個事情正標志了C++模板系統的圖靈完備性被發現;后來Todd Veldhuizen寫了一篇paper,用C++模板構建了一個元圖靈機,從而第一次系統證明了C++模板的圖靈完備性。接下來的事情就順理成章了——一些ad hoc的模板元編程技巧不斷被發掘出來,用于建造高效、高適應性的通用組件。最終,David Abrahams編寫了boost庫中的基本組件之一:Boost.MPL庫。Boost.MPL以類型和編譯期常量為數據,以模板特化為手段,實現了一個編譯期的STL。你可以看到常見的vector,你可以看到transform算法,只不過算法操縱的對象和容器存放的對象不再是運行期的變量或對象,而是編譯期的類型和常量。想知道模板元編程是如何用在庫構建中的,可以打開一個Boost的子庫(比如Boost.TupleBoost.Variant)看一看。
           
          然而,畢竟C++的模板元編程是一門被發現而不是被發明的子語言。一方面,它在構建泛型庫的時候極其有用。然而另一方面,由于它并非語言設計初始時考慮在內的東西,所以不僅在語法上面顯得不那么first-class(比較笨拙);更重要的是,由于本不是一個first-class的語言特性,所以C++編譯器并不知道C++元編程的存在。這就意味著,比如對下面這樣一個編譯期的if/else設施[8]
           
          template<bool b, class X, class Y>
          struct if_ {
           typedef X type; // use X if b is true
          };
          template<class X, class Y>
          struct if_<false,X,Y> {
          typedef Y type; // use Y if b is false
          };
           
          typedef if_<(sizeof(Foobar)<40), Foo, Bar>::type type;
           
          編譯器并沒有真的去進行if/else的分支選擇,而是按部就班毫不知情地進行著模板的特化匹配。如果遇到Boost.MPL這樣的模板元編程非常重的庫,就會嚴重拖累編譯速度,編譯器進行了一重一重的特化匹配,實例化了一個又一個的模板實例,就是為了去獲取里面定義的一個typedef,完了之后中間所有實例化出來的模板實例類型全都被丟棄[9]
           
          模板元編程最全面深入的介紹是Boost.MPL庫的作者David Abrahams的《C++ Template Metaprogramming》,其中的樣章(第三章)[10]對模板元編程作了一個非常高屋建瓴的概覽[11]。
           
          關于模板元編程,需要提醒的是,它并不屬于“大眾技術”。日常編程中極少需要用到元編程技巧。另一方面,C++模板里面有大量ad hoc的技巧,如果一頭扎進去的話,很容易只見樹木不見森林,所以需要提醒初學者的是,即便要學習,也要時刻保持“高度”,始終記得元編程的意義和目的,這樣才不至于迷失在無窮無盡的語言細節中。
           
          C++09——進化
          泛型編程在C++中取得了工業程度上的成功,得益于其高效性和通用性。但同時,在經過了近十年的使用之后,C++模板,這個作為C++實現泛型的機制的缺點也逐漸暴露出來。比如其中對于初學者最嚴重的一個問題就是在使用一個模板庫時常常遇到無法理解的編譯錯誤,動輒長達上K字節。這些編譯錯誤很容易把一個初學者嚇走。究其本質原因,為什么編譯器會報出令人難以卒讀的編譯錯誤,是因為在編譯器的眼里,只有類型,而沒有“類型的類型”。比如說,迭代器就是一個類型的類型,C++里面也把它稱為“概念”(Concept)。例如,std::sort要求參數必須是隨機訪問迭代器,如果你一不小心給了它一個非隨機訪問的迭代器,那么編譯器不是抱怨“嘿!你給我的不是隨機訪問迭代器”,而是抱怨找不到某某重載操作符(典型的比如operator+(int))。因為在編譯器眼里,沒有“迭代器”這么個概念,這個概念只存在于程序員腦子里和STL的文檔里。為了幫助編譯器產出更友好的信息(當然,還有許多非常重要的其它原因[12]),C++09將對“類型的類型”加入first-class的支持,其帶來的眾多好處會將C++中的泛型編程帶向一個新的高度:更友好、更實用、更直觀。
           
          此外,C++的模板元編程尚沒有first-class的語言支持,一方面是因為其運用不像一般的模板編程這么廣泛,因而沒有這么緊急。另一方面,C++09的時間表也等不及一個成熟的提案。如果以后模板元編程被運用得越來越廣泛的話,那first-class的語言支持是難免的。
           
          總結
          本文對C++模板,以及C++模板所支持的泛型編程作了一個概覽。著重介紹了泛型編程誕生的原因,泛型編程的過程和意義,與其它抽象手段的比較。并對C++中的模板元編程做了一些介紹。最后介紹了C++模板在C++09中的增強。
           


          [1] B. Stroustrup: A History of C++: 1979-1991. Proc ACM History of Programming Languages conference (HOPL-2). March 1993.
          [2] http://en.wikipedia.org/wiki/Alexander_Stepanov
          [3] http://www.cs.rpi.edu/~musser
          [4] 實際上,STL的區間概念被證明是一個不完美的抽象。你有沒有發現,要傳遞一個區間給一個函數,如std::sort,你需要傳遞兩個參數,一個是區間的開頭,一個是區間的末尾。這種分離的參數傳遞方式被證明是不明智的,在一些場合會帶來使用上不必要的麻煩。比如你想迭代一組文件,代表這組文件的區間由一個readdir_sequence函數返回,由于要分離表達一個區間,你就必須寫:
          readdir_sequence entries(".", readdir_sequence::files);
          std::for_each(entries.begin(), entries.end(), ::remove);
          如果你只想遍歷這個區間一次的話,你也許不想聲明entries這個變量,畢竟多一個名字就多一個累贅,你也許只想:
          std::for_each(readdir_sequence(".", readdir_sequence::files), ::remove);
          下一代C++標準(C++09)會解決這個問題(將區間這個抽象定義為一個整體)。
          [5] 當然,語言并沒有規定模板實例化的底層實現一定要是對每組參數類型組合實例化一個版本出來。但目前的實現,這種方案是最高效的。完全消除了抽象懲罰。另一方面,One size fit all的方案也不是不可行,但總會有間接調用。這也正說明了靜態類型系統的一個典型優點:幫助編譯器生成更高效的代碼。
          [6] http://en.wikipedia.org/wiki/Don't_repeat_yourself
          [7] http://en.wikipedia.org/wiki/Duck_typing
          [8] 摘自Bjarne Stroustrup的paper:Evolving a language in and for the real world: C++ 1991-2006
          [9] 也正因此,D語言加入了語言直接對模板元編程的支持,比如真正工作在編譯期的static if-else語句。
          [10] http://www.boost-consulting.com/mplbook/
          [11] 第三章的翻譯見我的blog:《深度探索元函數》http://blog.csdn.net/pongba/archive/2004/09/01/90642.aspx
          [12] 由于篇幅原因,這里無法展開詳述Concept對C++泛型編程的其它重要意義,有興趣的可以參見我的一篇blog:《C++0x漫談系列之:Concept! Concept!》。http://blog.csdn.net/pongba/archive/2007/08/04/1726031.aspx

          posted @ 2009-01-04 00:28 小強摩羯座 閱讀(208) | 評論 (0)編輯 收藏


          常去看的幾個博客
          1、劉未鵬|C++的羅浮宮
          http://blog.csdn.net/pongba
          假如你對人工智能、機器學習、知識發現和認知科學有興趣,這個博客絕對是一個寶藏!

           

          2、笑對人生,傲立寰宇 的博客:
          http://dahua.spaces.live.com/blog/
          一個非常好的技術博客,博主林大華是中科大本科、香港中文大學碩士,目前在MIT讀博。博客里有很多深入淺出、詼諧有趣的技術文章和讀書心得,常讓我拍案叫絕,那些干澀無味的數學原理也可以聊侃得如此趣味橫生,呵呵。數學和matlab方面的朋友不妨多上去看看 O(∩_∩)O

           

          3、不交作業 的博客:
          http://blog.163.com/oneoctopus@126/blog/
          一位在華南理工大學讀研的學生,和他不相識,但每周都會去他的博客看看。也許是因為同齡,看他的博客、他的經歷,讓自己有很大的共鳴。研二一年,就集中精力寫一篇文章,近期才完稿,投到著名的ACC(American Control Conference)會議去,有點‘十年磨一劍’的感覺;目前研三在申請美國的名校,祝他馬到成功啦。

          同齡人前進的腳步,最能鞭策自己不懈前行……

           

          4、晃晃悠悠 的博客:
          http://dy1981.ycool.com/
          以前學習小波的時候接觸到的一個博客,挺不錯的,而且還有對音樂和現實生活的一些體會和感受,每個人的人生故事都有特別的精彩之處。

           

          5、蘿卜驛站 的博客:
          http://luobo.ycool.com/
          matlab強人,博客里有N多小波、混沌等方面的matlab代碼共享,還有很多matlab編程技巧方面的解答。

           

          6、天上有宮闕 的博客:
          http://www.myclub2.com/blog/realghost/category/1396.html
          里面有不少matlab和數學的學習資料,特別是代碼共享,呵呵。


          posted @ 2009-01-04 00:27 小強摩羯座 閱讀(250) | 評論 (0)編輯 收藏

          讓人心疼的12句話...哪句說到你...-

          1有些事,我們明知道是錯的,也要去堅持,因為不甘心;有些人,我們明知道是愛的,也要去放棄,因為沒結局;有時候,我們明知道沒路了,卻還在前行,因為習慣了 

          2以為蒙上了眼睛,就可以看不見這個世界;以為捂住了耳朵,就可以聽不到所有的煩惱;以為腳步停了下來,心就可以不再遠行;以為我需要的愛情,只是一個擁抱 
           

          3那些已經犯過的錯誤,有一些是因為來不及,有一些是因為刻意躲避,更多的時候是茫然地站到了一邊我們就這樣錯了一次又一次,卻從不曉得從中汲取教訓,做一些反省 

          4你不知道我在想你,是因為你不愛我,我明明知道你不想我,卻還愛你,是因為我太傻也許有時候,逃避不是因為害怕去面對什么,而是在等待什么 

          5天空沒有翅膀的痕跡,但鳥兒已經飛過;心里沒有被刀子割過,但疼痛卻那么清晰這些胸口里最柔軟的地方,被愛人傷害過的傷口,遠比那些肢體所受的傷害來得犀利,而且只有時間,才能夠治愈 

          6很多人,因為寂寞而錯愛了一人,但更多的人,因為錯愛一人,而寂寞一生我們可以彼此相愛,卻注定了無法相守不是我不夠愛你,只是我不敢肯定,這愛,是不是最正確的 

          7如果背叛是一種勇氣,那么接受背叛則需要一種更大的勇氣前者只需要有足夠的勇敢就可以,又或許只是一時沖動,而后者考驗的卻是寬容的程度,絕非沖動那么簡單,需要的唯有時間 

          8生命無法用來證明愛情,就像我們無法證明自己可以不再相信愛情在這個城市里,誠如勞力士是物質的奢侈品,愛情則是精神上的奢侈品可是生命脆弱無比,根本沒辦法承受那么多的奢侈 

          9人最大的困難是認識自己,最容易的也是認識自己很多時候,我們認不清自己,只因為我們把自己放在了一個錯誤的位置,給了自己一個錯覺所以,不怕前路坎坷,只怕從一開始就走錯了方向 

          10生活在一個城市里,或者愛一個人,又或者做某件事,時間久了,就會覺得厭倦,就會有一種想要逃離的沖動也許不是厭倦了這個城市愛的人堅持的事,只是給不了自己堅持下去的勇氣 

          11多少次又多少次,回憶把生活劃成一個圈,而我們在原地轉了無數次,無法解脫總是希望回到最初相識的地點,如果能夠再一次選擇的話,以為可以愛得更單純
           
          12如果你明明知道這個故事的結局,你或者選擇說出來,或者裝作不知道,萬不要欲言又止有時候留給別人的傷害,選擇沉默比選擇坦白要痛多了 

          posted @ 2008-12-24 16:05 小強摩羯座 閱讀(181) | 評論 (0)編輯 收藏

          僅列出標題
          共20頁: First 上一頁 5 6 7 8 9 10 11 12 13 下一頁 Last 
          主站蜘蛛池模板: 天柱县| 蛟河市| 定边县| 绥棱县| 行唐县| 叙永县| 新邵县| 青龙| 阜城县| 内乡县| 娄底市| 泸水县| 深圳市| 大渡口区| 沛县| 高邑县| 健康| 泾源县| 勐海县| 平江县| 舒兰市| 基隆市| 昭平县| 大余县| 丹凤县| 沅江市| 闻喜县| 潼南县| 崇文区| 太湖县| 武胜县| 正镶白旗| 钟祥市| 互助| 金阳县| 玛纳斯县| 东海县| 桐城市| 邵东县| 许昌市| 清丰县|