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

          jndi全局注冊表和enc的基本概念
             通俗的將jndi就是對ejb容器中所有的資源和組件進行管理的花名冊,通過該服務(wù),可以很方便的找到希望使用的資源。當(dāng)組件被部署到服務(wù)器上后,該組件就會被自動注冊到花名冊上,以便用戶使用,如果組件被卸載,花名冊上的記錄就會自動消失。
              jndi中注冊的所有的資源和組件可以被服務(wù)器內(nèi)外的各種程序請求或者訪問,是一種全局性的資源!但是ejb中不同的組件通過全局性的jndi服務(wù)器形成依賴關(guān)系,則會給系統(tǒng)造成不穩(wěn)定的因素!因此就引入了enc(ejb組件的企業(yè)名稱上下文)的概念!通過她來實現(xiàn)不同組件之間的引用關(guān)系?。。?!
          在上一篇文章中寫到了通過標(biāo)注的方式實現(xiàn)方向依賴注入!還以上篇為例:
          有接口:HelloWordRemote  HelloWordLocal ICal(Remote)
          而HelloWordBean實現(xiàn)了分別實現(xiàn)了他們
          另外又有了個遠程接口:
          @Remote
          public Interface MyService{
          public String helloWord();
          public int add(int a,int b);
          }
          一個類想實現(xiàn)這個接口并且在這個類中引用了...如下:
          @Stateless
          public class FacedServcie implements MyService{
          private HelloWordLocal myserv1;
          private ICal ical;
          .....
          ....
          }
          可以通過配置文件實現(xiàn)反向依賴注入:
          <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>
          還可以通過檢索的方式來實現(xiàn):
          @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>
          本人建議使用第一種反向依賴注入的方式!
          還有其他的一些注入:如持久化單元注入,資源型注入 數(shù)據(jù)源類型的注入。。。

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

          EJB事務(wù)
          在ejb組件設(shè)計中,組件行為有時需要具備事務(wù)特征,即使用事務(wù)保證組件行為的完整性,使組件要么執(zhí)行成功,要么回到起點.等價沒有執(zhí)行!
          討論事務(wù)時要明確兩個概念:
          事務(wù)范圍
          算法的可恢復(fù)性與事務(wù)性:如果事務(wù)中的算法動作結(jié)果受事務(wù)提交或者回滾影響,則該算法具有事務(wù)可恢復(fù)性,否則就不具備事務(wù)可恢復(fù)性.
          事務(wù)在本質(zhì)上就是一個管理系列算法動作一致性的對象!ejb提供了兩種事務(wù)類型:聲明性和程序性事務(wù)
          聲明性事務(wù):由ejb容器負(fù)責(zé)事務(wù)對象的 生成,管理,銷毀;具體算法在事務(wù)上的注冊,事務(wù)的提交和回滾等
          主要介紹聲明性的事務(wù):
             ejb容器為其中的所有的ejb組件提供了一種默認(rèn)的事務(wù)模式:Requires
          在該模式下面,組件中的方法如果在事務(wù)環(huán)境下被調(diào)用(即客戶端調(diào)用了該組件的方法),則方法中的邏輯會被添加到客戶端的事務(wù)環(huán)境中,和客戶端的程序使用相同的事務(wù)控制對象.如果不在事務(wù)環(huán)境中調(diào)用(在客戶端沒有調(diào)用該組件中的方法),ejb容器就創(chuàng)建新的事務(wù)對象,管理該方法中的所有邏輯.
          例如:
          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);
          ...
          默認(rèn)情況下,ejb讀物起會為ejb組件中的所有方法配置一中requires型的事務(wù)服務(wù).在這種事務(wù)模式下面,如果方法被在事務(wù)環(huán)境下調(diào)用,方法就使用客戶端事務(wù)對象和事務(wù)環(huán)境ruguo不在事務(wù)環(huán)境中被調(diào)用,則ejb容器就會創(chuàng)建新的事務(wù)對象和環(huán)境來負(fù)責(zé)管理該方法的邏輯完整性!由于上面的#3錯誤,所以數(shù)據(jù)庫中不會添加任何記錄!
          ejb容器為ejb組件添加的默認(rèn)的事務(wù)策略能夠滿足多數(shù)情況下的算法要求,特殊情況下,可以通過@TransactionAttribute和<container-transaction>標(biāo)記修改組件的默認(rèn)事務(wù)策略!如下:
          <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方法事務(wù)修改成了RequiesNew模式,在這種模式下,ejb容器不論客戶端是否具有事務(wù)特征,為createPerson創(chuàng)建一個新的事務(wù)對象,此時兩個createPerson在完全不同的事務(wù)對象控制下,所以#2可以提交到數(shù)據(jù)庫中,#1,#3則回滾
          聲明性事務(wù)模式:
           Required  ejb容器為ejb組件方法提供的默認(rèn)事務(wù)模式,在這種模式下,如果調(diào)用程序具備自身的事務(wù)對象,則組件方法就和客戶程序使用相同的事務(wù)對象,否則ejb容器就會創(chuàng)建新的事務(wù)對象來管理組件方法邏輯
           Supports  在這種模式下,如果調(diào)用程序具備事務(wù)特征,則組件方法就會調(diào)用調(diào)用程序事務(wù)對象管理自身邏輯,如果調(diào)用程序不包含任何的事務(wù)對象,則組件方法也處于無事務(wù)管理狀態(tài)
           NotSupported  這種模式下,組件方法不支持事務(wù),同時也會忽略掉調(diào)用程序中的事務(wù)對象,組件方法中的邏輯不受客戶程序事務(wù)的提交或回滾的影響
           RequiresNew  在這種模式下,忽略調(diào)用程序具備的事務(wù)特征,ejb容器會新創(chuàng)建一個新的事務(wù)對象管理組件方法邏輯
           Mandatory  ejb容器不會為該方法創(chuàng)建新的事務(wù)管理對象。該組件方法的調(diào)用程序必須提供事務(wù)對象,處于事務(wù)環(huán)境中,否則程序?qū)a(chǎn)生異常javax.ejb.EJBTransactionRequiredException
           Never  這種模式下,該方法不會被ejb容器提供事務(wù)對象服務(wù),并且調(diào)用程序也不能處于事務(wù)環(huán)境中,否則將產(chǎn)生EJBException異常

          下面的程序首先清楚組件上的默認(rèn)事務(wù)模式,然后在為方法設(shè)定具體事務(wù)屬性:
          <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>
          聲明性事務(wù)的控制:
          @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容器提供的默認(rèn)的事務(wù)模式,事務(wù)會在方法結(jié)束時自動提交。
          getRollbackOnly()返回房前事務(wù)的狀態(tài),true表示已經(jīng)回滾,false表示沒有回滾。

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

          視頻總結(jié)-jndi
          jndi:java命名和目錄接口
               jndi把object和context(還可以有subcontext)組織成一個jndi樹
          這樣object就可一被綁定到不同的context上面
          jndi是一種查找服務(wù),用于查找:
              web應(yīng)用環(huán)境變量
              EJB和他們的環(huán)境變量
              通過DataSource的數(shù)據(jù)庫連接池
              JMS沒有表和連接工廠
              其他服務(wù)
          不要將jndi當(dāng)做數(shù)據(jù)庫使用
              jndi對象存儲在內(nèi)存中
              訪問jndi對象與網(wǎng)絡(luò)性能有關(guān)
          jndi樹:
          InitialContext是JNDI樹所有搜索的起點
          對象綁定到j(luò)ndi樹上,java對象是樹葉,context是節(jié)點
          一個綁定把對象與一個邏輯名和一個context關(guān)聯(lián)起來
          創(chuàng)建Initial Context
          從服務(wù)器端對象連接到j(luò)ndi
          //創(chuàng)建一個InitialContext
          context ctx=new InitialContext();//鏈接到當(dāng)前的jndi樹上
          從任何一個地方連接到j(luò)ndi
            .創(chuàng)建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對象創(chuàng)建InitialContext
             context ctx=env.getInitialContext();
            .hashtable的用法....
          創(chuàng)建subcontext
            創(chuàng)建一個用于綁定對象的subcontext
            創(chuàng)建Environment對象
            context ctx=env.getInitialContext();//首先獲得已經(jīng)存在的subcontext或者initialcontext
            填寫Environment
            context subcontext=ctx.createSubcontext("newSubcontext");
            subcontext.rebind("boundobject",object);
            subcontext.close();
            ctx.close();
          其他鏈接到j(luò)ndi的方法:
           
          使用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設(shè)置默認(rèn)的屬性
          .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
           使用默認(rèn)值:
           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){....}
          遠程綁定對象:
          .遠程綁定到遠程命名服務(wù)的對象必須是序列化的
          .訪問命名服務(wù)時,對象是采用復(fù)制機制
          查找的對象是序列化到客戶端的
          一個binding實例:
          public static Context getInitialContext()throws NamingException{
             創(chuàng)建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對象創(chuàng)建InitialContext
             context ctx=env.getInitialContext();
             return ctx;
          }
          //獲得Initial Context
          Context ctx=getInitialContext();
          //創(chuàng)建名為band的對象
          Bank myBank=new Bank();
          //把對象綁定到j(luò)ndi樹
          ctx.rebind("theBank",myBank);
          ctx.close();

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

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



          1 前言

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

          2 依賴注入

            2.1 基本概念

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

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

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

              @EJB用于注入EJB業(yè)務(wù)對象
              @PersistenceUnit 用于注入EntityManagerFactory
              @PersistenceContext 用于注入EntityManager
              @Resource 用于注入其它資源對象,如連接工廠、消息目標(biāo)等

            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;
          }

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

          3 截獲器

            3.1 基本概念

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

            定義在截獲器中用于攔截目的的方法被稱為截獲器方法,其中,針對業(yè)務(wù)方法的截獲器方法通過@AroundInvoke標(biāo)注或發(fā)布描述符文件中相關(guān)的標(biāo)簽指定;針對生命周期回調(diào)的截獲器方法通過@PostConstruct, @PreDestroy等標(biāo)注或發(fā)布描述符文件中對應(yīng)的標(biāo)簽指定。

            截獲器分為四類:

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

            3.2 截獲器鏈的調(diào)用順序

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

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

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

              在發(fā)布描述符文件中設(shè)置“exclude-default-interceptors” 可以取消對缺省截獲器的調(diào)用,而應(yīng)用“exclude-class-interceptors”則取消對類級截獲器的調(diào)用
              為了替換缺省的截獲器鏈調(diào)用順序,可以設(shè)置發(fā)布描述符文件的“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 {

          }
          }

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

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

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

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

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

          5 WebLogic Server 10 EJB3.0容器簡介

             5.1 Pitchfork 簡介

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

              當(dāng)前應(yīng)用服務(wù)器可使用Pitchfork實現(xiàn)Java EE 5中的依賴注入,標(biāo)注處理以及EJB3.0中的截獲器。
              在Spring容器中支持Java EE 5的標(biāo)注

            5.2 WebLogic Server 10 EJB3.0容器的架構(gòu)

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

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

          6 Spring擴展模型

            6.1 使用Spring擴展模型的主要開發(fā)步驟

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

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

            6.2 示例

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

            (1) 開發(fā)一個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) 開發(fā)一個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) 開發(fā)一個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) 開發(fā)一個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) 開發(fā)一個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) 開發(fā)一個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 優(yōu)點

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

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

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

            7.1 代理生成方式

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

            7.2 代理創(chuàng)建

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

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

            7.3 截獲的順序問題

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

            7.4 bean的實例化模式

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

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

          8 結(jié)束語

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

          作者簡介

            李鋼 dev2devid: cc_masterli ,BEA研發(fā)中心WebLogic Server 研發(fā)團隊成員,西安交通大學(xué)計算機專業(yè)博士,一直從事java中間件領(lǐng)域的研發(fā),2005年加入BEA,現(xiàn)為EJB3 中國研發(fā)小組的負(fù)責(zé)人。

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

          為什么要讀博ZZ
           
           
          宇.凡
               
            首先,談?wù)劄槭裁匆x博?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            ......

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

          相關(guān)回復(fù):

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

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

          作者: 康熙來了   發(fā)布日期: 2008-11-16
          共勉?。?!

          作者: kumu   發(fā)布日期: 2008-11-16
          非常好,借鑒中。。。

          作者: 無鋒   發(fā)布日期: 2008-11-16
          :P學(xué)習(xí)!

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

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

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

          作者: hanbin618   發(fā)布日期: 2008-11-17
          很中肯,學(xué)習(xí)!

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

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

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

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

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

          作者: wuyan9537   發(fā)布日期: 2008-11-18
          學(xué)習(xí)了:)

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

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

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

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

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

          作者: xiebin6592   發(fā)布日期: 2008-11-22
          :P:P:P

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

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

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

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

          作者: tsingo   發(fā)布日期: 2008-11-28
          hao學(xué)習(xí)學(xué)習(xí)

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

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

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



          dy @ 2007-10-14 18:07

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

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

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

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

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

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

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

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

          dy @ 2008-12-01 22:50

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

          堅持下去一定會有收獲

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

          堅持下去一定會有收獲

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

          堅持下去一定會有收獲

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

          堅持下去一定會有收獲

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

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


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

           

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

           

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

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

           

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

           

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

           

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

          僅列出標(biāo)題
          共20頁: First 上一頁 5 6 7 8 9 10 11 12 13 下一頁 Last 
          主站蜘蛛池模板: 鹿泉市| 大冶市| 株洲市| 玉山县| 呈贡县| 慈利县| 资源县| 宜春市| 吐鲁番市| 泸州市| 临夏县| 东乡县| 泰州市| 新闻| 楚雄市| 屯昌县| 长治市| 绵竹市| 卓尼县| 九台市| 方城县| 历史| 泰和县| 大埔县| 南郑县| 响水县| 合山市| 田阳县| 合阳县| 临汾市| 岢岚县| 杂多县| 凉山| 靖远县| 北川| 宁明县| 定远县| 长宁区| 区。| 承德县| 华坪县|