J2EE Dev : Enterprise JavaBean 3.0 – EJB 3.0


Phiên bản JavaBeans cho doanh nghiệp Enterprise JavaBeans (EJB) được giới thiệu để xây dựng các thành phần phân tán. Khi ra mắt, nó hứa hẹn giải quyết được mọi vấn đề và sự phức tạp trong CORBA. EJB trở thành trung tâm của J2EE sau khi chỉnh sửa vài lần và mở rộng thêm nhiều chức năng. Ngay từ đầu, hầu hết các nhà phát triển đều say mê EJB và dùng EJB trong ứng dụng của mình dù không cần thiết. “Đổ lỗi cho EJB” là xu hướng của nhiều nhà phát triển khi dự án của họ không hiệu quả mà lại sử dụng EJB.

Phát triển EJB chưa bao giờ đơn giản, và nó càng trở nên phức tạp hơn sau mỗi lần phát hành đặc tả EJB. EJB từng được so sánh với một chú voi vì tính phức tạp và nặng nề của nó. Nhiều nhà phát triển cảm thấy EJB giống như lớp siro đường phía trên chiếc bánh rán. Trong thời đại ăn kiêng, cộng đồng chuyên gia EJB không còn cách nào khác phải chuyển đổi EJB sang dạng ít béo, bằng cách đơn giản hóa quá trình phát triển của EJB. Cộng đồng chuyên gia EJB 3.0 đưa ra hình ảnh về mô hình rút gọn (lightweight model) trong hội nghị JavaOne 2004 khi họ thông báo ra mắt bản phác thảo đặc tả EJB 3.0 đầu tiên.

Đánh giá đầu tiên về mô hình EJB mới là nó có vẻ thú vị, và trong bài này chúng ta sẽ thảo luận cách thức mà EJB 3.0 thu hút được sự quan tâm của các nhà phát triển.


Dọn dẹp những gì không cần thiết

Hãy nhìn vào sự phức tạp trong mô hình EJB hiện tại trước khi chúng ta đi sâu vào phân tích cụ thể những gì EJB 3.0 mang lại.

* Mô hình EJB hiện tại yêu cầu tạo ra một số giao diện thành phần bổ sung và cài đặt những phương thức callback không cần thiết.
* Các giao diện thành phần đòi hỏi phải cài đặt EJBObject hoặc EJBLocalObject và phải xử lý nhiều exception không cần thiết.
* Deployment descriptor của EJB phức tạp và dễ xảy ra lỗi.
* CMP (container managed persistence) dựa trên mô hình EJB nên nó lại một lần nữa làm việc phát triển và quản lý trở nên phức tạp. Có một số tính năng cơ bản còn thiếu ví dụ như một cách thức chuẩn để định nghĩa khóa chính sử dụng sequence trong cơ sở dữ liệu (database sequence) và EJBQL còn rất giới hạn.
* Các thành phần EJB không có vẻ hướng đối tượng vì nó có các giới hạn trong sử dụng kế thừa và đa hình.
* Một nhược điểm chính của các EJB là không thể thử nghiệm một mudule EJB ở ngoài một EJB container, và dò lỗi một EJB trong container đúng là ác mộng với người thiết kế.
* Sự phức tạp trong lookup và gọi EJB. Bạn sẽ phải biết tất cả các chi tiết nhỏ nhất của JNDI chỉ để dùng một EJB trong ứng dụng của mình.

Đơn giản cái nhìn của người phát triển

Nếu đang phát triển một EJB có đặc tả mới nhất, bạn sẽ nhận ra rất khó khăn để phát triển một EJB đơn giản như HelloWorld EJB. Bạn cần ít nhất là hai giao diện, một lớp bean và một deployment descriptor. Phần lớn những người phát triển tự hỏi vì sao phải dùng những thứ đó. Các IDE như Oracle JDeveloper, Eclipse và XDoclet cho phép người phát triển ứng dụng thực hiện những công việc nhàm chán theo cách đơn giản hơn. Tuy vậy, người phát triển vẫn có nhiệm vụ biên dịch các lớp này, đóng gói mô tả phát triển trước khi triển khai EJB, nếu lựa chọn nó làm container.

EJB 3.0 cố giải quyết các phức tạp bằng cách:

* Loại bỏ các giao diện và mô tả phát triển, vì container tự tạo ra chúng dùng chú thích siêu dữ liệu (metadata annotations).
* Dùng các lớp Java chuẩn như các EJB và các business interface chuẩn cho EJB.

Chú thích siêu dữ liệu (Metadata Annotations)

EJB 3.0 phụ thuộc rất nhiều vào chú thích siêu dữ liệu. Chú thích siêu dữ liệu theo chuẩn JSR 175 và sẽ là một phần của J2SE 5.0. Chú thích là một dạng lập trình hướng thuộc tính, tương tự như XDoclet. Dù sao, không giống XDoclet phải tiền biên dịch, các chú thích được biên dịch vào các lớp (tùy theo giá trị mà @Retention được thiết lập) bởi bộ biên dịch Java vào thời gian biên dịch. Từ góc độ nhà phát triển, chú thích cũng giống các từ khóa bổ sung như “public” và có thể được dùng cho lớp, trường, phương thức, tham số, biến địa phương, hàm khởi tạo, các kiểu liệt kê và package. Có thể dùng chú thích trong mã nguồn Java bằng cách chỉ ra các thuộc tính dùng để sinh mã nguồn, lập tài liệu mã nguồn hoặc bằng cách cung cấp các dịch vụ đặc biệt như nâng cao độ bảo mật tầng nghiệp vụ hay logic nghiệp vụ đặc biệt trong thời gian chạy. Mục đích của J2EE 1.5 (5.0) là đơn giản hóa việc phát triển bằng cách sử dụng các chú thích và do vậy sẽ tạo ra một tập các chú thích. Các chú thích được đánh dấu bằng dấu @ như dưới đây:

@Author(“Debu Panda”)

@Bean

public class MySessionBean

Mục tiêu của EJB 3.0 là đơn giản hóa quá trình phát triển. Vì thế, nó dùng chú thích siêu dữ liệu để tạo những đối tượng mà thông thường phải thực hiện một cách thủ công chẳng hạn như giao diện, và dùng chú thích thay cho các deployment descriptor.

Sử dụng POJO và POJI

Theo các khái niệm truyền thống, JavaBeans và các interface thường liên quan đến đối tượng thuần Java – Plain Old Java Objects (POJO) tiếp đó là giao diện thuần Java – Plain Old Java Interfaces (POJI). Lớp và giao diện EJB giờ đây sẽ tương ứng thay thế cho POJO và POJI. Do vậy, sẽ loại bỏ được các đối tượng không cần thiết như giao diện home.

Người phát triển phải hoặc kế thừa một giao diện EJB (SessionBean, EntityBean hay MessageDrivenBean) trong gói javax.ejb package hoặc dùng chú thích trong lớp cài đặt bean. Có thể dùng một trong số các chú thích Stateless, Stateful, MessageDriven hoặc Entity cho lớp. Ví dụ, nếu định nghĩa một EJB phi trạng thái, như HelloWorld, ta định nghĩa EJB như sau:

@Remote

@Stateless public class HelloWorldBean {

public String sayHello(String s)

{ System.out.println(“Hello: “+s; }

}

Giao diện cho EJB cả remote và local đều không phải kế thừa EJBObject hay EJBLocalObject. Bạn phải hỗ trợ giao diện nghiệp vụ cho EJB và cài đặt giao diện đó trong lớp bean của mình, hoặc nó sẽ tự sinh trong quá trình triển khai. Giao diện là tùy chọn cho các bean thực thể, tuy nhiên vẫn phải có SessionBean và MessageDrivenBean. Nếu bạn không kế thừa một giao diện cho session bean, sẽ có một giao diện bean tự sinh. Loại giao diện tự sinh là local hay remote phụ thuộc vào chú thích bạn dùng trong lớp bean. Trong mã nguồn phía trên, rõ ràng là @Remote được dùng để sinh một giao diện remote cho bean HelloWorld.

Từ ví dụ trên có thể thấy người phát triển không cần phải thực hiện nhiều công việc nhàm chán như định nghĩa giao diện và cài đặt các phương thức callback.

Tên của giao diện tự sinh được tạo ra từ tên của lớp cài đặt bean. Các giao diện tự sinh cũng rất có ích cho người phát triển.

Tài liệu phác thảo đặc tả EJB 3.0 không nói rõ yêu cầu của phía khách cho tra cứu EJB, hay làm thế nào chúng ta điều khiển các giao diện cần dùng để kích hoạt EJB này? Tôi không khuyến khích dùng giao diện tự sinh vì các lý do sau:

Tên của giao diện tự sinh sẽ được tạo ra từ tên bean.

* Bạn sẽ không muốn để lộ một số phương thức của EJB trong giao diện, và giao diện tự sinh mặc định để lộ tất cả các phương thức này.
* Bạn cần giao diện phía khách để kích hoạt EJB.

Loại bỏ sự cần thiết của các phương thức gọi lại.

EJB 2.1 và các phiên phản trước yêu cầu kế thừa một số phương thức vòng đời như ejbPassivate, ejbActivate, ejbLoad, ejbStore, … cho tất cả các EJB kể cả khi bạn không cần chúng. Ví dụ, ejbPassivate là không cần thiết trong stateless session bean nhưng bạn vẫn phải kế thừa phương thức đó trong bean của mình. Vì EJB 3.0 bây giờ tương tự lớp Java chuẩn, nên kế thừa phương thức vòng đời (lifecycle methods) trở thành tùy chọn. Nếu bạn kế thừa bất kỳ phương thức callback nào trong EJB thì container sẽ kích hoạt phương thức đó.

Ngoại lệ duy nhất là phương thức ejbRemove trong stateful session bean, ở đó bạn có thể dùng chú thích Remove để ghi chú một phương thức nghiệp vụ của stateful session bean. Nếu bạn dùng chú thích này, nó sẽ gợi ý container loại bỏ instance của stateful session bean sau khi hoàn thành (bình thường hay bất thường) phương thức được ghi chú thích. Ví dụ, bạn có thể viết đoạn mã sau để loại bỏ instance của stateful session bean sau khi thực thi phương thức checkOut .

@Stateful public class Cart {

@Remove public void checkOut() {

}

}

So sánh annotation và deployment descriptor:

Như chúng ta đã thảo luận ở trên deployment descriptor sẽ không còn cần thiết cho các EJB, thay vào đó là các annotation (ghi chú). Giá trị mặc định cho từng thuộc tính trong deployment descriptor sẽ được chọn và người phát triển không cần phải quy định các thuộc tính này trừ phi họ muốn một giá trị khác với giá trị mặc định. Chúng có thể được quy định bằng cách dùng ghi chú trong chính lớp bean đó. Đặc tả EJB 3.0 định nghĩa một tập các ghi chú siêu dữ liệu để người phát triển dùng như loại bean, loại giao diện, các tham chiếu tài nguyên, các thuộc tính giao dịch, bảo mật,… Ví dụ, nếu muốn tham chiếu tài nguyên cho một EJB cụ thể, ta định nghĩa như sau:

@Resource(name=”jdbc/OracleDS”, resourceType=”javax.sql.DataSource”)

Các nhà cung cấp J2EE như Oracle, BEA, IBM sẽ thêm ghi chú cho thuộc tính trong deployment descriptor của riêng họ, và người phát triển sẽ dùng chúng chứ không phải các deployment descriptor. Điều này có vẻ rất hấp dẫn với người phát triển vì họ không phải dùng mô tả XML khó chịu, đáng ghét nữa. Nhưng điều này cũng có thể mang lại một vài vấn đề, chúng ta sẽ cẩn thận trước khi sử dụng chú thích.

* Nó chống lại mục đích về tính khả chuyển của ứng dụng, vì nếu EJB dùng mô tả triển khai của một nhà cung cấp cụ thể thì khi muốn thay đổi phải biên dịch và đóng gói lại các EJB.
* Deployment descriptor cung cấp cái nhìn chính tắc về các module EJB cho trình tích hợp/triển khai (ejb-jar) và không cần phải xem xét từng EJB riêng lẻ. Họ điều chỉnh các mobule này tùy theo yêu cầu của từng triển khai. Vì thế, nếu mô tả chỉ sẵn sàng, hoặc được sinh ra sau khi hoàn thành triển khai thì quả là ác mộng với họ.
* Deployment descriptor được các công cụ sử dụng để xác định các EJBs trong một module EJB, và nó rất hữu dụng khi bạn muốn chuyển từ một container này sang container khác. Đặc tả EJB 3.0 cũng đưa ra một cách để ghi đè các chú thích trong mô tả triển khai. Tuy thế, chi tiết về cách ghi đè chú thích chưa có trong đặc tả.

Rõ ràng thoát khỏi deployment descriptor sẽ làm người phát triển dễ thở hơn, nhưng nó cũng có thể trở thành ác mộng về quản lý nếu không được dùng cẩn thận.

Đơn giản hóa quản lý CMP (Container Managed Persistence)

CMP bean được thay đổi cơ bản trong EJB 3.0 để phù hợp với người phát triển. Các persistence framework như OracleAS TopLink, và mã nguồn mở Hibernate đã trở nên thân thiết để phát triển persistence framework cho các ứng dụng J2EE, không giống như entity bean có bản chất phức tạp và nặng nề. EJB 3.0 tiếp nhận mô hình persistence gọn nhẹ như TopLink and Hibernate để đơn giản quản lý CMP – điều này xem ra có vẻ phù hợp với người phát triển.

Entit bean là được coi như là các POJO và sẽ không cần các giao diện thành phần (component interface) cho entity bean. Các entity bean giờ đây sẽ giống như đối tượng thuần túy, cũng sẽ hỗ trợ kế thừa và đa hình.

Dưới đây là mã nguồn của một bean thực thể

@Entity public class Employee{

private Long empNo;

private String empName;

private Address address;

private Hashmap projects = new Hashmap();

private Double salary;

@Id(generate=SEQUENCE) public Long getEmpNo() {

return empNo;

}

protected void setEmpNo(Long empNo) {

this.empNo = empNo;

}

public String getEmpName() {

return EmpName;

}

public void setEmpName(String EmpName){

this.EmpName = EmpName;

}

@Dependent public Address getAddress() {

return address;

}

public void setAddress(Address address) {

this.address = address;

}

public Set getProjects() {

return projects;

}

public void setProjects(Set projects) {

this.projects = projects;

}

public Double getSalary() {

return salary;

}

public void setSalary(Double salary) {

this.salary = salary;

}

….

}

Nhìn vào mã nguồn, ta thấy lớp bean là một lớp cụ thể, chứ không phải là lớp trừu tượng như entity bean hiện tại.

Có một số cải tiến về khả năng truy vấn trong EJB QL và hỗ trợ các truy vấn SQL trên các entity bean. Một EntityManager API mới tương tự Hibernate và một phiên bản rút gọn của TopLink’ Session API được đề xuất để thực hiện thao tác với các entity bean chẳng hạn như tạo mới, xóa bỏ hay tìm kiếm.

Đơn giản hóa cái nhìn của client đối với EJB

Việc sử dụng các EJB để thực hiện các tác vụ như lookup và gọi là rất phức tạp, thậm chí ngay cả khi EJB được cấp phát trong ứng dụng. Đặc tả J2EE 1.4 và EJB 3.0 hiện đang tiến hành đơn giản hóa cái nhìn EJB từ phía client.

Nếu bạn muốn sử dụng một EJB, hiện tại, bạn phải định nghĩa ejb-ref hoặc ejb-local-ref trong deployment descriptor, lookup EJB và sau đó là triệu gọi. Nếu chúng ta muốn triệu gọi EJB HelloWorld của mình, dưới đây là cách thức đơn giản nhất bạn có thể triệu gọi một EJB với cách cài đặt hiện tại.

Đầu tiên là định nghĩa các tham chiếu EJB trong deployment descriptor như sau:

<ejb-ref>

<ejb-ref-name>HelloWorldEJB</ejb-ref-name>

<ejb-ref-type>Session</ejb-ref-type>

<home>hello.HelloWorldHome</home>

<remote> hello.HelloWorld</remote>

</ejb-ref>

Sau đó, lookup EJB như dưới đây. Bạn phải kiểm soát các exception một cách tường minh cho công việc lookup tạo mới một instance của bean.

try

{

Context context = new InitialContext();

HelloWorldHome helloHome =

(HelloWorld)PortableRemoteObject.narrow(context.lookup

(“java:comp/env/ejb/HelloWorldEJB”), HelloWorldHome.class);

HelloWorld hello = helloHome.create();

….

}

catch(RemoteException e)

{

System.err.println(“System/communication error: ” + e.getMessage());

}

catch(NamingException e)

{

System.err.println(“Communication error: ” + e.getMessage());

}

catch(CreateException e)

{

System.err.println(“Error creating EJB instance: ” + e.getMessage());

}

Để thay thế cho các biến môi trường, EJB 3.0 đề xuất một phương pháp là sử dụng setter injection để lookup và triệu gọi các EJB.

Dưới đây là cách thức HelloWorldEJB có thể được lookup trong một EJB khác bằng cách sử dụng setter injection.

@Inject private void setSessionContext(SessionContext ctx)

{

this.ctx = ctx

}

myHello = (HelloWorld)ctx.lookup(“java:comp/env/ejb/HelloWorldEJB”);

Nếu bạn quan sát mã nguồn trên một cách cẩn thận thì phương thức setSessionContext được ký hiệu bằng @Inject để chỉ ra rằng dependency injection được sử dụng cho phương thức này. Các phương thức được chèn vào này sẽ được triệu gọi bởi container để thiết lập EJBContext trước khi bất kỳ phương thức nghiệp vụ (business method) nào được gọi trên EJB đó.

Một ví dụ trực tiếp khác để chèn session bean HelloWorld là sử dụng khai báo @EJB public HelloWorld myHello và như vậy sẽ khiến myHello được thêm vào với một instance của bean HelloWorld.

Bạn có thể sử dụng dependency injection để lookup bất kỳ kiểu tham chiếu môi trường và tài nguyên nào như DataSource, JMS, Mail, Web Service…

Khả năng kiểm tra và tính dễ dùng bên ngoài container

Một mối quan tâm lớn đối với các nhà phát triển EJB hiện tại không chỉ là việc phát triển các EJB rất phức tạp, mà quá trình kiểm tra (test) cũng thực sự là cơn ác mộng. Một EJB container là thành phần không thể thiếu để phát triển và kiểm tra các EJB, và các nhà phát triển phải quen với nền tảng triển khai cuối cùng để thực thi việc kiểm tra. Đây có lẽ không phải là vấn đề lớn đối với nhiều nhà phát triển ứng dụng doanh nghiệp, nhưng lại là một vấn đề với các nhà cung cấp dịch vụ độc lập, những người làm việc trên nền tảng hỗ trợ nhiều nhà cung cấp và họ phải bảo trì nhiều môi trường để thực hiện việc kiểm tra cho các EJB của mình. Đặc tả EJB 3.0 hứa hẹn đem lại khả năng kiểm tra bên ngoài container, nhưng hiện tại tính năng này vẫn còn thiếu trong bản phác thảo của đặc tả.

Kết luận

Mặc dù vẫn còn thiếu nhiều thông tin về việc đóng gói, lắp ráp và chi tiết về các API, nhưng các đề xuất trong bản phác thảo đặc tả EJB 3.0 có vẻ như rất hứa hẹn đối với các nhà phát triển ứng dụng Java cho doanh nghiệp. Những tính năng mới sẽ giúp các nhà phát triển loại bỏ sự phức tạp bằng cách chuyển trái bóng sang các nhà cung cấp container. Vấn đề sẽ là các nhà cung cấp container sẽ cài đặt thế nào nhằm biến EJB 3.0 trở thành một lựa chọn hấp dẫn để phát triển các ứng dụng doanh nghiệp.

Tham khảo:

* EJB 3.0 Draft Specification (http://java.sun.com/products/ejb/docs.html)

Theo blog my.opera.com/Alibobo

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s