<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    weidagang2046的專欄

    物格而后知致
    隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
    數據加載中……

    EJB 3.0+Aspect實現聲明性編程初步

    提要 本文將與你一同探討怎樣把注解和方面的威力聯合起來,以與EJB 3.0兼容的方式為企業實現提供聲明性服務,而在同時仍然提供容器的獨立性。

      一、 引言

      在我們共同尋求進一步提高軟件開發生產性能的方法的過程中,我們-作為Java社團成員-一般都轉向J2EE來提供針對企業開發中更具挑戰性的技術問題如分布式事務管理、并發性和對象分布等的解決方案。其背后的指導思想-這些復雜的企業服務能被應用程序服務器供應商所實現并能為商業開發者所平衡-的確是一種很好的思想。J2EE,具體地說是EJB,已成功地提供了一個平臺-在其上構建企業Java應用程序。

      這其中部分的成功是由于能夠進行聲明性編程-一種程序開發方式-用這種方式,你可以聲明基礎結構服務而不是用商業邏輯明確地編碼從而使代碼散布于各處。EJB已經證明了這種編程方式的價值-通過允許企業問題例如事務和安全被用一種發布描述符所聲明并為容器所處理。

      然而,在過去的歲月中,越來越多的開發者認識到EJB在團隊的生產效率方面給它自己帶來新的大量的挑戰-每個EJB必須伴隨多個接口,以一種發布描述符描述,經由JNDI被存取,等等。而在容器外EJB上進行單元測試也帶來另外的困難,如今EJB已不再把重點放在單純的面向對象開發上。

      請注意,為閱讀本文您需具備如下工具:

      ·Java 2 SDK 1.5

      ·Maven 2.0 Beta 2

      EJB 3.0的目標在于從以下幾個方面使企業開發更為容易:

      ·通過引入元數據注解來實現聲明性請求企業服務

      ·經由注解實現依賴性/資源注入

      ·實現企業beans與EJB特定接口的解耦

      ·經由輕量級的對象關系映射實現持續性存儲的簡化

      這對于EJB開發者來說尤如一股春風-一直以來,他們竭力地從事開發、測試和維護EJB。利用EJB 3.0寫一個企業bean現在變得很容易,就如用特定的注解創建一個POJO(傳統的Java對象)以把它標明為一個EJB并請求企業服務。下面是一個來自于EJB 3.0 Public Draft中EJB的例子:

    @Stateful
    public class CartBean implements ShoppingCart
    {
    private float total;
    private Vector productCodes;
    public int someShoppingMethod(){...};
    ...
    }

      EJB 3.0聲明中實質上指明開發者需要的不是一重量級的、"一次發布滿足所有"的解決方案,而是一個輕量級的、容易使用的解決方案-為開發者提供一定范圍的企業服務。為此,EJB 3.0所提供的最重要的方法之一就是實現企業beans與EJB API的解耦。并且,此解決方案還帶來令人感興趣的衍生-EJB現在不僅能夠運行在不同的EJB容器上,而且還能運行于任何應用程序框架內部-這些框架必須能夠識別EJB 3.0(JSR 220)和用于聲明企業服務的普通注解(JSR 250)。

      本文沒有提供關于聲明性編程、EJBs、方面或注解的深度探索。相反,而只是分析一下這些技術之間的相互關系并討論如何把它們用一種新的方式結合起來以簡化應用程序開發。

      在本文中,你將會學習到如何編寫一個EJB 3.0兼容的bean并且通過創建幾個簡單的方面使其具有聲明性事務管理、安全和資源注入等功能。我希望您能從這個練習中得到以下的受益:

      ·學習方面的三個實際應用(依賴性注入、安全和事務)。

      ·熟悉EJB 3.0及其背后的思想。

      ·認識到怎樣實現EJB與特定API的解耦以允許EJB 3.0兼容的服務能夠以輕量級實現而不是僅由EJB來提供。

      二、 實例應用程序-航班訂購

      在整個后面的討論中,你將學習到一個航班訂購系統的實現-它使用方面和注解來實現依賴性注入、安全和事務管理。該應用程序僅執行兩項功能:它允許用戶搜索航班(圖1),然后訂購一次旅行(圖2)。這兩個操作都將被進行安全處理以僅允許能被識別的用戶來執行它們。另外,既然"訂購旅行"操作包含訂購兩個航班(外出和返回航班),那么需要把該操作創建為事務性的-如,兩個訂購將作為一個工作單元要么都成功要么都失敗。


    圖1.航班查詢:首先,用戶查找滿足他們的指定標準的航班。

    圖2.航班訂購:接下來,用戶訂購一個外出航班和一個返回航班。兩個訂購要么都成功要么都失敗。

      這個簡單的Web應用程序包含幾個servlet、一個服務外觀和一個DAO層(見圖3)。

      資源配置、安全性和事務管理等橫切關注點將由方面(用AspectJ 1.5 M3實現)所提供以實現在Java 5注解中所聲明的注入行為。


    圖3.航班訂購系統架構:這個航班訂購系統包括三個主要組成組件-它們聯合起來共同完成用戶請求。

    三、 資源注入

      EJB 3.0草案聲明中允許資源經由@Resource注解來聲明(這一決定定義在草案普通注解聲明中)并且被容器注入進你的EJB。依賴性注入是一項技術-使用這種技術,一個對象外部的實體而不是顯式地為該對象所創建的實體能夠提供(注入)一個對象的依賴性。它有時被描述為好萊塢原則-這開玩笑似地意味著"不要給我們打電話,我們會給你打電話的"。

      以TravelAgencyServiceImpl類為例-這個類為了持續性存儲一些數據需要找到一個IFlightDAO接口的實現。傳統地,這是經由一個工廠、singleton、服務定位器或一些另外的定制解決方案來實現的。其中,一個可能的解決方案看上去如下所示:

    public class TravelAgencyServiceImpl implements ITravelAgencyService
    {
     public IFlightDAO flightDAO;
     public TravelAgencyServiceImpl()
     { flightDAO = FlightDAOFactory.getInstance().getFlightDAO(); }
     public void bookTrip(long outboundFlightID, long returnFlightID, int seats)
     throws InsufficientSeatsException
     {
      reserveSeats(outboundFlightID, seats);
      reserveSeats(returnFlightID, seats);
     }
    }

      你已看到,這個實現包含創建一個特定的工廠類-它很可能讀取存儲在某處的配置信息以了解要創建IFlightDAO的實現方式。如果不是讓服務顯式地創建它的由容器所注入的依賴性,那么配置細節和對象創建將被代理到容器上。這允許一個應用程序中的組件能夠被容易地連接到一起-用不同的配置并且消除大量老式的singleton和工廠代碼。

      該類的一個實現-它依賴于一個用JSR 250資源注解所聲明的IFlightDAO的實現-可能看上去如下所示:

    public class TravelAgencyServiceImpl implements ITravelAgencyService
    {
     @Resource(name = "flightDAO")
     public IFlightDAO flightDAO;
     public void bookTrip(long outboundFlightID, long returnFlightID, int seats)
     throws InsufficientSeatsException
     {
      reserveSeats(outboundFlightID, seats);
      reserveSeats(returnFlightID, seats);
     }
    }

      在這種情況下,容器將把一個命名為"flightDAO"的資源的正確實現提供給服務類。但是,如果你現在就想利用資源注入,而不是等待EJB 3.0發行版,又該如何呢?好,你可以采用一種輕量級的容器-它能夠提供例如Spring或Pico Container的依賴性注入。然而,當前我還不了解存在一個輕量級的容器-它能夠使用JSR 250資源注解以指定注入要求(盡管我非常盼望在這一方面出現一些)。

      一種解決方案是使用方面來實現依賴性注入。如果你為此使用@Resource注解,那么你的實現將與EJB 3.0方式一致并且向前兼容EJB 3.0實現-而實現這并不是很困難的事情。下列列表顯示用AspectJ創建的一個方面-它注入用@Resource注解所注解的字段:

    @Aspect
    public class InjectionAspect
    {
     private DependencyManager manager = new DependencyManager();
     @Before("get(@Resource * *.*)")
     public void beforeFieldAccesses(JoinPoint thisJoinPoint)
     throws IllegalArgumentException, IllegalAccessException
     {
      FieldSignature signature = (FieldSignature) thisJoinPoint.getSignature();
      Resource injectAnnotation = signature.getField().getAnnotation(Resource.class);
      Object dependency = manager.resolveDependency(signature.getFieldType(),injectAnnotation.name());
      signature.getField().set(thisJoinPoint.getThis(), dependency);
     }
    }

      這個簡單方面所做的全部是,從一個屬性文件(這個邏輯被封裝在DependencyManager對象中)查詢實現類并且在存取字段之前把它注入到用@Resource注解所注解的字段中。顯然,這種實現不是完整的,但是它確實說明了你可以怎樣以一種JSR 250兼容方式且不需采用EJB來提供資源注入。
    四、 安全性

      除了資源注入外,JSR 250和EJB 3.0還提供經由注解的元數據安全表示。javax.annotation.security包定義了五個注解-RunAs,RolesAllowed,PermitAll,DenyAll和RolesReferenced-所有這些都能應用到方法上來定義安全要求。例如,如果你想要聲明上面列出的bookFlight方法僅能為具有"user"角色的調用者所執行,那么你可以用如下的安全約束來注解這個方法:

    public class TravelAgencyServiceImpl implements ITravelAgencyService
    {
     @Resource(name = "flightDAO")
     public IFlightDAO flightDAO;
     @RolesAllowed("user")
     public void bookTrip(long outboundFlightID, long returnFlightID, int seats)
     throws InsufficientSeatsException
     {
      reserveSeats(outboundFlightID, seats);
      reserveSeats(returnFlightID, seats);
     }
    }

      這個注解將指出由容器來負責保證只有指定角色的調用者才能執行這個方法。因此現在我將展示另一個簡單的方面-它將進一步加強在該應用程序上的安全約束:

    @Aspect
    public class SecurityAspect
    {
     @Around("execution(@javax.annotation.security.RolesAllowed * *.*(..))")
     public Object aroundSecuredMethods(ProceedingJoinPoint thisJoinPoint)
     throws Throwable
     {
      boolean callerAuthorized = false;
      RolesAllowed rolesAllowed = rolesAllowedForJoinPoint(thisJoinPoint);
      for (String role : rolesAllowed.value())
      {
       if (callerInRole(role))
       { callerAuthorized = true; }
      }
      if (callerAuthorized)
      { return thisJoinPoint.proceed(); }
      else
      {
       throw new RuntimeException("Caller not authorized to perform specified function");
      }
     }
     private RolesAllowed rolesAllowedForJoinPoint(ProceedingJoinPoint thisJoinPoint)
     {
      MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
      Method targetMethod = methodSignature.getMethod();
      return targetMethod.getAnnotation(RolesAllowed.class);
     }
     private boolean callerInRole(String role)
     { ... }
    }

      這個方面包含了所有方法的執行-通過核實該調用者是在注解中所指定的角色之一,用@RolesAllowed注解來注解并且保證調用者被授權調用該方法。當然你還能代之以任何你喜歡的算法來授權用戶并且檢索他/她的角色,例如JAAS或一個定制的解決方案。在本示例程序中,為方便起見,我選擇代理到servlet容器。
    五、 事務

      事務成為企業開發的一個重要部分-因為它們有助于在一個并發的環境中的數據集成。從一個高層次上看,事務可以通過多種或者是完整的或者是都不完整的操作來保證這一點。

      不象針對資源注入和安全的注解,針對事務的注解是特定于EJB 3.0的并且沒有在JSR 250普通注解中定義。EJB 3.0定義了兩個與事務相聯系的注解:TransactionManagement和TransactionAttribute。該TransactionManager注解指定事務是由容器所管理還是為bean所管理的。在EJB 3中,如果這個注解沒被指定,那么將使用容器所管理的事務。TransactionAttribute注解用于指定方法的事務傳播級別。有效值-包括強制的、要求的、要求新的、支持的、不支持的和從不支持的-用來定義是否要求一個已有事務或啟動一個新的事務,等等。

      因為bookFlight操作包含兩步-訂購一個外出航班和一個返回航班,所以,通過把它包裝成一個事務,你能保證這項操作的一致性。通過使用EJB 3.0事務注解,這將看上去如下所示:

    public class TravelAgencyServiceImpl implements ITravelAgencyService
    {
     @Resource(name = "flightDAO")
     public IFlightDAO flightDAO;
     @RolesAllowed("user")
     @TransactionAttribute(TransactionAttributeType.REQUIRED)
     public void bookTrip(long outboundFlightID, long returnFlightID, int seats)
     throws InsufficientSeatsException
     {
      reserveSeats(outboundFlightID, seats);
      reserveSeats(returnFlightID, seats);
     }
    }

      并且你可以應用一個簡單的方面來自動地界定事務邊界:

    @Aspect
    public class TransactionAspect
    {
     @Pointcut("execution(@javax.ejb.TransactionAttribute * *.*(..))")
     public void transactionalMethods(){}
     @Before("transactionalMethods()")
     public void beforeTransactionalMethods()
     { HibernateUtil.beginTransaction(); }
     @AfterReturning("transactionalMethods()")
     public void afterReturningTransactionalMethods()
     { HibernateUtil.commitTransaction(); }
     @AfterThrowing("transactionalMethods()")
     public void afterThrowingTransactionalMethods()
     { HibernateUtil.rollbackTransaction(); }
    }

      這個實現基于這樣的假設-Hibernate和無所不在的線程本地模式被用于管理Hibernate會話和事務對象;但是,任何其它適當的實現,例如基于JTA的實現,都能被代替使用。

      六、 小結

      通過使用EJB 3.0和JSR 250注解集,本文已經展示了例如資源管理、安全和事務等橫切關注點是怎樣被實現為方面的。當然,還有許多內容我們需進一步學習。首先要學的就是通過使用AspectJ的實現這些示例方面為模塊化橫切關注點所提供的藍圖。其次,我們已經看到了在如今正浮出水面的EJB 3.0聲明背后的一些新思想和新概念。最后,我們還以戲劇性的方式看到了從EJB API中解耦我們的商業對象所必須要提供的自由。在這一點上,所有你想使TravelAgencyServiceImpl成為一個無狀態會話要做的僅是添加一條最后的注解:

    @Stateful
    public class TravelAgencyServiceImpl implements ITravelAgencyService
    { ... }

      最后,我非常希望這種自由地提供企業服務的方式會帶來框架/容器工業界的競爭和革新。

    from: http://www.7dspace.com/doc/21/2005-11-21/2005112107135764791_1.htm

    posted on 2005-12-24 21:15 weidagang2046 閱讀(176) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 亚洲精品国产自在久久 | 亚洲成人福利在线观看| 中文字幕视频在线免费观看 | 亚洲色成人中文字幕网站| 人人爽人人爽人人片A免费| www.亚洲精品| www成人免费观看网站| 中文字幕在亚洲第一在线| 久久国产一片免费观看| 国产AV无码专区亚洲Av| 国产精品免费无遮挡无码永久视频 | 亚洲精品亚洲人成在线观看下载 | 亚洲kkk4444在线观看| 成人au免费视频影院| 亚洲精品蜜夜内射| 四虎亚洲国产成人久久精品| 国产高清对白在线观看免费91 | 在线看片免费不卡人成视频| 亚洲色大成网站www久久九| 国产精品免费播放| 中文字幕高清免费不卡视频| 亚洲日本一区二区三区| 久久久久久久免费视频| 国产AV无码专区亚洲AV麻豆丫| 亚洲国产成人久久笫一页| a级毛片免费高清毛片视频| 亚洲另类自拍丝袜第1页| 国产午夜影视大全免费观看| 国产裸体美女永久免费无遮挡 | 日本免费的一级v一片| www.av在线免费观看| 亚洲∧v久久久无码精品| A级毛片内射免费视频| eeuss免费影院| 亚洲国产精品成人综合久久久| 国产精品无码一区二区三区免费| 中文字幕不卡免费视频| 亚洲人成综合在线播放| 精品国产人成亚洲区| 成年在线观看网站免费| 巨胸喷奶水视频www免费视频|