Dependency Injection với Abstract Factory


Bài viết này, chúng ta cùng tìm hiểu ưu và nhược điểm của Dependency Injection (DI - “tiêm ” phụ thuộc) với một số cách khác nhau dùng Abstract Factory design pattern. Đặt trong ngữ cảnh của một số vấn đề như: Tạo stateful objects với tham số, điều khiển kiểm tra exceptions khi tạo object, và gắn động các objects. Mà các IoC frameworks, như Spring IoC container, PicoContainer và Guice, không đưa ra giải pháp tốt nhất cho các trường hợp này.

Abstract Factory Design Pattern cho Dependency Injection


GoF* Abstract Factory design pattern được tóm gọn theo 2 bước:
Một factory interface thay thế cho một class abstract factory (Optional),
Mọi factory method chịu trách nhiệm tạo một object và tiêm phụ thuộc vào nó.
Xét ví dụ đơn giản sau:

ComponentA phụ thuộc vào ComponentB. Để có thể unit-testing class ComponentAImpl, hiện thực của interface ComponentB phải tiêm vào ComponentAImpl. Đoạn code sau minh hoạ cách dùng Abstract Factory design pattern để tiêm phụ thuộc.

//Abstract Factory for Dependency Injection
//Factory interface
public interface Module1ServiceFactory {

ComponentA getComponentA();

ComponentB getComponentB();
}

//Concrete factory
public class Module1ServiceFactoryImpl implements Module1ServiceFactory {

private ComponentA componentA;
private ComponentB componentB;
private Module1Servicefactory instance;

private Module1ServicefactoryImpl() {
}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServicefactoryImpl();
componentA = new ComponentAImpl();
componentB = new ComponentBImpl();
componentA.setComponentB(componentB);
}
return instance;
}

public ComponentA getComponentA() {
return componentA;
}

public ComponentB getComponentB() {
return componentB;
}
}

//Client
public class Client {

public static void main(String[] args) {
Module1ServiceFactory m1sf =
Module1ServicefactoryImpl.getInstance();
ComponentA componentA = m1sf.getComponentA();
componentA.operationA1();
}
}


Lazy-instantiation


Lazy-instantiation có thể thực hiện bàng cách thay đổi phương thức để có thể xem như objects đã được tạo và chỉ lấy ra khi cần. Để làm điều này, getComponentA() có thể chỉnh lại như sau:

public synchronized ComponentA getComponentA() { if (null == componentA) { componentA = new ComponentAImpl(); } return componentA; }

Dĩ nhiên Module1ServiceFactoryImpl.getInstance() phải được sửa lại không tạo objects.
Ta có thể thêm parameter cho Module1ServiceFactoryImpl .getInstance() để cho biết nó có cần tạo objects hay không.

Non-Singleton Scope


Đoạn code trên sẽ tạo singleton objects. Nếu một object mới chỉ cần khi gọi phương thức getComponentA() và getComponentB(), thì ta sửa lại như sau:


//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;

private Module1ServiceFactoryImpl() {}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
}

return instance;
}

public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB();
componentA.setComponentB(componentB);
return componentA;
}


public ComponentB getComponentB() {
return new ComponentBImpl();
}
}


Ta có thể tiêm một singleton object vào một non-singleton object. Ví dụ, nếu ComponentB là một singleton, và ComponentA là một non-singleton, ta có thể làm như sau:

//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;
private ComponentB componentB;

private Module1ServicefactoryImpl() {}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
componentB = new ComponentBImpl();
}

return instance;
}

public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
componentA.setComponentB(componentB);
return componentA;
}

public ComponentB getComponentB() {
return componentB;
}
}

Ngược lại ta cũng có thể tiêm một non-singleton object cho một singleton, tuy nhiên trường hợp này rất ít gặp.

Tạo Local Stateful Objects với tham số cho Singletons


Đây là vấn đề đặt trưng cho tất cả các IoC frameworks. Được minh hoạ bằng phương thức cho ComponentA singleton:

public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = new ComponentCImpl(s, i);
//do something else.
}

Ở đây, ComponentAImpl dùng ComponentC. Hiển nhiên là chúng ta cần tiêm cho nó một hiện thực của ComponentC là ComponentCImpl. Tuy nhiên, chúng ta không thể tạo biến componentC khi nó là một stateful object với trạng thái chỉ dùng được trên client và sẽ không thể dùng trong clients khác thông qua threads. Vậy, nó không thể tiêm dùng setter hay constructor.
Có 2 giải pháp để giải quyết vấn đề này dùng Abstract Factory pattern. In both schemes, chúng ta cần thay đổi Module1ServiceFactory và thêm một tham số cho factory method:

ComponentC getComponentC(String s, int i);

Và hiện thực phương thức này trong Module1ServiceFactoryImpl:

public ComponentC getComponentC(String s, int i) {
return new ComponentCImpl(s, i);
}

Giải pháp thứ nhất là tiêm factory object vào class có local stateful objects cần:

private Module1ServiceFactory factory;
public void setModule1ServiceFactory(Module1ServiceFactory factory) {
this.factory = factory;
}

ComponentAImpl.operationA2() trở thành:

public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = factory.getComponentC(s, i);
//do something else.
}

Bất lợi của cách này là ComponentAImpl phụ thuộc vào Module1ServiceFactory và chúng ta cần cung cấp một mock hiện thực Module1ServiceFactory để unit-test ComponentAImpl. Mặc dù có nhược điểm như vậy, nhưng tiêm factory object vào một class dùng trong việc tạo local stateful objects là đơn giản nhất. Và được dùng nhiều nhất trong J2EE technology. Ví dụ, trong JPA (Java Persistence API), một entity manager factory có thể tiêm vào code, và một application-managed entity manager được tạo từ entity manager factory.
Cách thứ 2 để tạo local stateful objects là chuyển phương thức sang abstract class, có thể dùng trong unit-tested, và có objects phụ thuộc cụ thể trong subclass.

public abstract class AbstractComponentA implements ComponentA {
public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = getComponentC(s, i);
//do something else.
}

public abstract ComponentC getComponentC(String s, int i) ;

}

public class ComponentAImpl extends AbstractComponentA {
public ComponentC getComponentC(String s, int i) {
return new ComponentCimpl(s, i);
}

}

Cách này được dùng nhiều trong Method Injection của Springframework chỉ hỗ trợ trường hợp không cần tham số khi tạo stateful objects. Unit-testing code không cần hiện thực mock factory. Tuy nhiên, đó là một giải pháp nguy hiểm. Giả sử chúng ta có 10 local stateful objects trong, chúng ta cần 10 abstract methods cho mục đích dùng unit-testing. Đúng là có thể dùng unit-testing và dùng rất đơn giản – at the expense of cluttered application code.
Springframework đưa ra phương thức có thể giải quyết vấn đề này dùng Java reflection. Nhưng nó là một cách rất phức tạp và không phù hợp cho một application bình thường.

Kiểm tra Exceptions Thrown khi tạo Object


Đây là vấn đề mà một IoC container thường làm không tốt. Nếu kiểm tra exceptions được tung ra trong quá trình tạo object, ứng dụng có thể muốn bắt và thu lại. Lấy ví dụ một web service client, nếu web service chưa được tạo khi client gọi, client có thể bắt exception mà nó tung ra, hiện messages phù hợp và đề nghị thực hiện lại. Trường hợp này khó cho IoC containers để tung ra lổi đã được khai báo trong ứng dụng. Factories có thể dể dàng điều khiển trạng thái – chúng ta có thể đơn giản khai báo exceptions cần kiểm tra và tung lổi trong factory methods và cho phép application code điều khiển và thu lại ngay tại đó.

Gắn linh động


Là trường hợp có nhiều hiện thực khác nhau của cùng một interface cần tiêm vào một object khác nhau. Một ví dụ hay là Strategy design pattern. Một tham số có thể dùng để cho biết class cụ thể nào cần được tiêm. Trường hợp này khó hiện thực theo kiểu tiêm phụ thuộc trong file XML hỗ trỡ trong IoC containers, chỉ đơn giản cung cấp một cách để lắp các objects theo cách tĩnh. Lập trình IoC containers có thể cho phép giải quyết cấn đề phụ thuộc động. Tuy nhiên, tiêm phụ thuộc bằng tay với Abstract Factory cung cấp một cách đơn giản nhất và và là một giải pháp đơn giản nhất trong trường hợp này, như ta thấy trong ví dụ sau:

//Concrete factory
public class Module1ServiceFactoryImpl {
...

public ComponentA getComponentA(int strategy) {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB(strategy);
componentA.setComponentB(componentB);
return componentA;
}


public ComponentB getComponentB(int strategy) {
switch(strategy) {
case STRATEGYA:
return new StrategyA();
case STRATEGYB:
return new StrategyB();
default:
return null;
}
}
}

Trong ví dụ này, cả StrategyA và StrategyB đều là hiện thực của interface ComponentB.

Tổng kết


Các trường hợp đã được đưa ra cho vấn đề tiêm phụ thuộc với Abstract Factory design pattern bao gồm tạo local stateful objects từ tham số động, điều khiển kiểm tra exceptions trong quá trình tạo object, và gắn linh động. Bên cạnh đó, vấn đề là một cách tốt nhất để so sánh với các IoC containers từ dùng Java code và gắn cứng (XML). Bất lợi ở chổ developers cần viết nhiều code hơn để bắt đầu. Một hạn chế khác là hiện thực của factory code thay đổi đáng kể nếu chúng ta đổi giựã lazy-initialization và eager-initialization hay từ singletons đến non-singletons. Tuy nhiên, nó có thể chứng tỏ rằng it is rare that we need to make these kinds of changes.
Vấn đề chính là cho phép unit-testing là lập trình dùng interfaces để classes không dựa vào classes cụ thể trong ứng dụng. Để mock objects có thể tiêm vào một class khi test và thi hành tất cả sự phụ thuộc.
Phụ thuộc đã được giải quyết, theo một cách nào đó trong ứng dụng. Một ý tưởng thường thấy phía sau tất cả IoC containers và các giải pháp cho DI là phụ thuộc được giải quyết theo cách dể hình dung – XML configuration files (Spring IoC), đặc biệt Java classes (Google Guice), hay factory classes cụ thể. Trong trường hợp này, chúng ta tránh sự lan rộng của phụ thuộc thông qua code ứng dụng và một ít class cụ thể có thể dễ dàng. Mock objects có thể dùng để unit-testing.
Và cuối cùng, với IoC containers, chúng ta loại trừ phụ thuộc vào classes cụ thể và có thể tạo unit-testing, theo cách mà họ cung cấp – thông qua các thirty-party APIs hay cấu hình trên file XML. Khi không có một chuẩn cho IoC containers và mổi framework cung cấp các tính năng và chức năng khác nhau chung quanh vấn đề tiêm phụ thuộc, thì ta khó mà thay thế một IoC framework để dùng một cái khác.

*GoF: Gang of Four. Người ta thường gọi quyển sách Design Patterns: Elements of Reusable Object-Oriented Software với cái tên này vì có 4 tác giả viết nó.

Dịch từ TheServerSide

Đọc tiếp >>

Cao Trong Hien

,

10 Blogs hữu ích cho Web Developer


Làm thế nào để biết được thế giới này đang có những gì, và cần gì?

Làm sao để lựa chọn một công nghệ web cho dự án mà mình đang tiến hành?

Dùng media player nào? Flex hay Silverlight?

Dùng ngôn ngữ nào? Java, .Net hay PHP?

Và còn rất nhiều câu hỏi mà để tìm ra câu trả lời thì cần có một khoảng thời gian gắn bó, hay chỉ đơn giản là tìm kiếm trên một số websites hữu ích. Bạn chọn cách nào?

Với tôi thì vấn đề ngôn ngữ là dễ dàng, vì tôi chỉ chọn Java। Nhưng dùng frameworks nào? JSP, Servlet, Struts, JSF, Spring MVC... thì cũng khá là đau đầu.

Các blogs sau sẽ cung cấp một số kiến thức bổ ích về thế giới Internet.


1. Smashing Magazine

Smashing Magazine là một trong những nơi để tìm một mẫu thiết kế hay ít nhất là ý tưởng. Mỗi bài viết là một bìa học về thiết kế web và phát triển, và là một blog không thể thiết đối với một web designer.

2. Ajaxian

Có ai đó nói rằng: “nếu bạn biết Javascript, thì bạn đã biết 80% về Ajax”. Thì Ajaxian phần lớn các bài viết nói về Javascript, và các thư viện Javascript như Dojo hay JQuery. Cường độ post bài là 5 đến 10 mỗi ngày, thì đây là một trang đáng xem đối với các Web 2.0 Developer.

3. ReadWriteWeb

Mọi thứ diễn ra trong thế giới internet, bạn đều có thể tìm thấy trên ReadWriteWeb. Nếu bạn là một nhà kinh doanh trên internet hay xây dựng websites, thì đây là blog sẽ đem đến cho bạn một kiến thức bổ ích cho công việc. Được xây dựng một cách bài bản, với số lượng bài đều đặn, blog này đang có một thứ hạng cao với PC World’s Top 100 và Technorati’s Top 20.

4. Adam Bien’s Blog

Bài viết là những nhận xét về kỹ thuật, vấn đề mắc phải, tutorial về JavaEE và mọi thứ liên quan đế Sun. Là một địa chỉ không thể thiếu đối với những Java EE Developer.

5. Flex Examples

Flex là một framework đang được dùng khá phổ biến trong Rich Internet Application – Nói đến các ứng dụng web có tính năng và đặc tính như một ứng dụng trên máy desktop- (RIA). Đây là một framework hay, nhưng cũng có nhiều thứ khó có thể làm theo ý mình. Flex Examples sẽ giúp bạn giải quyết các vướng mắc khi sử dụng bằng các tutorials nhằm giải quyết các vấn đề. Nếu bạn là một Flex developer, bạn không thể bỏ qua blog này.

6. Vitamin

Được viết theo kiểu “how-to” tutorials chung quanh các vấn đề về thiết kế và hiện thực websites. Mỗi tutorial được trình bày một cách rỏ ràng theo một ngôn từ dễ hiểu. Họ được nhận giải SXSW Award 2007 Best Education Resource - nơi tốt nhất để học tập.

7. Agile Ajax

AJAX đang đóng một vai trò lớn trong phát triển web. Agile Ajax viết về các tutorials và các đoạn code hữu ích cho Javascript developer. Bên cạnh tutorials, họ còn có các bình luận về sách.

8. Slashdot

Đây cũng là một trong những blog chuyên về các tin tức công nghệ rất được yêu thích. Bạn cũng có thể tìm thấy những comment rất thẳng thắn và thú vị ở đây.

9. TechCrunch

Với xứ mệnh tìm kiếm các thông tin và bình luận về các công ty và sản phẩm internet. Tìm ra xu hướng và các công ty hứa hẹn đem đến một nét mới cho internet. Người sáng lập ra blog này là luật sư Michael Arrington. Những mối quan hệ của Arrington đã mang tới cho blog những tin tức mới nhất trước khi phần còn lại của thế giới biết đến.

10. A List Apart

Những bài viết mà tôi mong chờ ở họ bao gồm web-standards, best practices, accessibility, và usability. Những bài viết của ALA có chất lượng rất tốt và họ chỉ post khoảng 2 bài một tháng, nhưng cũng đáng để chờ. Được viết bởi những người có uy tín trong ngành, trong đó có Eric MeyerJeffrey Zeldman.


Hi vọng các bạn có thể học được nhiều điều từ các websites trên. Và tất nhiên, sự thiếu nếu có thêm một site nào hay thì có thể chia sẽ trong comment


Đọc tiếp >>

Cao Trong Hien

,

Hiendt's weblog – Cái nhìn mới


Cuối cùng thì cũng xong! Một giao diện mới.
Có lẽ tôi đặt tên cho nó là red steel vì nó được lấy từ template blue-steel của bloggerbuster.

Mất 4 ngày chỉnh sửa, tôi cho rằng ổn, Với một số tính năng mới:


  • Tính năng đọc thêm cho bài viết

  • Chia sẽ bài viết bằng comment hay các trang chia sẽ (Digg, StumbleUpon, và del.icio.us)

  • Tính năng cho các bài viết liên quan


Chuyển từ tông xanh sang đỏ là không dễ dàng, các bạn có thể thấy cái vẻ gượng gạo trong cách phối màu। Cái này là chắc rồi vì tôi chỉ là một developer mà.

Mọi ý kiến đóng góp vui lòng để trong nhận xét.

Update: Đã thêm phần chia sẽ với vietkick.
Update: Mới thêm 2 widget ratingbest post.

Đọc tiếp >>

Cao Trong Hien

6 Dịch Vụ Cung Cấp SVN & Project Hosting


Nguồn mở (Open Source) đang chiếm ưu thế, ít nhất là hiện giờ. Và các dịch vụ online đang tăng cường nhảy vào các dịch vụ cộng đồng miễn phí, dĩ nhiên nó có ý nghĩa rất lớn đối với developers muốn lưu trữ (hosting), quản lý (manage), giới thiệu và chia sẽ online. Xin giới thiệu 6 SVN hosting miễn phí và cung cấp các tính năng cho quản lý dự án (project management) mà tôi biết.

Unfuddle – Một cái tên đẹp và một website trau chuốt. Dùng công nghệ web 2.0 cộng với chức năng theo dõi tiến độ dự án (project tracking), quản lý code (source control), thời gian (time tracking), các mốc dự án (milestones), vv... Gói miễn phí bao gồm 200MB lưu trữ và giới hạn thành viên(2), nó cũng không rộng rãi như Assembla không giới hạn thành viên nhóm.

Assembla – Một phần của gói các tính năng đầy đủ cho project management với một người dùng thường với 500MB bộ nhớ. Với $19, còn có thể đang tìm ứng viên cho project và một số tính năng như wiki , blogs,...

OpenSVN – Một phiên bản miễn phí đầu tiên của SVN hosting của các dự án nguồn mở và ta có thể thấy được sự “cổ kính” đó ngay khi bắt đầu vào trang và dùng các tính năng.

Bounty Source
– Cung cấp các tính năng như một SVN bình thường với wiki và CMS và quản lý công việc (task tracker). Bounty Source là server duy nhất có tính năng thanh toán tiền công cho developer theo số yêu cầu mà họ thực hiện được (bounties).

SourceForge
– Đã tồn tại từ khá lâu và cũng đã thể hiện được uy tín từ số năm tồn tại. Họ cũng cố gắng dùng các tính năng của Web2.0, tuy nhiên vẫn không thể trút bỏ hoàn toàn, bạn có thể thấy khi dùng các tính năng mà nó cung cấp.

Google Project Hosting
– Kế thừa đầy đủ các tính năng của SourceForge nên đầy đủ. Tuy nhiên, như đã đề cập trên thì nó nhìn cũ và tôi nghĩ Google không chăm sóc dịch vụ này tận tình lắm.

Đọc tiếp >>

Cao Trong Hien

KonaKart: Java Shopping Cart miễn phí


Hãng DS Data Systems Anh vừa cho ra đời KonaKart v2.2.4.0, một hệ thống shopping cart miễn phí bằng được viết bằng java. KonaKart bao gồm các tính năng cần thiết cho một online shopping cart, dựa trên các tính năng của osCommerce nổi tiếng.
KonaKart dựa trên giải pháp của Java / JSP / XML dùng các java API và các interface của SOAP Web Service kết nối với nhau.

Hầu hết các tính năng trên bản 2.2.4.0 là thêm tính năng quản lý nhóm khách hàng, nhiều loại giá và hệ thống lên hệ trực tiếp.

Khách hàng có thể được sắp vào nhóm như nhóm đại lý, khách hàng thân thiết hay sinh viên-học sinh. Thông tin về nhóm có thể dùng để phân định giá bán, thăng cấp và còn có thể dùng email.

Trường hợp một sản phẩm thể có nhiều loại giá. Vì dụ, có thể là giá dành cho hệ thống đại lý, giá cho khách hàng thân thiết và giá thường. Giá hiển thị phụ thuộc vào nhóm mà khác hàng đó thuộc về.
Bạn có thể xem thêm các thông tin về nó trên http://www.konakart.com.

Đọc tiếp >>

Cao Trong Hien

,

Xbox 360 không bị ảnh hưởng bởi thất bại của HD DVD


Tập đoàn Microsoft không cho rằng một sản phẩm của họ là Xbox 360 sẽ không bị tổn hại vì Toshiba Corp không tiếp tục với công nghệ HD DVD, Microsoft nói trong một bài phát biểu hôm thứ 2

“Chúng tôi không cho rằng những thông tin mới từ phía HD DVD sẽ có một ảnh hưởng đến Xbox 360 hay vị thế trên thương trường của nó,” họ nói. “Chúng tôi sẽ chờ cho đến khi nghe một thông tin chính thức từ Toshiba trước khi đưa ra một kế hoạch cho Xbox 360 với định dạng HD DVD.”

Xbox 360 hỗ trợ HD DVD plug-in cho phép người dùng có thể xem những hình ảnh chất lượng cao được sản xuất bởi công nghệ từ Toshiba.

Một thông tin đáng tin cậy từ phía Toshiba cho rằng công ty đang chỉnh sửa cách kinh doanh HD DVD, bằng cách ngưng phát hành trong khoảng 2 tháng để cho ra đời một kiểu định dạng khác cho DVD.

Những khách hàng có thể sẽ mua DVD có độ phân giải cao được sản xuất với Blu-ray, được phát hành bởi tập đoành Sony.

Theo thông tin từ phía Microsoft thì người dùng Xbox 360 sẽ tiếp tục được xem những bộ phim chất lượng cao, chương trình TV, và những DVD mà họ đang có.

Trước đó trong tháng 1, Microsoft tuyên bố rằng sẽ hỗ trợ công nghệ Blu-Ray cho những chiếc Xbox 360.

Trọng Hiền (Reuters)

Đọc tiếp >>

Cao Trong Hien

AOP xử dụng Spring Framework


Trong khoảng 5 năm trở lại đây, một khuynh huớng lập trình mới xuất hiện. Nó được gọi là AOP để phân biệt với kiểu lập trình OOP đã có sẵn. Nguời viết muốn cung cấp cho bạn đọc một kiến thức cơ bản về kiểu lập trình mới mẻ này, và xử dụng springframework, một open-source phổ biến, để minh hoạ. Nếu bạn muốn tìm hiểu chi tiết về cách xử dụng springframework, thì bài viết này không nhằm mục đích đó, mà chỉ trình bày khái quát về những thuật ngữ và nguyên tắc trong việc xử dụng 1 chức năng phổ biết của spring: declarative transaction .

Một điểm quan trọng nữa cần đuợc nêu ra, AOP đuợc xem là cái bổ sung cho OOP, chỗ mà OOP còn thiếu sót trong việc tạo những ứng dụng thuộc loại phức tạp. AOP khônng phải là cái thay thế OOP. Nguời lập trình bắt buộc phải quen thuộc với OOP để bắt đầu với AOP. Cũng vì lí do này mà AOP thuờng đuợc xem là dành cho các bạn đã có kinh nghiệm, chứ không dành cho các bạn mới bắt đầu làm quen với Java. Bạn có thể làm quen với OOP qua lí thuyết và sách vở từ truờng học. Và nếu bạn thấy vẫn còn lạc lối trong việc tìm kiếm những danh từ, tính từ, hay trả lời những câu hỏi ai, cái gì, làm gì... đại loại như vậy, trong việc tìm kiếm class, thì bạn có thể đọc lại những bài viết về OOP mà nguời viết đã trình bày truớc đây xem có giúp ích hơn không. Dù học OOP theo kiểu nào thì kết quả cuối cùng của OOP là chia ứng dụng thành nhiều phần nhỏ với những chức năng riêng biệt, theo kiểu các hộp đen (black box). Các hộp đen này làm cho việc tái xửng dụng và bao quản chúng đuợc dễ dàng hơn....và còn thêm nhiều ưu điểm khác nữa không kể ra ở đây.

Lấy ví dụ về transaction trong việc truy cập database. Trong Java, truy cập database đòi hỏi nhiều buớc: tạo ra Connection, bắt đầu transation, commit, clean up connection... Để đơn giản hoá, ta hãy tạo ra 1 class hay black box chuyên làm việc này.

public class DBTransaction {
public DBTransaction () {
//mã nguồn tạo ra Connection và bắt đầu 1 transaction
}

public Connection getConnection () {
//mã nguồn return Connection đã tạo ra
}

public void commit () {
//mã nguồn commit transaction và clean up resources
}
}

Giả sử trong 1 ứng dụng, có 1 class (hay blackbox) XuatNhapHang làm chức năng xuất nhập hàng và nó chứa 1 method làm chức năng nhập hang.

public void nhapHang ( int monHang, int soLuong )
{
//xử dụng blackbox để bắt đầu 1 transaction
DBTransation tx = new DBTransactiơn ();

// ...mã nguồn truy cập database để nhập hàng...

tx.commit ();
}

Bạn dễ dàng hình dung đuợc mục đích xử dụng của blackbox này.
Mỗi khi cần truy cập database, nguời xử dụng chỉ việc gọi các public methods của nó mà không cần biết tới bên trong nó hoạt động ra sao. Việc thay đổi bên trong của blackbox cũng không làm ảnh huởng tới nguời xử dụng nó. Đó là cái đẹp của việc tạo ra blackbox. Mọi nguời hình như đều vui vẻ và độc lập với công việc của mình. Thực tế không hoàn toàn như vậy. Giả sử ứng dụng sau này đòi hỏi phải theo dõi tất cả mọi hoạt động liên quan đến việc truy cập database. Mỗi khi database đuợc truy cập, tên nguời xử dụng và thời gian sẽ đuợc lưu trữ lại. Ta có thể tạo ra 1 blackbox đơn giản chuyên làm việc này.

public class DBTruyCapTheoDoi {
public DBTruyCapTheoDoi (Connection con, String tenNguoi) {
//mã nguồn lưu lại trong database nguời xử dụng và thời gian
.....
}
}

Method nhapHang hay những nơi trong ứng dụng đã truy cập database đều phải sửa đổi như sau

public void nhapHang ( int monHang, int soLuong )
{
//xử dụng blackbox để bắt đầu 1 transaction
DBTransation tx = new DBTransactiơn ();
//theo doi truy cap
DBTruyCapTheoDoi (tx.getConnection (), tenNguoi);

// ...mã nguồn truy cập database để nhập hàng...

tx.commit ();
}

Sửa đổi không nhiều nhưng nó rộng khắp trong toàn ứng dụng. Đây chính là điểm làm cho nhiều nguời không hài lòng. Những nguời lập trình kì cựu đều đồng ý với nhau rằng, trong thực tế, đòi hỏi của ứng dụng luôn thay đổi theo thời gian. Cứ mỗi 1 yêu cầu mới của ứng dụng thì một (hay nhiều) blackbox đuợc tạo thành, và mã nguồn sẽ bị thay đổi rộng khắp trong ứnng dụng để xử dụng blackbox mới này. Thay đổi mã nguồn rộng khắp ứng dụng là điều tối kị vì nó đòi hỏi phải testing lại toàn bộ . Những bug xuất hiện lúc này thuờng rất khó tìm vì nguời lập trình thuờng cho rằng "mình sửa có 1 chút thì không sao..." .

Câu hỏi đặt ra là làm sao tạo đuợc một kiểu lập trình uyển chuyển với sự phức tạp của ứng dụng . Mô hình này phải cho phép tạo dựng nhanh chóng ứng dụng khi nó ở trong giai đọan đầu đơn giản, và thay đổi nhanh chóng để thích ứng kịp thời với đòi hỏi mới . OOP cho phép tạo ra những blackbox và điều này vẫn đuợc xem là không thể thiếu trong việc lập trình . Bản thân những blackbox không phải là vấn đề, mà chính việc xử dụng chúng mới là vấn đề . Việc gọi trực tiếp những public method của 1 blackbox khi phải xử dụnng nó trong mã nguồn, tạm gọi là nối cứng (hard wired) blackbox vào mã nguồn . Có cách nào để xử dụng 1 blackbox mà khônng cần gọi trực tiếp nó trong mã nguồn hay không? Cần có 1 cách nào đó để gọi gián tiếp những public method, hay tạm gọi là nối mềm (soft wired) khi xử dụng những blackbox. Đây là chỗ OOP bỏ sót, và AOP ra đời để đáp ứng nhu cầu này .

Đến đây bạn có thể thấy rằng, OOP là buớc đầu tiên cần phải có để tạo thành các blackbox. AOP là buớc kế tiếp để nối mềm những blackbox tạo thành 1 ứng dụng hoàn chỉnh . Việc nối mềm đòi hỏi nguời thiết kế phải có kinh nghiệm trong việc chia ứng dụng thành nhiều lớp (layer) để ứng dụng đuợc tạo ra và chạy 1 cách hữu hiệu . Điều này sẽ đuợc nói kĩ hơn sau đây. Một rắc rối nữa của việc nối mềm là nó thuờng đòi hỏi tạo nhiều cấu hình (configuration) phụ trợ .

Làm thế nào để nối mềm 1 ứng dụng? Đây cũng chính là câu hỏi mà AOP cần phải trả lời . Java cho phép là đuợc việc này .

Nối mềm là cho phép xử dụng 1 class (hay blackbox) mà không cần gọi trực tiếp public methods của nó trong mã nguồn, và bạn có thể ngạc nhiên nếu biết rằng điều này thực sự đã đuợc làm từ lâu . Nó đuợc làm bởi các container chẳng hạn như của EJB, portlet, servlet. Lấy EJB container làm ví dụ, vì nó rất gần với khái niệm AOP . Muốn xử dụng 1 EJB, bạn phải gọi create... chứ không bao giờ xửng dụng new . EJB trong thực tế chạy bên trong 1 container. Container trực tiếp tạo ra instance của EJB và chuyển cho nguời xử dụng khi method create... được gọi . Mỗi lần nguời xử dụng gọi method của EJB, container sẽ đón đầu (intercept) cú gọi này, rồi mới chuyển giao cho instance của EJB . Truớc khi chuyển giao cho EJB, thuờng container có thể sẽ làm nhiều việc khác nữa .... Container có thể bắt đầu 1 transaction, hay kiểm tra xem nguời gọi có đuợc phép gọi hay không, tùy theo cách cấu hình của EJB đó bên trong file ejb-jar.xml . Nếu xem EJB là 1 blackbox thì việc nối giữa EJB và nguời xử dụng nó mặc dù là gián tiếp nhưng chưa đuợc xem là nối mềm . Bản thân EJB container có thể chứa sẵn bên trong nó 1 blackbox làm công việc bắt đầu 1 transaction, hay 1 blackbox khác làm công việc kiểm tra mức độ cho phép nguời gọi . Việc nối kết giữa EJB và những blackbox bên trong của container mới chính xác là mềm ... Bản thân EJB hay nguời viết nó hoàn toàn không biết đến có tồn tại 1 blackbox có sẵn bên trong container làm công việc transaction . Nguời viết EJB chỉ việc thông tin với container qua file cấu hình ejb-jar.xml rằng phải bắt đầu 1 transaction hay làm thêm những chuyện khác mỗi khi method của nó đuợc gọi . Cũng dựa trên ý tuởng này, spring framework chính là 1 container thuộc loại nhẹ và nó có thể chứa đựng những Java object thông thuờng chứ không phức tạp như EJB .

Trở lại ví dụ xuất nhập hàng ở trên, nếu class XuatNhapHang chạy bên trong spring framework thì method nhapHang ở trên có thể viết lại như sau

public void nhapHang ( int monHang, int soLuong )
{
// ...mã nguồn truy cập database để nhập hàng...
}

Không hề có 1 đọan mã nguồn nào bên trong method nhapHang nói đến việc tạo ra transaction hay theo doi truy cap . Bản thân các blackbox transaction và theo dõi try cập cũng đuợc chạy trong spring. Nguời viết class XuatNhapHang chỉ việc truyền đạt cho spring, qua 1 file cấu hình, rằng mỗi khi method nhapHang đuợc gọi , hãy gọi blackbox transaction và theo dõi truy cập truớc khi chuyển nó đến nhapHang . Bằng cách nối mềm này, việc bao gồm hay loại bỏ những blackbox đuợc thực hiện qua việc thay đổi file cấu hình, chứ không cần phải thay đổi mã nguồn của class XuatNhapHang . Đây chính là lập luận mạnh nhứt trong việc cho ra đời AOP . Những nguời ủng hộ AOP trong ví dụ này lí luận rằng class XuatNhap hay method nhapHang chỉ nên lo lắng việc xuất nhập hàng . Việc bắt đầu 1 transaction hay theo dõi truy cập dữ liệu , đành rằng phải có do yêu cầu của ứng dụng, cũng không nên chen lấn 1 cách thô bạo vào trong mã nguồn của class XuatNhap, hay bất kì vào trong những blackbox nào khác khi chúng cũng cần truy cập dữ liệu . Có như vậy thì 1 blackbox mới giữ đuợc tính độc lập của nó với những thay đổi của yêu cầu của ứng dụng, dẫn đến việc tái xử dụng blackbox đuợc triệt để hơn .
Những khía cạnh như transaction hay theo dõi truy cập, nếu cần phải 'chen lấn ' thì mã nguồn không phải là chỗ tốt để làm . Có những chỗ tốt hơn chẳng hạn như dùng file cấu hình, và spring framework làm đúng như vậy . Công việc của spring framework là đón đầu các cú gọi và thực hiện các chức năng thể hiện qua file cấu hình . Đây cũng chính là nguyên tắc cơ bản của AOP: thay các cú gọi trực tiếp, bằn các cú gọi qua file cấu hình ..

Đọc đến đây, có thể bạn không mấy hào hứng với AOP . Thực tế các file cấu hình cho spring hay các AOP framework khác như AspectJ không đơn giản chút nào . Gọi trực tiếp method chỉ mất 1 dòng và cũng dễ theo dỏi logic của ứng dụng . Thay đổi file cấu hình liệu có an toàn hơn thay đổi mã nguồn hay không ? Những nguời ủng hộ AOP thì cho rằng nó rất nên làm . Những nguời còn hoài nghi thì luỡng lự . Các AOP framework khác nhau đều có cách tạo file cấu hình khác nhau. Không giống như EJB có thể chạy trong mọi EJB container, ứng dụng viết cho AOP framework này không chạy đuợc trong AOP framework khác . Những cố gắng để thống nhứt các AOP framework cho đến bây giờ vẫn chưa kết thúc . Việc container đón đầu các cú gọi có thể ảnh huởng đến tốc độ chạy của ứng dụng . Thêm nữa, không phải mọi class trong ứng dụng đều cần đuợc quản lí bởi AOP framework cũng như không phải mọi class đều trở thành EJB. Nếu ứng dụng thiết kết kém cỏi có thể dẫn đến số luợng class mà AOP container phải quản lí cùng với các file cấu hình tăng lên nhanh chóng . Có lẽ cũng chính vì những lí do này mà AOP vẫn chưa cất cánh nhanh chóng như OOP . Điểm khó khăn cuối cùng nữa của AOP là lí thuyết hoá nó để truyền đạt . AOP đưa ra những khái niệm lạ hoắc khó nắm bắt, dễ làm nản lòng những nguời mới bắt đầu . Phần kế tiếp nguời viết sẽ trình bày những khái niệm cơ bản của AOP, và nguyên tắc Inversion of Control hay còn gọi là Dependency Injection của springframework trong việc triển khai AOP .

Khái niệm đầu tiên thuờng gặp trong AOP là concern (1 mối lo âu) hay aspect ( 1 khía cạnh của vấn đề). Concern hay aspect trong AOP chỉ là 1, và nó tuơng đuơng với chức năng của 1 blackbox trong OOP. Lấy ví dụ trong ứng dụng cho 1 cửa hàng mua bán . Những yêu cầu của ứng dụng bao gồm : chi thu tài chính, xuất nhập hàng, kết toán cuối tháng, cuối năm, quản lí nhân viên ... Và có thể thay đổi trong tuơng lai theo yêu cầu của thực tế . Việc chia nhỏ 1 yêu cầu cùng với OOP sẽ đưa đến các blackbox như xuất nhập hàng, transaction, hay theo dõi truy cập như ở trên . Chức năng của mỗi blackbox có thể đuợc xem là 1 khía cạnh của ứng dụng mà nguời thiết kế phải lo lắng . Tới đây bạn có thể thấy vì sao 2 chữ concern và aspect mang nghĩa không mấy ăn nhập với nhau lại đuợc dùng để chỉ chung 1 khái niệm . Có những khía cạnh, như transaction, cần phải 'chen lấn ' vào các khía cạnh khác . Những khía cạnh đó đuợc gọi là crosscutting aspect, tạm gọi là những khía cạnh cắt ngang . Trong thực tế, điểm chen lấn của những crosscutting aspect không tùy tiện mà nó thuờng là các điểm đặc biệt . Ví dụ như khía cạnh trasaction chỉ chen vào khi bắt đầu method nhapHang để khởi tạo 1 transaction và lại chen vào 1 lần nữa khi method nhapHang return để commit transaction. Những điểm đặc biệt có thể kể ra là bắt đầu hay kết thúc 1 method, khi xảy ra exception. Spring chỉ cho phép chen vào các điểm đặc biệt, còn AspectJ thì cho phép hầu như vào bất cứ điểm nào trong mã nguồn . Việc chen lấn tuỳ tiện cần được cân nhắc kĩ lưỡng và thuờng đuợc khuyên nên tránh . Điểm chen lấn đuợc gọi là joinpoint (điểm nối ) . Tập họp các điểm nối đuợc gọi là pointcut (cắt điểm). Bản thân blackbox XuatNhapHang bị chen lấn nên nó đuợc gọi là target object . Bản thân blackbox transaction, triển khai transaction aspect, làm công việc chen lấn, đuợc gọi là advice . Vì có nhiều điểm chen lấn đặc biệt kể trên, nên có nhiều loại advice.
_ Around advice: là loại chen vào truớc khi cú gọi đuợc chuyển tới method và sau khi method thực hiện xong. Transaction advice chính là loại này
_ Before advice: chen vào truớc khi cú gọi đuợc chuyển tới method
_ Throws advice: chen vào khi bản thân method thows excpetion
_ After returning advice: chen vào sau khi method thực hiện và không có exception .

Ta có thể hình dung như sau: mỗi khi ứng dụng gặp điểm 'chen lấn ', container sẽ đón đầu cú gọi và chạy mã nguồn của advice cho điểm 'chen lấn ' đó rồi mới chuyển giao cho method .
Tới đây có lẽ khá đủ cho nguời mới làm quen với AOP. Để thực sự có thể lập trình theo kiểu AOP, bạn cần phải thông thạo với 1 AOP framework như spring hay aspectJ, đặc biệt là cách tạo file cấu hình cho mỗi framework.

Trở lại spring framework, nó đuợc đề cập ở đây vì 1 chức năng phổ biến : declarative transaction, giống như trong EJB, nhưng đơn giản và dễ xử dụng hơn nhiều. Để xử dụng chức năng này, chỉ cần khái niệm của AOP ở trên là đủ . Khi xử dụng spring, 1 khái niệm luôn gặp phải là Inversion of Control (IoC) hay còn gọi là Dependency Injection, nó sẽ đuợc nói rõ duới đây .

IoC (tạm dịch là đảo nguợc kiểm soát) thuờng được thực hiện bởi các loại container như servlet, portlet, hay EJB. Lấy ví dụ EJB container, nguời xử dụng không trực tiếp tạo ra instance của EJB, mà container tạo ra nó và chuyển giao nguời xử dụng khi cần tới . Khi nào instance đuợc tạo ra nằm ngoài sự kiểm soát của nguời xử dụng . Container có thể tạo instance ra truớc và chờ đến khi nguời xử dụng, hoặc tạo ra ngay vào lúc đuợc cần tới . Tên gọi IoC cũng nhằm chỉ lí do này: container giành sự kiểm soát từ nguời xử dụng (trong lập trình thông thuờng nguời xử dụng giành kiểm soát bằng cách gọi new để tạo ra instance). Khi instance của EJB đuợc tạo ra và trong truờng hợp session bean, container luôn gọi method setSessionContext(SessionContext sc) để cho EJB xử dụng SessionContext của nó . Tuơng tự trong servlet container, khi instance của servlet đuợc tạo ra, container luôn gọi method init(ServletConfig sc) để servlet xử dụng . Trong cả 2 truờng hợp, container đuợc xem là nạp (injection) cho instance cái mà nó cần . Cái đuợc cần như SessionContext hay ServletConfig gọi là dependency . Tên gọi Dependency Injection cũng từ đây mà ra. Có 1 điểm bất đồng giữa cách gọi tên Dependency Injection và định nghĩa về mối quan hệ giữa class trong UML . Dựa trên tài liệu "Mastering UML with Rational Rose" thì instance của EJB xử dụng SessionContext nên instance mới chính là dependency phụ thuộc vào SessionContext . Nếu bạn giải thích đuợc tại sao có sự bất đồng này thì làm ơn cho mọi nguời cùng biết . Dù sao thì chúng ta không nên mất quá nhiều thời giờ cho vấn đề định nghĩa và tên gọi ở đây .

Muốn xử dụng spring, ít nhiều bạn phải làm quen với spring container . Class tiêu biểu cho spring container là ApplicationContext . Nguời xử dụng phải trực tiếp tạo ra instance của spring container truớc khi có thể xử dụng những object mà nó chứa . Có nhiều cách tạo ra spring container. Cách thông thuờng nhứt là (những ví dụ theo sau đuợc dựa trên tài liệu spring-reference.pdf vversion 1.2.8)

ApplicationContext ac = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml", "applicationContext-part2.xml"});

Spring container tạo ra theo cách này sẽ đọc những file config duới dạng xml để load tất cả các Java ojbect mà nó cần quản lí .
Như ví dụ sau
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

ExampleBean và ExampleBeanTwo có thể là những java object thông thuờng chứ không có gì đặc biệt . Muốn truy cập chúng qua container rất dễ dàng

ExampleBean eb = (ExampleBean)ac.getBean("exampleBean");
ExampleBeanTwo eb2 = (ExampleBeanTwo)ac.getBean("anotherExample");

Theo mặc định thì container sẽ tạo ra singleton instance cho mỗi bean, có nghĩa là chỉ 1 instance của 1 bean đuợc tái xử dụng cho những lần gọi sau . Ta có thể xử dụng Dependency Injection của container như sau

<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<property name="beanTwo"><ref bean="yetAnotherBean"/></property>
<property name="integerProperty"><value>1</value></property>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;

public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}

Bản thân ExampleBean phải chứa những setter method để container gọi ngay sau khi tạo ra chúng và truớc khi chuyển cho nguời xử dụng .

Nguyên tắc xử dụng spring container chỉ đơn giản như vậy thôi . Nó cho phép định nghĩa qua file cấu hình những logic phức tạp hơn mà bài viết không trình bày hết ra đây . Tới đây bạn có thể thắc mắc như vậy thì sức mạnh của spring nằm ở đâu ? Tiện lợi chỉ đơn giản như vậy thì có đáng đuợc xử dụng không ?

Cần nhắc lại 1 nguyên tắc làm việc của mọi dạng container là đón đầu những cú gọi . Spring làm việc này bằng cách dựa trên file cấu hình để tạo ra những object phụ trợ khác vào lúc runtime . Cái return từ method getBean đuợc xem là 1 proxy đuợc tạo ra vào lúc runtime của java object mà spring quản lí . Đằng sau proxy này là 1 tập họp các phụ trợ object thực hiện các chức năng theo yêu cầu của file cấu hình truớc khi chuyển cú gọi tới cho java object . Chẳng hạn như các phụ trợ object có thể chạy mã nguồn của advice, hoặc bắt đầu 1 transaction, một chức năng đã đuợc làm sẵn trong spring, sẽ đuợc nói tới duới đây .

Trong việc truy cập database, ứng dụng có thể xử dụng các phuơng pháp khác nhau như: trực tiếp xử dụng SQL, Hybernate, EJB Entity ... Để đơn giản hoá vấn đề, ta lấy truờng xử dụng SQL để cập nhựt database .

Trong Java, connection thường tạo ra duới dạng connection pool hay DataSource, là 1 tập họp những connection để xử dụng chung cho toàn bộ ứng dụng . Giả sử apache datasource đuợc xử dụng ở đây . Để container có thể tạo ra datasource cho oracle, ta xử dụng cấu hình duới đây

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//localhost:1521"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>

Nếu datasource đã đuợc tạo ra xử dụng JNDI, ta có thể dùng cấu hình

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/jpetstore"/>>
</bean>

Bản thân datasource sẽ đuợc xử dụng bởi 1 transaction manager, 1 object quản lí transaction có sẵn trong spring như sau:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

Trở lại class XuatNhapHang ở trên, muốn spring tự động bắt đầu và kết thúc 1 transaction mỗi khi 1 method của class này đuợc gọi , cần có những cấu hình cho pointcut hay advice khá phức tạp theo kiểu AOP . Rất may là spring đã gói gọn trong 1 class TransactionProxyFactoryBean đơn giản sau

<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED, -MyException</prop>
</props>
</property>
</bean>

Chúng ta sẽ kiểm tra kĩ lưỡng cấu hình này .
_ abstract="true" có nghĩa là ứng dụng không đuợc phép gọi method getBean("txProxyTemplate") . Cấu hình này chỉ đuợc dùng để các cấu hình khác extends . Giống như tính chất inheritance trong OOP
_ property name="transactionManager" ref="txManager" cho biết class TransactionProxyFactoryBean sẽ đuợc nạp bean txManager bởi container.
_ prop key="*" : áp dụng cho mọi method của những class extends cấu hình này
_ PROPAGATION_REQUIRED: bắt đầu 1 transaction nếu chưa có hoặc tiếp tục 1 transaction có sẵn .
_ -MyException: nếu method throw MyException, thì dấu - đằng truớc sẽ làm transaction bị rollback, và dấu + sẽ commit transaction truớc khi throw MyException.
Cấu hình của class XuatNhapHang sẽ extends cấu hình này như sau:

<bean id="xuatNhapBean" parent="txProxyTemplate">
<property name="target">
<bean class="XuatNhapHang"></bean>
</property>
</bean>

Ứng dụng có thể xử dụng class XuatNhapHang như sau:

XuatNhapHang xnh = (XuatNhapHang)ac.getBean("xuatNhapBean");
xnh.nhapHang(...);

Bằng cách extends cấu hình của txProxyTemplate qua việc sử dụng attribute parent, mỗi khi 1 method của class XuatNhapHang đuợc gọi, 1 transaction sẽ tự động bắt đầu và kết thúc . Transaction sẽ bị rollback trong truờng hợp exception MyException xảy ra . Spring còn giúp mô hình JDBC operations như những java object qua việc xử dụng class MappingSqlQuery, SqlUpdate, StoredProcedure .

Bài viết đuợc kết thúc ở đây chỉ với mục đích giúp bạn làm quen với những khái niệm của AOP । Vì AOP là cái bổ sung cho những thiếu xót của OOP, AOP không dành cho những bạn mới bắt đầu lập trình . Spring framework mặc dù triển khai AOP đơn giản hơn so với AspectJ, cũng khác phức tạp với rất nhiều chức năng có thể dùng đuợc, và nguời viết chỉ tóm tắt 1 chức năng phổ biến nhứt của nó là declarative transaction. Dù sao thì bạn vẫn cần tham khảo những tài liệu huớng dẫn về spring truớc khi có thể dùng nó 1 cách hữu hiệu . Chúc bạn may mắn .

Theo(Javavietnam)


Đọc tiếp >>

Cao Trong Hien

,