SlideShare a Scribd company logo
1 of 51
Download to read offline
ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
PHẠM ĐÌNH PHONG
NGHIÊN CỨU VỀ
KIỂM CHỨNG BẤT BIẾN CỦA ĐỐI TƯỢNG
SỬ DỤNG LẬP TRÌNH HƯỚNG KHÍA CẠNH
Ngành: Công nghệ thông tin
Chuyên ngành: Công nghệ phần mềm
Mã số: 60 48 10
LUẬN VĂN THẠC SĨ
NGƯỜI HƯỚNG DẪN KHOA HỌC: PGS. TS. Nguyễn Việt Hà
Hà Nội – 2010
ii
Lời cảm ơn
Với lòng biết ơn sâu sắc, em xin chân thành cảm ơn thầy giáo PGS. TS. Nguyễn
Việt Hà, người đã trực tiếp định hướng đề tài và tận tình hướng dẫn em hoàn thành luận
văn này. Em cũng chân thành cảm ơn thầy TS. Phạm Ngọc Hùng đã có những nhận xét,
đánh giá trong quá trình hoàn thiện luận văn.
Em xin được bày tỏ lòng biết ơn đối với các thầy giáo, cô giáo Khoa Công nghệ
thông tin Trường Đại học Công nghệ đã tận tình chỉ bảo, giảng dạy em suốt thời gian
học tại trường cũng như việc hoàn thành luận văn này.
Cuối cùng, xin được bày tỏ tình cảm tới những người thân trong gia đình, các bạn
bè trong tập thể lớp Cao học K15T2, K15T3 và K15CNPM đã động viên, hỗ trợ em về
mọi mặt.
Em xin chân thành cảm ơn!
Hà Nội, tháng 09 năm 2010
Phạm Đình Phong
iii
Lời cam đoan
Tôi xin cam đoan rằng, ngoại trừ các nội dung được trích từ tài liệu tham khảo
hoặc các công trình khác như đã ghi rõ trong luận văn, các kết quả nêu trong luận văn
này là do chính tôi thực hiện.
Hà Nội, tháng 09 năm 2010
Phạm Đình Phong
iv
MỤC LỤC
Lời cảm ơn ..................................................................................................................ii
Lời cam đoan............................................................................................................. iii
MỤC LỤC..................................................................................................................iv
Danh mục bảng biểu ...................................................................................................vi
Danh mục hình vẽ......................................................................................................vii
Danh mục ký hiệu, từ viết tắt ....................................................................................viii
MỞ ĐẦU.....................................................................................................................1
Chương 1 – Lập trình hướng khía cạnh........................................................................4
1.1. Giới thiệu ......................................................................................................4
1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng ........................................5
1.2.1. Các mối quan tâm của hệ thống..............................................................5
1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP .................................7
1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP8
1.3. Lập trình hướng khía cạnh...........................................................................10
1.3.1. Lịch sử hình thành................................................................................10
1.3.2. Cú pháp của AOP và mô hình lập trình ................................................11
1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh...................12
1.3.4. Đan kết.................................................................................................13
1.3.5. Phương pháp lập trình hướng khía cạnh ...............................................14
1.3.6. Lợi ích của lập trình hướng khía cạnh...................................................15
1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh .....................17
1.3.8. Các công cụ AOP.................................................................................18
1.4. AspectJ........................................................................................................19
1.4.1. Thực thi cắt ngang................................................................................19
1.4.2. Joint Point ............................................................................................20
1.4.3. Pointcut................................................................................................22
1.4.4. Advice..................................................................................................26
1.4.5. Introduction..........................................................................................29
1.4.6. Aspect ..................................................................................................30
1.5. Kết luận.......................................................................................................33
Chương 2 - Công cụ kiểm chứng mô hình Java PathFinder........................................34
2.1. Giới thiệu ....................................................................................................34
2.2. Công cụ kiểm chứng mô hình Java PathFinder ............................................34
2.2.1. Lịch sử của Java PathFinder .................................................................35
2.2.2. Các thành phần của Java PathFinder.....................................................35
2.2.3. Những gì có thể được kiểm chứng bởi Java PathFinder ........................37
2.2.4. Kiểm chứng mô hình trong Java PathFinder.........................................37
2.3. Các đề án mở rộng của Java PathFinder.......................................................40
2.4. Kết luận.......................................................................................................41
Chương 3 – Kiểm chứng bất biến của chương trình Java sử dụng lập trình hướng khía
cạnh...........................................................................................................................42
3.1. Đặt vấn đề ...................................................................................................42
3.2. Ngôn ngữ mô hình hóa thống nhất UML .....................................................43
3.2.1. Thuộc tính............................................................................................43
v
3.2.2. Liên kết................................................................................................44
3.2.3. Thao tác ...............................................................................................44
3.3. Ngôn ngữ ràng buộc đối tượng OCL ...........................................................45
3.3.1. Biểu diễn biểu thức OCL......................................................................45
3.3.2. Bất biến (invariant)...............................................................................46
3.4. Ví dụ minh họa............................................................................................48
3.5. Kiểm chứng bất biến sử dụng AOP .............................................................50
3.6. Vấn đề kế thừa các bất biến ở lớp con .........................................................51
3.7. Kiểm chứng bất biến của lớp con có ràng buộc thay đổi so với lớp cha .......55
3.8. Kiểm chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con ..60
3.9. Thực nghiệm ...............................................................................................62
3.10. Kết luận ...................................................................................................64
Chương 4 – Sinh tự động các ca kiểm thử bằng công cụ Java PathFinder ..................65
4.1. Tổng quan ...................................................................................................65
4.2. Thực thi ký hiệu ..........................................................................................65
4.3. Sinh tự động các ca kiểm thử bằng thực thi ký hiệu.....................................67
4.4. Kiểm chứng bất biến bằng việc chèn khẳng định .........................................71
4.4.1. Khẳng định trong Java và Java PathFinder ...........................................71
4.4.2. Xác định các bất biến ...........................................................................72
4.4.2.1. Đặt khẳng định trong đoạn mã.......................................................72
4.4.2.2. Kiểm tra bất biến trong phương thức main ....................................72
4.4.2.3. Bất biến như là một tiến trình (Invariant as a Thread)....................74
4.4.3. So sánh phương pháp AOP và phương pháp chèn khẳng định ..............75
4.5. Kết quả thực nghiệm ...................................................................................76
4.5.1. Kết quả thực nghiệm sinh các ca kiểm thử tự động...............................76
4.5.2. Kết quả thực nghiệm kiểm chứng bất biến bằng chèn khẳng định.........79
4.6. Kết luận.......................................................................................................80
KẾT LUẬN ...............................................................................................................81
TÀI LIỆU THAM KHẢO..........................................................................................83
vi
Danh mục bảng biểu
Bảng 1.1. So sánh giữa aspect và lớp
Bảng 3.1. Một số kết quả thực nghiệm
vii
Danh mục hình vẽ
Hình 1.1. Các mối quan tâm trong một hệ thống
Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP
Hình 1.3. Chồng chéo mã nguồn
Hình 1.4. Dàn trải mã nguồn
Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect
Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP
Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP
Hình 1.8. Các giai đoạn phát triển AOP
Hình 1.9. Ví dụ về định nghĩa pointcut
Hình 2.1. Sự bố trí các tầng của JPF
Hình 2.2. Các thành phần của JPF
Hình 2.3. Bùng nổ không gian trạng thái do sự đan xen giữa các luồng
Hình 3.1. Biểu diễn các ràng buộc trên sơ đồ UML
Hình 3.2. Ví dụ biểu đồ lớp của hệ thống card ATM
Hình 3.3. Quy trình kiểm chứng bất biến
Hình 4.1. Thực thi ký hiệu
viii
Danh mục ký hiệu, từ viết tắt
Từ viết tắt Thuật ngữ Ý nghĩa
AOP Aspect-Oriented Programming Lập trình hướng khía cạnh
API
Application Programming
Interface
Giao diện lập trình ứng dụng
ASCII
American Standard Code for
Information Interchange
Bộ mã chuẩn cho trao đổi thông tin
của Mỹ
AWT Abstract Window Toolkit
Bộ công cụ đồ họa độc lập nền tảng
của Java
CTW Compile-time Weaving Đan kết lúc biên dịch
Eclipse Bộ công cụ phát triển phần mềm
IBM
International Business Machines
Corp
Một trong những nhà sản xuất máy
tính lớn nhất thế giới
JDK Java Development Kit Bộ phát triển ứng dụng Java
JPF Java PathFinder
Bộ công cụ kiểm chứng mô hình
cho ngôn ngữ Java
JVM Java Virtual Machine Máy ảo Java
LTW Load-time Weaving Đan kết lúc nạp chương trình
MJI Model Java Interface Giao diện Java mẫu
OCL Object Constraint Language Ngôn ngữ ràng buộc đối tượng
OOP Object-Oriented Programming Lập trình hướng đối tượng
RTW Run-time Weaving Đan kết lúc thực thi
SPIN Simple Promela INterpreter
Công cụ thông dịch ngôn ngữ
Promela (trong kiểm chứng mô
hình)
SUT System Under Test Hệ thống được kiểm thử
Syntropy
Một phương pháp phân tích và thiết
kế hướng đối tượng thế hệ thứ hai
UML Unified Modeling Language Ngôn ngữ mô hình hóa thống nhất
VM Virtual Machine Máy ảo
XML eXtensible Markup Language Ngôn ngữ đánh dấu mở rộng
1
MỞ ĐẦU
Những năm gần nay, với sự phát triển của phương pháp lập trình hướng đối
tượng (OOP) [1, 2, 12] đã mang lại nhiều bước tiến mới cho lập trình nói chung và đưa
ngành Công nghệ phần mềm lên một bước phát triển mới. Ưu điểm lớn nhất của lập
trình hướng đối tượng là một hệ thống phần mềm được xây dựng bởi tập các lớp rời
rạc. Mỗi lớp có nhiệm vụ hoàn toàn xác định, các nhiệm vụ của nó được vạch ra một
cách rõ ràng. Trong một ứng dụng hướng đối tượng, các lớp cộng tác với nhau để đạt
được mục tiêu chung của ứng dụng. Tuy nhiên, có các phần của một hệ thống không
chỉ gánh nhiệm vụ giới hạn trong một lớp, chúng cắt ngang toàn bộ hệ thống và ảnh
hưởng đến nhiều lớp. Đó chính là sự đan nhau phức tạp giữa các thành phần bên trong
ứng dụng. Bên cạnh đó, tính tĩnh trong cách tiếp cận hướng đối tượng không cho phép
phần mềm thích ứng với những thay đổi mới đáp ứng yêu cầu người dùng. Một hướng
tiếp cận mới trong việc phát triển phần mềm là lập trình hướng khía cạnh (AOP:
Aspect-Oriented Programming) [10, 22, 3]. Hướng tiếp cận này còn khá mới mẻ
nhưng hứa hẹn những lợi điểm giải quyết được những yêu cầu có tính đan xen phức
tạp, đồng thời mang lại cho phần mềm khả năng thay đổi và bổ sung yêu cầu mới sau
khi đã hoàn chỉnh hay thậm chí đã đưa vào sử dụng.
Ngôn ngữ mô hình hóa thống nhất (Unified Modelling Language - UML [4])
được chấp nhận rộng rãi như là một chuẩn cho phân tích và thiết kế hướng đối tượng.
Việc biểu diễn và mô hình hóa cấu trúc tĩnh của hệ thống hướng đối tượng được dùng
phổ biến trong các sơ đồ lớp UML. Tuy nhiên, không phải các cấu trúc chi tiết nào
cũng có thể được biểu diễn một cách dễ dàng trong một sơ đồ lớp. Ngôn ngữ ràng
buộc đối tượng (Object Constraint Language - OCL [29]), một phần của UML, là ngôn
ngữ dùng cho việc mô tả các ràng buộc thêm vào trên các mô hình hướng đối tượng.
Các ràng buộc OCL được sử dụng để mô tả các bất biến trên các lớp và các kiểu, các
tiền điều kiện và hậu điều kiện của các thao tác. Các ràng buộc OCL luôn luôn được
kết nối tới một mô hình hướng đối tượng UML. Một bất biến (invariant) là một ràng
buộc liên quan đến một lớp, kiểu hay giao diện trong một mô hình UML. Bất biến
được biểu diễn như một biểu thức lôgic giới hạn giá trị của một thuộc tính hay liên kết
hay nó có thể biểu diễn mối quan hệ giữa các giá trị của các thuộc tính, các liên kết.
Kết quả của biểu thức phải là đúng đối với tất cả các thể hiện của lớp được tham chiếu.
Giai đoạn đảm bảo chất lượng phần mềm ngày càng trở nên quan trọng. Trong
giai đoạn này, các đặc tả UML và các ràng buộc OCL đã được tạo ra bởi các nhà thiết
kế phần mềm, chương trình chính đã được cài đặt bởi các nhà phát triển phần mềm
dựa trên các đặc tả UML. Như vậy làm thế nào để kiểm chứng được bất biến của các
đối tượng được thể hiện bằng các ràng buộc OCL có bị vi phạm tại thời điểm thực thi
hay không. Sau khi nghiên cứu phương pháp AOP, chúng tôi thấy có thể sử dụng
2
phương pháp này để cài đặt các mã kiểm chứng để kiểm chứng các bất biến của các
phần mềm được thiết kế theo phương pháp hướng đối tượng dựa trên các ràng buộc
OCL đã được thiết kế. Đã có những nghiên cứu trước đó liên quan đến phương pháp
này [3, 23]. Theo đó, công việc kiểm chứng được tách biệt hoàn toàn khỏi chương
trình chính bằng cách tạo ra các aspect chứa mã kiểm chứng. Các aspect này sẽ được
đan tự động vào chương trình chính và khi chương trình được thực thi, công việc kiểm
chứng sẽ được thực hiện tự động. Tuy nhiên các nghiên cứu chưa xem xét việc kiểm
chứng bất biến cho các lớp con được kế thừa bên dưới. Chúng tôi quan tâm tới việc
xem xét các bất biến của các đối tượng theo quan hệ kế thừa, cụ thể là nghiên cứu
kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào lớp con và bất
biến của lớp con có ràng buộc thay đổi so với lớp cha.
Việc kiểm thử tính đúng đắn của các phương thức cần có bộ dữ liệu làm đầu vào
cho các phương thức cần kiểm thử. Một bộ dữ liệu vào như vậy được gọi là một ca
kiểm thử (test case). Việc chọn các bộ dữ liệu như thế nào để có thể phủ toàn bộ các
đường thực thi có thể (possible execution path) là rất khó. Nếu có công cụ sinh tự động
các ca kiểm thử phủ toàn bộ các đường thực thi có thể thì ta có thể chứng minh tính
đúng đắn của phương thức thông qua các ca kiểm thử được sinh ra. Java PathFinder
(JPF) [19, 25, 30, 31] với phần mở rộng của nó là thực thi ký hiệu dùng để sinh tự
động các ca kiểm thử phủ được toàn bộ các đường thực thi có thể cho các phương thức
của các đối tượng trong chương trình được cài đặt bằng ngôn ngữ Java. Chúng tôi sử
dụng công cụ thực thi ký hiệu để sinh tự động các ca kiểm thử nhằm kiểm tra lại
phương pháp kiểm chứng bất biến bằng AOP.
Nội dung nghiên cứu: Tìm hiểu và nghiên cứu về kiểm chứng phần mềm, lập trình
hướng khía cạnh (Aspect Oriented Programming - AOP) và sử dụng AOP để kiểm
chứng bất biến của đối tượng bao gồm:
Nghiên cứu về lý thuyết kiểm chứng phần mềm, các phương pháp, công cụ
kiểm chứng phần mềm.
Nghiên cứu phương pháp lập trình hướng khía cạnh và AspectJ - một đặc tả
ngôn ngữ cho việc cài đặt các aspect bằng ngôn ngữ lập trình Java.
Mở rộng phương pháp sử dụng AOP để kiểm chứng các bất biến của đối
tượng trong chương trình Java tại thời điểm thực thi được đề xuất trong [23] bao gồm
kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào ở lớp con và bất
biến của lớp con có ràng buộc thay đổi so với lớp cha.
Để kiểm tra tính đúng đắn của các phương thức cần có các ca kiểm thử làm
dữ liệu đầu vào. Do đó chúng tôi nghiên cứu công cụ kiểm chứng mô hình Java
PathFinder và phần mở rộng thực thi ký hiệu (Symbolic Execution) [15] của nó để
sinh tự động các ca kiểm thử cho các phương thức của các đối tượng trong chương
trình hướng đối tượng Java.
3
Sử dụng công cụ Java PathFinder để kiểm chứng bất biến được khai báo dưới
dạng các khẳng định (assertion) trong chương trình Java và so sánh với phương pháp
kiểm chứng bất biến sử dụng AOP.
Cấu trúc luận văn: Luận văn gồm các phần: Mở đầu, 4 chương, kết luận và tài liệu
tham khảo:
Chương 1 giới thiệu phương pháp lập trình hướng khía cạnh. Chúng tôi trình bày
quá trình hình thành phương pháp lập trình hướng khía cạnh, ưu điểm và nhược điểm
của nó đồng thời trình bày về AspectJ – một cài đặt phổ biến của AOP trên ngôn ngữ
lập trình hướng đối tượng Java.
Chương 2 trình bày tổng quan về công cụ kiểm chứng mô hình Java PathFinder
(JPF) và các mở rộng của nó.
Chương 3 trình bày và mở rộng kỹ thuật kiểm chứng bất biến của đối tượng trong
chương trình hướng đối tượng Java tại thời điểm thực thi sử dụng phương pháp AOP.
Chúng tôi trình bày kỹ thuật sử dụng AOP để kiểm chứng bất biến của đối tượng Java.
Phương pháp này đã có các nghiên cứu được công bố [23, 3] và chúng tôi mở rộng
xem xét các bất biến theo quan hệ kế thừa. Cụ thể là chúng tôi đề xuất kỹ thuật kiểm
chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con và bất biến của lớp
con có ràng buộc thay đổi so với lớp cha.
Chương 4 trình bày phương pháp sử dụng công cụ thực thi ký hiệu là một mở
rộng của JPF để sinh các ca kiểm thử tự động cho các phương thức của đối tượng
trong chương trình hướng đối tượng Java nhằm mục đích kiểm tra lại phương pháp
kiểm chứng sử dụng AOP. Chương này cũng trình bày phương pháp kiểm chứng bất
biến được khai báo dưới dạng các khẳng định trong chương trình Java sử dụng JPF và
so sánh với phương pháp kiểm chứng bất biến sử dụng AOP. Một vài thực nghiệm của
thực thi ký hiệu và của kiểm chứng bất biến bằng việc chèn các khẳng định cũng được
trình bày.
4
Chương 1 – Lập trình hướng khía cạnh
1.1. Giới thiệu
Hệ thống phần mềm có thể được xem là một thể hiện kết hợp nhiều vấn đề. Một
hệ thống tiêu biểu có thể gồm nhiều dạng vấn đề như xử lý nghiệp vụ, hiệu suất, bảo
toàn dữ liệu, bảo mật, bẫy lỗi, … và còn có những vấn đề của quá trình phát triển hệ
thống như tính dễ quản lý, dễ bảo trì và phát triển. Trong việc thiết kế phần mềm, các
nhà thiết kế phần mềm thường tập chung sự quan tâm vào các chức năng chính, cơ bản
của hệ thống. Trong ứng dụng của các doanh nghiệp, đó chính là các logic nhiệp vụ cơ
bản. Ví dụ như trong ứng dụng quản lý nhgiệp vụ bảo hiểm, các mô-đun chức năng
chính được thiết kế cho việc quản lý các giao dịch bảo hiểm do khách hàng hoặc nhân
viên phòng nghiệp vụ thực hiện. Trong ứng dụng quản lý nhân sự, các mô-đun quản lý
chính là quản lý hồ sơ nhân viên, tính toán lương và các chế độ cho nhân viên. Trong
hai ứng dụng trên, các mô-đun xử lý nghiệp vụ chính có thể được thực hiện riêng rẽ
nhưng có những mối quan tâm liên quan đến nhiều mô-đun như tính năng lưu vết, xác
thực quyền hạn, truy cập cơ sở dữ liệu, bẫy lỗi, … Các tính năng đó là cần thiết đối với
mỗi mô-đun chính của hệ thống và dàn trải trên nhiều môđun của hệ thống. Các mối
quan tâm dàn trải trên nhiều mô-đun của hệ thống đó được gọi là các mối quan tâm cắt
ngang (cross-cutting concerns). Do vậy đối với mỗi mô-đun, lập trình viên ngoài việc
quan tâm đến những vấn đề cơ bản còn phải tính đến những mối quan tâm cắt ngang
và sự trộn lẫn nhiều đoạn mã để xử lý những yêu cầu khác nhau. Sự trộn lẫn nhiều
đoạn mã như vậy gọi là vấn đề đan nhau. Do vấn đề đan nhau có ở nhiều mô-đun nên
các đoạn xử lý liên quan cũng xuất hiện ở nhiều mô-đun. Những vấn đề này ảnh
hưởng đến vấn đề thiết kế và phát triển phần mềm như hệ thống khó xây dựng, khó
quản lý, phát triển và tái sử dụng kém.
Lập trình hướng đối tượng (Object-Oriented Programming - OOP) [1, 2, 12] là
phương pháp lập trình phổ biến nhất hiện nay được sử dụng để quản lý các mối quan
tâm nghiệp vụ chính, tuy nhiên phương pháp này chưa đủ mạnh để xử lý hiệu quả rất
nhiều các mối quan tâm cắt ngang hệ thống, đặc biệt là các ứng dụng phức tạp.
Phương pháp lập trình hướng khía cạnh (Aspect-Oriented Programming - AOP)
[10, 22, 3] là phương pháp lập trình mới cho phép chúng ta thực hiện các vấn đề riêng
biệt một cách linh hoạt và kết hợp chúng lại để tạo nên hệ thống sau cùng. AOP bổ
sung cho kỹ thuật lập trình hướng đối tượng bằng việc cung cấp một dạng mô-đun
khác bằng cách kéo các mối quan tâm cắt ngang vào một khối, đó chính là aspect. Với
AOP, ta có thể cài đặt các mối quan tâm cắt ngang hệ thống trong các aspect thay vì
dàn trải chúng trên các mô-đun nghiệp vụ chính liên quan. Quá trình bộ đan aspect
(weaver) kết hợp các mô-đun nghiệp vụ chính với các aspect thành hệ thống cuối cùng
5
được gọi là quá trình đan (weaving). Như vậy, AOP đã mô-đun hóa các mối quan tâm
cắt ngang một cách rõ ràng, tách biệt với các mô-đun nghiệp vụ chính giúp cho việc
thiết kế, thực thi và bảo trì hệ thống dễ dàng hơn và tốn ít chi phí, công sức. Các aspect
của hệ thống có thể thay đổi, thêm hoặc xóa lúc biên dịch và có thể tái sử dụng.
Lập trình hướng khía cạnh là kỹ thuật lập trình mới cho phép đóng gói những
hành vi liên quan đến nhiều đối tượng và rất có thể sẽ là bước phát triển kế tiếp trong
phương pháp lập trình. Tuy nhiên AOP không thay thế OOP mà nó là sự bổ sung cho
OOP, cho phép chúng ta giải quyết các bài toán phức tạp tốt hơn và hiệu quả hơn.
Trong các phần tiếp theo, chúng ta sẽ khảo sát những vấn đề mà lập trình hướng đối
tượng làm tốt và những vấn đề phát sinh từ các đối tượng và làm thế nào AOP có thể
lấp khoảng trống này. AspectJ [11, 13, 26], một cài đặt phổ biến của AOP trên ngôn
ngữ Java cũng được giới thiệu trong chương này.
1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng
Phát triển phần mềm đã đi được một quãng đường khá dài. Khi sự hữu ích của
phát triển phần mềm được phát hiện, sự cải tiến nó đã trở nên bắt buộc để tìm kiếm các
kỹ thuật để mô hình hóa các bài toán của thế giới thực một cách hiệu quả hơn. Nhiều
năm trước, phương pháp luận chung cho việc giải quyết một bài toán là chia nó thành
các môđun chức năng nhỏ hơn và mỗi chức năng được cấu thành từ nhiều dòng lệnh.
Phương pháp luận này đã làm việc tốt nhưng một trạng thái hệ thống được điều khiển
bởi một số lượng lớn các biến toàn cục mà chúng có thể được thay đổi bởi bất kỳ dòng
lệnh nào trong ứng dụng. Sự xuất hiện của phương pháp luận hướng đối tượng kéo
trạng thái của hệ thống vào các đối tượng riêng lẻ, chúng có thể trở nên riêng tư và
được điều khiển thông qua các phương thức truy cập và logic.
Kỹ thuật OOP rất xuất xắc trong việc đóng gói các hành vi vào chủ thể lớp
(class), miễn là chúng riêng biệt. Tuy nhiên, trong các bài toán thực tế có những hành
vi dàn trải trên nhiều lớp. Trong hầu hết các ngôn ngữ lập trình hướng đối tượng
truyền thống như C++ [2] hay Java [1, 12] đều không hỗ trợ việc đóng gói các hành vi
dàn trải trên nhiều môđun, dẫn đến mã chương trình có thể nằm lẫn lộn, rải rác và khó
quản lý. Hiện tại, OOP được lựa chọn cho hầu hết các dự án phần mềm. Nó tập chung
vào giải quyết các nghiệp vụ chính nhưng nó không phải là phương pháp tốt để quản
lý các hành vi dàn trải trên nhiều mô-đun.
1.2.1. Các mối quan tâm của hệ thống
Sự chia tách các mối quan tâm là một nguyên lý cơ bản của kỹ nghệ phần mềm.
Nguyên lý này giúp quản lý tính phức tạp của phát triển phần mềm bằng việc khai báo,
đóng gói và khai thác các phần của phần mềm liên quan đến một mối quan tâm đặc
thù. Một mối quan tâm (concern) là một yêu cầu cụ thể hoặc một sự cân nhắc nào đó
cần phải được đưa ra nhằm thỏa mãn mục đích chung của toàn hệ thống. Một hệ thống
phần mềm là việc thực thi tập các mối quan tâm đó. Ví dụ trong một hệ thống quản lý
6
nghiệp vụ bảo hiểm bao gồm việc thực thi các mối quan tâm sau: quản lý khách hàng,
quản lý hợp đồng bảo hiểm, tính lãi suất cho các hợp đồng bảo hiểm có yếu tố tiết
kiệm, thực hiện chi trả bảo hiểm, tạo báo cáo, xác thực quyền hạn, lưu vết giao dịch,
… Bên cạnh các mối quan tâm của hệ thống, một dự án phần mềm cần chỉ ra được các
mối quan tâm khác liên quan đến toàn bộ các thuộc tính chất lượng của hệ thống như
tính dễ hiểu, dễ quản lý, dễ bảo trì và phát triển.
Các mối quan tâm được chia thành hai loại: mối quan tâm chính được cài đặt
chức năng chính của một mô-đun và mối quan tâm cắt ngang là yêu cầu ngoài, mức hệ
thống và dàn trải trên nhiều mô-đun. Một ứng dụng của một doanh nghiệp không
những quan tâm đến các mối quan tâm nghiệp vụ chính mà còn phải quan tâm đến các
mối quan tâm cắt ngang hệ thống như xác thực quyền hạn, lưu vết giao dịch, bẫy lỗi,
truy cập tài nguyên chung, đảm bảo tính toàn vẹn của giao dịch, … Tất cả các mối
quan tâm này đều cắt ngang một số mô-đun. Ví dụ như mối quan tâm về việc lưu vết
giao dịch liên quan đến tất cả các môđun giao dịch chính, mối quan tâm về truy cập dữ
liệu liên quan đến các mô-đun có truy xuất cơ sở dữ liệu, mối quan tâm về xác thực
quyền hạn liên quan đến các mô-đun có yêu cầu về quản lý quyền truy cập. Hình 1.1
minh họa việc thực thi các mô-đun trong một hệ thống chứa cả các mối quan tâm mức
hệ thống và các mối quan tâm nghiệp vụ. Ở đây, một hệ thống được mô tả như một sự
tổng hợp của nhiều mối quan tâm. Hệ thống trở nên chồng chéo lên nhau bởi các kỹ
thuật cài đặt hiện tại, chính vì thế, sự độc lập giữa các mối quan tâm không được đảm
bảo.
Hình 1.1. Các mối quan tâm trong một hệ thống.
7
1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP
Trong quá trình phát triển phần mềm các nhà phát triển thường xác định các mối
quan tâm và sau đó chia tách chúng cho các nhóm phát triển khác nhau để mô-đun hóa
chúng. Có những trở ngại lớn cho các nhóm phát triển khi mô-đun hóa các mối quan
tâm là làm sao xử lý hiệu quả các mối quan tâm cắt ngang hệ thống. Trong thực tế,
phương pháp OOP thường được sử dụng để mô-đun hóa các mối quan tâm của một hệ
thống phần mềm. Tuy nhiên, thực tế thì, mặc dù OOP giải quyết rất tốt trong việc mô-
đun hóa các mối quan tâm nghiệp vụ chính nhưng lại gặp khó khăn trong việc mô-đun
hóa các mối quan tâm cắt ngang hệ thống.
Trong OOP, các mô-đun chính có thể được kết nối lỏng với nhau thông qua giao
diện, nhưng không dễ gì làm việc này với các mối quan tâm cắt ngang hệ thống. Lý do
chính là một mối quan tâm được thực thi thành hai phần: Phần phía server (phần phục
vụ) và phần phía client (phần được phục vụ). OOP mô-đun hóa phần client khá tốt
bằng các lớp và các giao diện. Tuy nhiên, ở phía server, một mối quan tâm lại là một
loại cắt ngang hệ thống, bao gồm các yêu cầu gửi đến server, dàn trải trên các client.
Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP.
Xét một ví dụ điển hình về việc thực thi một mối quan tâm cắt ngang hệ thống
trong OOP: Một mô-đun lưu vết cung cấp các dịch vụ thông qua một giao diện trừu
tượng. Việc sử dụng giao diện nới lỏng kết nối giữa các client và việc thực thi các giao
diện. Các client sử dụng các dịch vụ lưu vết thông qua giao diện dành cho hầu hết các
phần không quan tâm đến chi tiết cài đặt mà họ đang sử dụng. Khi có bất cứ thay đổi
nào đến các cài đặt mà chúng đang sử dụng sẽ không yêu cầu thay đổi đến bản thân
các client. Tương tự như thế, việc thay thế sự thực thi lưu vết bằng một sự thực thi
khác chỉ là vấn đề về việc khởi tạo đúng loại thực thi. Kết quả là một sự thực thi về lưu
vết có thể được chuyển đổi với sự thực thi khác với ít hoặc không thay đổi cho các
8
mô-đun client riêng lẻ. Tuy nhiên, trong cấu hình này, các client vẫn phải chứa các
đoạn mã để gọi các API. Những lời gọi này cần phải có trong tất cả các mô-đun có yêu
cầu cần lưu vết và được trộn lẫn với các đoạn mã dành cho logic nghiệp vụ chính.
Hình 1.2 minh họa cách thực thi mối quan tâm lưu vết trong một hệ thống phần
mềm quản lý nghiệp vụ bảo hiểm sử dụng các kỹ thuật truyền thống như OOP. Thậm
chí khi sử dụng mô-đun lưu vết được thiết kế tốt đưa ra API trừu tượng và che giấu chi
tiết về việc định dạng và phân lớp các thông điệp lưu vết, thì mỗi mô-đun client như
mô-đun Subscribing, Claim hay Database đều phải chứa các đoạn mã để triệu gọi API
lưu vết. Kết quả tổng thể là gây ra sự lộn xộn, chồng chéo giữa các mô-đun cần lưu vết
và bản thân các mô-đun lưu vết.
1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP
Khi thực thi các mối quan tâm cắt ngang bằng phương pháp OOP, hệ thống sẽ
gặp phải một số vấn đề trong đó có hai vấn đề chính là sự chồng chéo mã nguồn và
dàn trải mã nguồn.
Chồng chéo mã nguồn (Code tangling): Các mô-đun trong hệ thống có thể
đồng thời phải thực hiện nhiều yêu cầu khác nhau. Ví dụ như trong quá trình phát triển
một mô-đun nào đó, ngoài việc đảm bảo yêu cầu chính của mô-đun đó, lập trình viên
luôn phải tính tới các mối quan tâm khác như hiệu năng, đồng bộ, an ninh, lưu vết, lưu
trữ,... Các mối quan tâm này làm cho việc xuất hiện rất nhiều loại mã chương trình của
các mối quan tâm khác nhau trong quá trình cài đặt mô-đun. Hiện tượng này gọi là
chồng chéo mã nguồn. Hình 1.3 minh họa vấn đề chồng chéo mã nguồn do sự thực thi
của nhiều mối quan tâm trên cùng một mô-đun.
Hình 1.3. Chồng chéo mã nguồn.
Dàn trải mã nguồn (Code scattering): Mã nguồn của các yêu cầu mức hệ
thống (an ninh, lưu vết, lưu trữ,...) được cài đặt ở trong rất nhiều mô-đun. Ví dụ như
chức năng lưu vết được cài đặt ở tất các các mô-đun quan trọng cần lưu vết. Như vậy
việc cài đặt mã nguồn cho một mối quan tâm bị xé nhỏ vào rất nhiều mô-đun khác
9
nhau. Hiện tượng này gọi là dàn trải mã nguồn. Hình 1.4 minh họa vấn đề dàn trải mã
nguồn do đặt nhiều đoạn mã giống nhau trong nhiều mô-đun khác nhau nhằm thực thi
một chức năng nào đó. Ở đây, trong ví dụ hệ thống quản lý nghiệp vụ bảo hiểm, nhiều
mô-đun trong hệ thống phải chứa đoạn mã để đảm bảo rằng những người dùng hợp lệ
mới có thể truy cập các các chức năng nghiệp vụ của hệ thống.
Hình 1.4. Dàn trải mã nguồn.
Với các vấn đề đã phân tích ở trên, quá trình phát triển phần mềm sẽ bị ảnh
hưởng với một số vấn đề sau:
Ánh xạ giữa các mối quan tâm và cài đặt kém: Việc đồng thời cài đặt nhiều
mối quan tâm cũng gây ra hiệu ứng làm giảm thiểu khả năng tư duy ánh xạ giữa một
mối quan tâm và mã nguồn cài đặt của nó cho lập trình viên cũng như người kiểm
duyệt mã nguồn.
Hiệu suất làm việc thấp: Việc đồng thời cài đặt nhiều mối quan tâm làm cho
lập trình viên phải phân tán tư tưởng vào nhiều mối quan tâm một lúc, giảm hiệu suất
làm việc.
Khả năng sử dụng lại mã nguồn kém: Một mô-đun thực tế đã cài đặt rất nhiều
mối quan tâm một lúc, nếu như hệ thống khác có nhu cầu sử dụng chức năng tương tự
có thể chưa chắc đã sử dụng lại mô-đun này do nó còn phụ thuộc vào các mối quan
tâm khác.
Chất lượng mã nguồn thấp: Việc chồng chéo mã nguồn trong quá trình cài đặt
sẽ gây ra những vấn đề tiềm ẩn mà lập trình viên có thể không phát hiện ra được khi
lập trình, do sự chú ý của mình bị ảnh hưởng bởi quả nhiều mối quan tâm.
10
Khó bảo trì hệ thống: Việc xây dựng hệ thống tại thời điểm nào đó thường bị
giới hạn trong một khung nhìn với những yêu cầu cụ thể nào đó, thể hiện ở các mối
quan tâm hiện có của hệ thống. Nếu như trong tương lai có sự thay đổi nào đó cần bổ
sung vào hệ thống, do việc cài đặt không được mô-đun hóa nên việc sửa đổi sẽ làm
ảnh hưởng tới rất nhiều mô-đun, có thể gây ra những sửa đổi không đồng bộ và không
thống nhất với nhau. Vì thế đòi hỏi thêm chí phí và thời gian để kiểm thử và đảm bảo
việc thay đổi trên là không gây ra lỗi.
1.3. Lập trình hướng khía cạnh
1.3.1. Lịch sử hình thành
Lập trình hướng khía cạnh (AOP) là một tiếp cận thiết kế phần mềm được phát
minh tại trung tâm nghiên cứu Xerox Palo Alto trong những năm 1990. Nó kế thừa các
kết quả của các phương pháp lập trình khác như lập trình tự sinh (generative
programming), siêu lập trình (meta-programming), lập trình tự điều chỉnh (reflective
programming), lập trình có khả năng thích ứng (adaptive programming), lập trình
hướng chủ đề (subject-oriented programming), lập trình có mục đích (intentional
programming), … Mục đích của AOP là để các nhà thiết kế và các nhà phát triển tách
các mối quan tâm cắt ngang mà một hệ thống phần mềm gặp phải tốt hơn. Các mối
quan tâm cắt ngang là các phần tử của một hành vi hệ thống không được xác định một
cách dễ dàng đối với các thành phần cụ thể trong một kiến trúc ứng dụng. Các mối
quan tâm cắt ngang thông thường là xử lý lỗi, các kiểm tra bảo mật, lưu vết các sự
kiện, xử lý giao dịch, … Mỗi thành phần trong ứng dụng phải chứa mã đặc trưng cho
mỗi mối quan tâm cắt ngang, tạo ra mã của thành phần phức tạp hơn và khó thay đổi
hơn.
Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect
Để xác định các mối quan tâm cắt ngang, AOP cũng cấp các kỹ thuật cho sự nhận
dạng có hệ thống, sự chia tách, sự biểu diễn và kết cấu. Mỗi quan tâm cắt ngang được
đóng gói trong các mô-đun riêng gọi là các aspect. Trong quá trình thực thi, các aspect
11
được đan kết vào chương trình thực thi để thực thi các mối quan tâm cắt ngang hệ
thống.
1.3.2. Cú pháp của AOP và mô hình lập trình
Cắt ngang là một kỹ thuật AOP cho phép nhận dạng các mối quan tâm và cấu
trúc chúng vào trong các mô-đun bằng cách chúng có thể được triệu gọi tại các điểm
khác nhau thông qua ứng dụng. Có hai loại cắt ngang, tĩnh và động. Cắt ngang động
sửa đổi hành vi thực thi của một đối tượng bằng việc đan kết hành vi mới tại các điểm
quan tâm cụ thể. Cắt ngang tĩnh thay thế cấu trúc tĩnh của một thành phần bằng việc
xen thêm các phương thức và các thuộc tính tại thời điểm thực thi. Các cấu trúc ngôn
ngữ cơ bản và cú pháp được sử dụng để khai báo cắt ngang trong AOP như sau:
Joint point là một điểm thực thi có thể nhận dạng trong một chương trình. Nó
có thể là một lời gọi tới một phương thức hay một lệnh gán cho một thuộc tính của đối
tượng. Các joint point là quan trọng, chúng là nơi mà các hành vi của aspect được đan
kết vào trong chương trình.
Pointcut là một cấu trúc chương trình lựa chọn ra một nhóm các join point và
tập hợp ngữ cảnh tại các join point này. Hay nói cách khác, pointcut nhận dạng một
joint point trong chương trình mà tại đó một mối quan tâm cắt ngang cần được áp
dụng. Ví dụ như, một pointcut có thể lựa chọn một join point là lời gọi tới một phương
thức, nó cũng có thể nắm bắt ngữ cảnh của phương thức đó, chẳng hạn như đối tượng
đích chứa phương thức được gọi và các tham số của phương thức đó. Pointcut dùng để
chỉ ra các quy tắc đan còn join point là các vị trí thỏa mãn các quy tắc đó.
Ví dụ sau khai báo một pointcut khi phương thức setValue của lớp Stock được
gọi:
pointcut log(String msg): args(msg) &
execution(void Stock.setValue(float));
Advice là một đoạn mã thực thi logic một mối quan tâm cắt ngang. Nó được
thực thi khi một pointcut cụ thể được đạt tới. Advice có thể được thực thi trước (before
advice), sau (after advice) hoặc “xung quanh” (around advice) join point.
Ví dụ một before advice được cài đặt trong AspectJ:
before (String msg): log(msg){
//Đoạn mã thực thi
}
Introduction là chỉ thị cắt ngang có thể tạo các thay đổi tĩnh đối với các thành
phần ứng dụng. Một introduction có thể tạo ra các thay đổi tĩnh cho các mô-đun mà
không ảnh hưởng trực tiếp đến các hành vi của chúng. Ví dụ, một instruction có thể
thêm một phương thức hoặc một trường vào một lớp trong ứng dụng.
12
Aspect trong AOP tương ứng với một lớp trong lập trình hướng đối tượng. Nó
đóng gói các pointcut, các advice và các intruction.
Ví dụ một aspect được cài đặt bằng AspectJ:
public aspect LoggingModule {
pointcut log(String msg):args(msg) &
execution(void Stock.setValue(float));
before (String msg): log(msg){
//Đoạn mã thực thi
}
}
Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP
1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh
Với việc sử dụng các kỹ thuật thiết kế thông thường, một mối quan tâm cắt ngang
có thể được mô-đun hóa bằng việc sử dụng một giao diện để đóng gói sự thực hiện
mối quan tâm từ việc triệu gọi các thành phần phía client. Mặc dù giao diện làm giảm
sự móc nối giữa các client và sự thực thi mối quan tâm, các client vẫn cần mã nhúng
để triệu gọi các phương thức giao diện từ bên trong logic nghiệp vụ.
Với thiết kế và lập trình hướng khía cạnh, mỗi mối quan tâm cắt ngang được cài
đặt một cách riêng rẽ trong một thành phần là aspect. Aspect định nghĩa các điểm thực
thi trong các thành phần phía client đòi hỏi sự thực hiện mối quan tâm cắt ngang. Đối
với mỗi điểm thực thi, aspect định nghĩa các hành vi cần thiết để thực hiện hành vi của
aspect, ví dụ như gọi một API lưu vết. Trong hình 1.7, mối quan tâm cắt ngang là việc
13
lưu vết sự thực thi các mô-đun Subscribing, Claim và Database được cài đặt trong một
aspect là Logging aspect. Tiếp đó, Logging aspect có các lời gọi API tới Logging
module để thực thi các phương thức cần thiết. Trong quá trình thực thi ứng dụng,
Logging aspect được đan tự động vào các mô-đun nghiệp vụ chính để thực hiện việc
lưu vết giao dịch. Bộ phận phát triển các mô-đun Subscribing, Claim và Database
không cần quan tâm đến việc thực thi việc lưu vết trong quá trình phát triển.
Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP.
Quan trọng hơn là các mô-đun phía client không chứa bất kỳ mã để triệu gọi sự
thực thi aspect nào. Điều này dẫn đến các thành phần phía client không bị xen lẫn bởi
các lời gọi để thực thi một hoặc nhiều mối quan tâm.
Việc sử dụng một aspect được xác định theo một quy tắc nhất định gọi là quy tắc
đan. Các quy tắc đan là đầu vào cho một tiện ích lập trình gọi là bộ đan. Một bộ đan
kết hợp mã ứng dụng với các aspect để tạo ra hệ thống cuối cùng. Các ngôn ngữ lập
trình hướng khía cạnh như AspectJ cung cấp các công cụ đan kết và vì thế các ngôn
ngữ AOP và các công cụ là cần thiết để thực hiện hiệu quả các thiết kế hướng khía
cạnh.
1.3.4. Đan kết
Việc thực hiện một thiết kế hướng khía cạnh đòi hỏi sự hỗ trợ của ngôn ngữ lập
trình để thực thi các aspect riêng lẻ. Ngôn ngữ cũng định nghĩa các luật cho việc đan
kết một thực thi của aspect với toàn bộ mã chương trình. Việc đan kết có thể tuân theo
một số chiến lược:
1) một bộ tiền xử lý mã nguồn đặc biệt được thực thi trong qua trình biên dịch.
14
2) một bộ hậu xử lý vá các tệp nhị phân.
3) một trình biên dịch nhận biết AOP sinh ra các tệp nhị phân được đan kết.
4) đan kết lúc nạp (load-time weaving – LTW): ví dụ, trong Java việc đan kết
advice liên quan bằng việc nạp từng lớp advice vào trong JVM.
5) đan kết lúc thực thi (run-time weaving – RTW): bằng việc chặn từng join
point tại thời điểm thực thi và thực thi tất cả các advice liên quan.
Hầu hết các ngôn ngữ AOP hỗ trợ việc đan kết lúc biên dịch (CTW) sử dụng một
trong ba tùy chọn đầu. Trong Java, trình biên dịch sinh ra các tệp lớp nhị phân Java
chuẩn mà bất kỳ JVM chuẩn nào cũng có thể thực thi. Sau đó các tệp .class được sửa
đổi dựa trên các aspect đã được định nghĩa. CTW không phải lúc nào cũng là lựa chọn
tốt và đôi khi không khả thi (ví dụ với Java Server Page). LTW đưa ra giải pháp tốt
hơn và mềm dẻo hơn. Trong Java, LTW đòi hỏi trình nạp JVM để có thể biến đổi các
lớp lúc thực thi. JDK v5.0 hỗ trợ tính năng này thông qua một kỹ thuật chuẩn đơn
giản. LTW phải xử lý mã bytecode của Java lúc thực thi và tạo các cấu trúc dữ liệu
biểu diễn bytecode của một lớp cụ thể. Quá trình xử lý này có thể diễn ra chậm. Một
khi tất cả các lớp được nạp, LTW không có ảnh hưởng gì đến tốc độ thực thi của ứng
dụng. AspectJ [11, 13, 26], JBoss AOP [27] và AspectWerkz [28] hiện hỗ trợ LTW.
RTW là một lựa chọn tốt nếu các aspect phải có hiệu lực lúc đang chạy. Tuy nhiên,
như LTW, RTW có thể có những nhược điểm về mặt hiệu suất tại thời điểm thực thi
trong khi các aspect đang được đan kết.
1.3.5. Phương pháp lập trình hướng khía cạnh
Hiện nay phương pháp lập trình hướng khía cạnh đang được quan tâm phát triển
và đang dần được hoàn thiện. Phương pháp này không phải thay thế các phương pháp
lập trình truyền thống mà là bổ sung và làm phong phú thêm phương pháp lập trình
truyền thống. AOP cung cấp một giải pháp cho việc pháp triển các hệ thống bằng việc
tách các mối quan tâm cắt ngang thành các mô-đun và ghép nối lỏng các mô-đun này
vào các mối quan tâm nghiệp vụ chính của hệ thống. Về cơ bản quá trình phát triển
phần mềm theo AOP gồm có 3 bước sau đây:
1) Phân tích các yêu cầu để xác định vấn đề chung và vấn đề đan nhau: trong
bước này ta sử dụng phương pháp phân tích và thiết kế hướng khía cạnh (Aspect-
Oriented Analyis and Design) để phân tích các yêu cầu của bài toán nhằm tách các mối
quan tâm nghiệp vụ chính và mối quan tâm cắt ngang hệ thống. Sau bước này ta thu
được bản phân tích mà các mối quan tâm nghiệp vụ chính và các mối quan tâm cắt
ngang được tách riêng.
2) Xây dựng thể hiện từng vấn đề riêng biệt: sau khi các mối quan tâm cắt ngang
được tách ra khỏi các mối quan tâm nghiệp vụ chính thì ta có thể dùng phương pháp
lập trình truyền thống như lập trình hướng thủ tục hoặc lập trình hướng đối tượng để
15
cài đặt các mối quan tâm nghiệp vụ chính, còn các mối quan tâm cắt ngang thì được
cài đặt trong một aspect theo quy tắc mà công cụ AOP được sử dụng quy định. Như
vậy, mối quan tâm nghiệp vụ chính được xây dựng độc lập với các mối quan tâm cắt
ngang.
Hình 1.8. Các giai đoạn phát triển AOP
3) Tổng hợp các thể hiện: sau khi các mối quan tâm nghiệp vụ chính và các mối
quan tâm cắt ngang được cài đặt một các riêng rẽ, để hệ thống có thể hoạt động được
thì các mối quan tâm cần phải được kết hợp theo một số quy tắc nào đó. Quá trình kết
hợp này gọi là quá trình tích hợp hay quá trình đan được thực hiện bằng cách sử dụng
các quy tắc đan. Sau quá trình đan ta nhận được hệ thống cuối cùng mà các mối quan
tâm nghiệp vụ chính và mối quan tâm cắt ngang đã được đan kết với nhau để thực hiện
mục tiêu theo yêu cầu. Ví dụ một luật tích hợp: “Tất cả các hoạt động của hệ thống cần
phải được lưu vết lại” sẽ được cài đặt trên một ngôn ngữ AOP nào đó để chỉ ra các quy
tắc đan. Như vậy, mối quan tâm lưu vết sẽ được bộ đan tích hợp vào các mô-đun
nghiệp vụ theo đúng quy tắc chỉ ra.
1.3.6. Lợi ích của lập trình hướng khía cạnh
AOP là một kỹ thuật mới đầy triển vọng, hứa hẹn đem lại nhiều lợi ích cho việc
phát triển phần mềm. Việc cấu trúc hóa các ứng dụng với các aspect và thực thi trực
tiếp bằng sử các ngôn ngữ lập trình hướng khía cạnh có khả năng cải thiện chất lượng
các hệ thống phần mềm. Các aspect tạo ra các hệ thống phần mềm lớn và phức tạp có
thể được sản xuất và tổ chức lại đơn giản hơn và cho chất lượng cao hơn. Dưới đây là
một số lợi ích chính của AOP:
Có thể nhận dạng và miêu tả một cách rõ ràng các mối quan tâm cắt ngang
giúp các kiến trúc sư có thể xem xét các hành vi cắt ngang dưới dạng các aspect tại
giai đoạn sớm của vòng đời dự án.
Phân chia trách nhiệm rõ ràng cho các mô-đun riêng lẻ: AOP cho phép tách
các mối quan tâm cắt ngang ra khỏi các mối quan tâm nghiệp vụ chính. Do vậy một
16
mô-đun chỉ nhận trách nhiệm với mối quan tâm nghiệp vụ chính của nó mà không cần
có nghĩa vụ gì với các mối quan tâm cắt ngang nó. Ví dụ như, một mô-đun thực hiện
một giao dịch nghiệp vụ chính và các thông tin thay đổi trong quá trình thực hiện giao
dịch phải được lưu lại thì nó chỉ cần quan tâm đến việc thực hiện giao dịch mà không
cần quan tâm đến thao tác lưu vết giao dịch. Việc lưu vết giao dịch sẽ được thực hiện
trong một aspect bằng AOP. Điều này giúp cho việc phân chia trách nhiệm rõ ràng hơn
và khả năng theo dõi được cải thiện.
Dễ dàng phát triển hệ thống: AOP mô-đun hóa các aspect riêng lẻ do đó khi
hệ thống cần chức năng mới, nhà phát triển chỉ cần tạo ra một aspect thực hiện các yêu
cầu mới đó mà không cần thay đổi các mô-đun nghiệp vụ chính. Khi thêm mô-đun
mới đó vào hệ thống, các aspect hiện có sẽ đan kết với chúng và tạo nên sự phát triển
chặt chẽ. Như vậy hệ thống sẽ đáp ứng nhanh hơn với những yêu cầu mới.
Tái sử dụng mã nguồn: AOP cho phép các nhà phát triển dễ dàng sử dụng lại
mã nguồn của một aspect trong nhiều thành phần và do đó giảm các nỗ lực thể hiện mã
chương trình.
Khả năng mô-đun hóa và đóng gói: AOP làm tăng tính mô-đun hóa và đóng
gói như mã thành phần tốt hơn ngắn gọn và gọn gàng.
Cho phép để lại quyết định thiết kế tương lai: Một thiết kế tốt phải tính đến cả
yêu cầu hiện tại và tương lai, việc xác định yêu cầu tương lai là một công việc khó
khăn. Nếu bỏ sót những yêu cầu tương lai có thể sẽ phải thay đổi hay thực hiện lại
nhiều phần hệ thống. Với AOP, người thiết kế hệ thống có thể để lại các quyết định
thiết kế cho những yêu cầu tương lai nhờ thực hiện theo các aspect riêng biệt.
Rút ngắn thời gian bàn giao sản phẩm: Việc kết nối muộn các giải pháp thiết
kế giúp cho chu trình thiết kế được nhanh hơn. Bên cạnh đó, việc tách biệt rõ ràng các
trách nhiệm của các mô-đun giúp cho người lập trình không gặp nhiều khó khăn trong
việc thực thi các mô-đun, từ đó tăng năng suất làm việc của các nhà lập trình. Việc tái
sử dụng mã nguồn tốt hơn giúp giảm thời gian phát triển hệ thống. Hơn thế nữa, hệ
thống tiến triển dễ dàng hơn giúp cho hệ thống có thể đáp ứng nhanh hơn với các yêu
cầu mới. Tất cả những điều trên giúp cho hệ thống có thể phát triển và triển khai nhanh
hơn.
Giảm thiểu chi phí thực thi: Bằng cách tránh việc sửa đổi nhiều mô-đun khi
phải cài đặt một chức năng cắt ngang, AOP giúp giảm chi phí cài đặt các chức năng
cắt ngang. Với AOP, các lập trình viên có thể tập trung vào các chức năng chính của
của các mô-đun nghiệp vụ và tận dụng được khả năng chuyên môn của họ vào các
công việc chính nên chi phí của các yêu cầu nghiệp vụ chính cũng được giảm xuống.
Như vậy, việc thực thi các chức năng của toàn hệ thống sẽ được giảm thiểu đáng kể.
17
1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh
Phương pháp lập trình hướng khía cạnh có nhiều ưu điểm kể trên, tuy nhiên nó
cũng có một số hạn chế sau:
Liệu các aspect có phá vỡ tính đóng gói của các đối tượng? Bình thường các
aspect tuân theo các luật điều khiển truy cập. Bằng cách này hay cách khác, các aspect
có thể phá vỡ tính đóng gói của các đối tượng. Nhưng chúng làm theo cách có thể
kiểm soát được. Các aspect có thể truy cập đến phần riêng tư của các đối tượng mà
chúng tham chiếu đến nhưng không làm tổn hại đến sự đóng gói giữa các đối tượng
của các lớp khác nhau. Ví dụ trong AspectJ, để bỏ qua các luật truy cập ta thêm bổ ngữ
đặc biệt privileged vào trước từ khóa aspect:
privileged aspect EmployeeVerifier {
pointcut verify_experience(Manager staff, int val):
target(staff)&& set(int Manager.experience)&& args(val);
void around(Manager staff, int val):
verify_experience(staff, val) {
if(val<3) {
System.out.println("Manager.experience>=3");
} else{
proceed(staff, val);
}
}
}
Trong ví dụ này, ta có thể truy cập đến thuộc tính experience của lớp Manager
cho dù nó có được bảo vệ bởi từ khóa private hoặc protected hay không.
Giảm hiệu suất thực thi trong trường hợp thực hiện đan kết lúc thực thi hoặc
tốn thời gian nạp chương trình trong trường hợp thực hiện đan kết lúc nạp chương
trình.
Khi chúng ta mắc sai lầm trong việc diễn đạt thực thi cắt ngang có thể gây lỗi
tràn ngập toàn chương trình.
Việc thay đổi các joint point của một chương trình (ví dụ như đổi tên hay di
chuyển các phương thức) mà không được lường trước bởi người viết aspect sẽ gây ra
các lỗi.
Vấn đề bảo mật có thể bị phá vỡ bởi việc sử dụng AOP để cài thêm các đoạn
mã tại các vị trí phù hợp.
18
1.3.8. Các công cụ AOP
Mô hình cơ sở của AOP là mô hình join point. Tất cả các công cụ dùng mô hình
này để cung cấp phương tiện nhận dạng nơi mà các mối quan tâm cắt ngang được áp
dụng. Tuy nhiên, các công cụ khác nhau thực hiện các mô hình aspect theo cách của
nó và đưa ra các ngữ nghĩa và kỹ thuật đan kết các aspect mới.
Ví dụ, trong JBoss AOP [27], các advice được thực thi thông qua bộ chặn
(interceptor) sử dụng Java reflection và các pointcut được khai báo trong một tập XML
mô tả nơi để đan kết trong một advice một cách tự động tại thời điểm thực thi. Trong
AspectJ, cả advice và pointcut được khai báo trong một lớp aspect và được đan kết
tĩnh.
Tính đa dạng này trong các công cụ AOP là khó giải quyết đối với phát triển
phần mềm sử dụng aspect vì sự khác nhau về ngữ nghĩa của các mô hình AOP và các
cách khác nhau một aspect được đan kết với các lớp khác. Khó có thể phát triển lại
một cách đơn giản một aspect đang tồn tại để nó có thể đan kết với các aspect được
phát triển bởi mô hình AOP khác.
Để giải quyết vấn đề này, AspectWerkz [28] đã đề xuất một mô hình kiến trúc
mở cho một bộ chứa aspect (aspect container) đối với các công cụ Java dựa trên AOP.
Ý tướng cơ bản là để cung cấp một bộ đan và một bộ chứa (container) có thể đan, triển
khai và chạy bất kỳ aspect không quan tâm đến việc nó được cài đặt và khai báo như
thế nào. Nó có trách nhiệm giải quyết sự khác nhau giữa các mô hình aspect. Một bể
chứa như vậy có thể cho phép các aspect được phát triển bởi các mô hình AOP và
công cụ khác nhau cùng tồn tại trong một môi trường thực thi. Hiện tại, AspectWerkz
đã thực hiện một mô hình mở rộng cho các aspect thực hiện các giao tiếp AOP
Alliance, Spring AOP [8, 24] và AspectJ [11, 13, 26].
Thiết kế và thực thi hướng khía cạnh đòi hỏi sự hỗ trợ của các công cụ AOP hiệu
quả. Với các công cụ này, các nghiên cứu và phát triển đang tiến hành đang cố gắng
cung cấp các giải pháp tốt hơn trong một số phạm vi như bảo trì, hiệu suất, tích hợp,
…
Bảo trì: việc thiết kế các hệ thống hướng khía cạnh chất lượng có nghĩa là chú
tâm đến việc định nghĩa các pointcut lan tỏa và việc sử dụng quyền thừa kế các aspect
một cách hợp lý. Các pointcut bắt giữ nhiều joint point hơn mong đợi hay bỏ xót các
joint point mong muốn có thể gây đổ vỡ hệ thống khi được cải tiến. Do vậy một công
cụ gỡ lỗi hiệu quả là cần thiết để dò tìm sự thực thi các joint point và các point cut lỗi.
Hiệu suất: việc sử dụng AOP tăng thêm các chi phí về hiệu suất trong các ứng
dụng, cả trong quá trình đan kết và tiềm tàng lúc thực thi. AOP cần giảm thời đan kết
và biên dịch đông thời tăng hiệu suất thực thi.
19
Tích hợp: việc sử dụng lại các aspect không được khám phá đầy đủ sẽ khiến
các các nhà phát triển các thư viện aspect từ các aspect bị lỗi. Mỗi công cụ AOP chỉ
cung cấp sự thực hiện các aspect cho mô hình của công cụ đó. Một aspect được thực
hiện bằng một mô hình AOP cụ thể không thể được đan kết một cách dễ dàng bằng
một mô hình AOP khác. Đây là chướng ngại vật lớn trong việc phát triển phần mềm
hướng khía cạnh.
1.4. AspectJ
Lập trình hướng khía cạnh là cách mô-đun hóa các mối quan tâm cắt ngang giống
như lập trình hướng đối tượng là cách để mô-đun hóa các mối quan tâm thông thường.
AspectJ [11, 13, 26] là một thực thi lập trình hướng đối tượng cho ngôn ngữ lập trình
Java. AspectJ mở rộng một số khái niệm của ngôn ngữ Java. Trình biên dịch AspectJ
sẽ biên dịch các từ khóa cụ thể của AspectJ thành byte-code và tạo điều kiện thuận lợi
cho việc đan kết các byte-code vào trong một tệp lớp (.class). Một aspect sẽ được biên
dịch thành mã aspect được chứa trong một lớp và các cấu trúc cụ thể khác của AspectJ
được chuyển đổi thành Java chuẩn. Trình biên dịch AspectJ đan kết aspect dưới dạng
byte-code vào trong byte-code của ứng dụng chính và tạo ra các tệp lớp Java phù hợp
có thể thực thi được bởi máy ảo Java.
Để thực hiện AOP bằng AspectJ nhà phát triển tách biệt hai phần: Phần đặc tả
ngôn ngữ và phần thực thi ngôn ngữ. Phần đặc tả ngôn ngữ định nghĩa ngôn ngữ viết
mã chương trình. Với AspectJ, các mối quan tâm nghiệp vụ chính được cài đặt trên
ngôn ngữ lập trình Java còn các mối quan tâm cắt ngang và các quy tắc đan được cài
đặt trên các mở rộng của AspectJ. Phần thực thi ngôn ngữ cung cấp các công cụ biên
dịch, gỡ lỗi và tích hợp với các môi trường phát triển tích hợp khác phổ biến [11, 13].
Trong AOP, công việc kết hợp (đan - weaving) mối quan tâm cắt ngang với các
mối quan tâm nghiệp vụ chính được thực hiện dựa trên các quy tắc đan. Các quy tắc
đan chỉ ra hành động nào được thực hiện khi một số điểm nào đó trong quá trình thực
thi chương trình xảy ra. Với AspectJ khi thực thi AOP, trình biên dịch AspectJ sử
dụng các mô-đun cài đặt các mối quan tâm cắt ngang chứa các quy tắc đan (các aspect)
để chèn thêm hành vi mới cho các mô-đun cài đặt các mối quan tâm nghiệp vụ chính
mà không cần thay đổi mã nguồn của các mô-đun nghiệp vụ chính. Việc đan mã
nguồn nghiệp vụ chính với các aspect chỉ thực hiện trong byte-code mà trình biên dịch
sinh ra.
1.4.1. Thực thi cắt ngang
Như ở phần trên đã trình bày về các loại đan kết. AspectJ hỗ trợ tất cả các loại
đan kết bao gồm đan kết lúc biên dịch (CTW), đan kết lúc nạp chương trình (LTW) và
đan kết lúc chương trình đang thực thi (RTW). Việc đan kết này còn được gọi là thực
thi cắt ngang (crosscutting). Việc đan kết phải tuân theo các quy tắc nhất định gọi là
các quy tắc đan. Các quy tắc đan này cắt ngang nhiều mô-đun một cách có hệ thống
20
nhằm mô-đun hóa các mối quan tâm cắt ngang. AspectJ định nghĩa ra hai loại thực thi
cắt ngang, đó là thực thi cắt ngang tĩnh (static crosscutting) và thực thi cắt ngang động
(dynamic crosscutting).
Thực thi cắt ngang tĩnh: là việc đan hay chèn thêm các sửa đổi vào trong một
lớp, giao diện hay aspect của hệ thống hoặc thay đổi tính thừa kế hay thực thi giao
diện của các lớp trong cây thừa kế. Thực thi cắt ngang tĩnh còn được sử dụng để khai
báo các cảnh báo và lỗi tại thời điểm biên dịch. Thông thường thực thi cắt ngang tĩnh
là để chuẩn bị hay hỗ trợ cho thực thi cắt ngang động.
Thực thi cắt ngang động: là việc đan hành vi mới vào quá trình thực thi của
chương trình. Việc đan hành vi mới theo cách cắt ngang nhiều môđun vì thế làm thay
đổi hành vi của hệ thống. Ví dụ muốn chèn thêm một hành động lưu vết sau khi lưu dữ
liệu vào cơ sở dữ liệu ta chỉ cần chỉ ra điểm đan là điểm sau thao tác lưu dữ liệu kết
thúc.
AspectJ sử dụng các cú pháp mở rộng cho ngôn ngữ lập trình Java để chỉ ra các
quy tắc đan cho việc thực thi cắt ngang động và thực thi cắt ngang tĩnh. Để thực hiện
các quy tắc đan một cách tự động, AspectJ sử dụng các cấu trúc và bộ mô tả sau để mô
tả việc cài đặt các mối quan tâm cắt ngang hệ thống như: Join point, point cut, advice,
introduction, chỉ thị biên dịch và aspect.
1.4.2. Joint Point
Bộ biên dịch AspectJ cần tìm các vị trí trong mã nguồn hoặc byte-code nơi mà
các hành vi mới được đan vào được thực thi. Những điểm có thể xác định đó được gọi
là các joint point. Đó có thể là một lời gọi đến một phương thức hoặc lệnh đọc hay gán
đối với một thành viên của một đối tượng.
Một số join point chính trong AspectJ như sau:
Joint point triệu gọi phương thức (Method call join point): xảy ra khi bất kỳ
lời gọi phương thức nào được thiết lập bởi một đối tượng hay một phương thức tĩnh.
Joint point này nằm trong một đối tượng hay ứng dụng triệu gọi phương thức, thường
là nằm trong các phương thức triệu gọi phương thức đang xét. Chúng ta xem xét ví dụ
sau:
ATMcard c=new ATMcard (0, 3000);
c.withdrawMoney(4000);//<--withdrawMoney() method call joint
point
Trong ví dụ này, một joint point triệu gọi phương thức được thiết lập tại vị trí
triệu gọi phương thức c.withdrawMoney(4000) đang xét.
Joint point triệu gọi phương thức khởi tạo (Constructor call joint point): xảy
ra khi một phương thức khởi tạo đối tượng được triệu gọi trong quá trình tạo mới một
21
đối tượng. Joint point này xảy ra bên trong đối tượng hay ứng dụng triệu gọi phương
phức khởi tạo đối tượng. Chúng ta xem xét đoạn mã sau:
ATMcard c = new ATMcard (0, 3000);
Trong ví dụ này, một joint point xảy ra khi lệnh new kích hoạt một joint point
triệu gọi phương thức.
Join point thực thi phương thức (Method execution joint point): xảy ra khi
một phương thức của một đối tượng được triệu và chuyển điều khiển cho phương thức
được triệu gọi đó. Joint point này xảy ra trên đối tượng nhận lời gọi phương thức và
trước khi các đoạn mã của phương thức được thực thi.
Joint point thực thi phương thức khởi tạo (Constructor execution joint point):
giống như joint point thực thi phương thức nhưng xảy ra trước khi đoạn mã khởi tạo
được thực thi.
Field get joint point: xảy ra khi một thuộc tính của một đối tượng được đọc,
tham chiếu hay lấy giá trị. Đoạn mã sau đây minh họa một field get joint point xảy ra
khi thuộc tính balanceAmount của lớp ATMCard được lấy giá trị:
class ATMCard {
int balanceAmount;
…
public void printAccountBalance(){
System.out.print(“Balance amount is “
+ balanceAmount // <-- field get joint point + …);
}
…
}
Field set joint point: xảy ra khi một thuộc tính của một đối tượng được gán
giá trị. Đoạn mã sau minh họa một field set joint point xảy ra khi thuộc tính
balanceAmount được gán giá trị mới:
class ATMCard {
int balanceAmount;
…
public void withdrawMoney(int amount){
balanceAmount-=amount; <-- field set joint point
}
…
22
}
Exception handler execution joint point: xảy ra khi một xử lý ngoại lệ được
thực thi.
Ngoài ra còn một số loại join point khác như: Class initialization join point,
Object initialization join point, Object pre-initialization join point, Advice execution
join point. Chi tiết các loại join point này có thể xem chi tiết trong các tài liệu [11, 13].
1.4.3. Pointcut
Pointcut là một cấu trúc chương trình lựa chọn ra một nhóm các join point và tập
hợp ngữ cảnh tại các join point này. Nó chỉ ra một cách trực tiếp một mối quan tâm sẽ
cắt ngang ứng dụng chính như thế nào. Pointcut hợp lệ ngang qua tất cả các đối tượng
được thể hiện từ các lớp và nếu bạn có một số lượng lớn các đối tượng, bạn nên lường
trước một số lượng lớn các so khớp. Pointcut dùng để chỉ ra các quy tắc đan còn join
point là các vị trí thỏa mãn các quy tắc đó.
Một bộ mô tả pointcut (pointcut designator) dùng để xác định pointcut bằng tên
hoặc bằng một biểu thức. Ta có thể khai báo một pointcut trong một aspect, một lớp
hoặc một giao diện. Giống như dữ liệu và phương thức, ta có thể sử dụng một định
danh phạm vi truy cập (public, private,...) để giới hạn quyền truy cập đến pointcut.
Định dạng tổng quát của pointcut như sau:
<pointcut> ::= <access_type> <pointcut_name> ({ <parameters> })
: { designator [ && | || ] };
<access_type> ::= public | private [abstract]
<pointcut_name> ::= { <identifier> }
<parameters> ::= { <identifier> <type> }
<designator> ::= [!]Call | execution | target | args |
cflow | cflowbelow | staticinitialization |
within | if | adviceexecution |
preinitialization
<identifier> ::= ký tự { ký tự | số }
<type> ::= kiểu Java hợp lệ
Chúng ta đặt pointcut vào bên trong một cấu trúc aspect và sử dụng nó để so
khớp các joint point trong mã. Kiểu truy cập của pointcut có thể là public hoặc private
(tùy thuộc vào các lưu ý thiết kế) và chỉ ra phạm vi của pointcut trong aspect/class.
Phạm vi truy cập mặc định là trong phạm vi gói (package) và do vậy chúng ta phải
cung cấp kiểu truy cập cụ thể cần thiết cho pointcut. Sau kiểu truy cập là tên của
pointcut. Tên này là chuỗi được sử dụng để biểu diễn pointcut bên trong aspect/class.
23
Tên tương tự như tên phương thức được sử dụng trong một lớp Java truyền thống. Bên
trong ngữ cảnh của một aspect hay class, tất cả các pointcut phải có một tên duy nhất,
điều đó có nghĩa là không nập chồng được pointcut trong AspectJ.
Tên của pointcut có thể chứa một số tham số. Các tham số này được sử dụng để
chuyển giao ngữ cảnh được kéo từ một joint point. Ngữ cảnh có thể được chuyển giao
tới một cấu trúc aspect hoặc các joint point khác.
Sau các tham số của pointcut là dấu hai chấm và một hoặc nhiều bộ mô tả
pointcut. Bộ mô tả cung cấp một định nghĩa xung quanh joint point được sử dụng
trong pointcut. Nếu một pointcut muốn có nhiều bộ mô tả, bạn phải sử dụng các toán
tử lôgic để tạo sự kết nối.
Java cũng cấp khả năng tạo các cấu trúc không được đặt tên hay nặc danh.
AspectJ cũng cung cấp khả năng này, trong một cấu trúc được gọi là pointcut nguyên
bản (primitive pointcut). Pointcut nguyên bản không có tên và chỉ bao gồm các bộ mô
tả joint point.
Như ta đã đề cập, pointcut lựa chọn một tập một hay nhiều joint point để xác định
hành động dự định của chúng. Khi joint point được đạt tới trong mã ứng dụng chính,
pointcut sẽ được kích hoạt và một số đoạn mã (advice) được thực thi tiềm tàng. Chúng
ta sẽ chỉ ra bộ miêu tả hành động như thế nào trong một ứng dụng AspectJ. Tất cả các
bộ mô tả được viết dưới định dạng sau:
designator ::= designator_identifier(<signature> |
<typePattern> | <pointcut>)
<designator_identifier> ::= Call | execution | target | args |
cflow | cflowbelow | staticinitialization |
within | if | adviceexecution |
preinitialization
<typePattern> ::= Kiểu lớp Java
<pointcut> - được định nghĩa ở trên
Tham số trong bộ miêu tả là một joint point signature hay một kiểu lớp joint point
hay một pointcut khác. Một joint point signature nhìn chung biểu diễn chữ ký
(signature) của một phương thức, một phương thức khởi tạo trong một lớp hay một
kiểu. Có thể có một số ký tự đại diện trong chữ ký. Trong trường hợp một joint point
khởi tạo phương thức, chữ ký bao gồm lời gọi hàm new(). Đối với một joint point kiểu
lớp, tham số là tên của một lớp trong ứng dụng. Chúng ta cũng có thể sử dụng các ký
tự đại diện với các kiểu lớp.
24
Để chỉ ra một nhóm các join point, phần chữ ký (signature) của pointcut chứa các
ký tự đại diện (wildcard) và các toán tử. Trong AspectJ, có 3 loại ký tự đại diện và 2
loại toán tử.
Ký tự đại diện:
“*”: Chỉ ra số lượng bất kỳ các ký tự trừ dấu chấm (“.”).
“..”: Chỉ ra số lượng bất kỳ các ký tự, chứa cả dấu chấm.
“+”: Chỉ ra bất kỳ lớp con hoặc giao diện con nào.
Toán tử:
Toán tử một ngôi: AspectJ chỉ cung cấp duy nhất một toán tử một ngôi “!”
cho point cut: Toán tử phủ định cho phép phù hợp tất cả các join point trừ join
point mà point cut chỉ ra bằng toán tử “!”.
Toán tử hai ngôi: “||” (Hoặc) và “&&” (Và) để kết nối các pointcut với nhau.
Hình 1.9 minh họa ví dụ về định nghĩa pointcut với tên accountOperations().
Point cut này sẽ nắm bắt toàn bộ các phương thức trong lớp Account.
Hình 1.9. Ví dụ về định nghĩa pointcut
Sau đây chúng tôi liệt kê các bộ mô tả pointcut một cách ngắn ngọn, chi tiết về
các bộ mô tả này có thể xem trong các tài liệu [11, 13]:
execution – So khớp sự thực thi của một phương thức hay một phương thức
khởi tạo. Ví dụ:
pointcut p(): execution(int ATMCard.withdrawMoney(..));
call – So khớp các lời gọi tới một phương thức hay một phương thức khởi tạo.
Ví dụ:
pointcut p(): call(int ATMCard.withdrawMoney(..));
initialization – So khớp sự thực thi của phương thức khởi tạo đầu tiên tới một
lớp. Ví dụ:
pointcut p() : initialization(ATMCard.new(..));
25
handler – So khớp các ngoại lệ. Ví dụ:
pointcut p() : handler(Throwable+);
get – So khớp sự tham chiếu tới một thuộc tính của lớp. Ví dụ:
pointcut p() : get(int ATMCard.accountBalance);
set – So khớp sự gán giá trị của một thuộc tính của lớp.
pointcut p() : set(int ATMCard.accountBalance);
this – Trả lại đối tượng liên kết với một joint point cụ thể. Ví dụ:
pointcut p() : this(ATMCard);
target – Trả lại đối tượng đích của một join point. Ví dụ:
pointcut p() : target(ATMCard);
args – Đặt các tham số cho các joint point. Ví dụ:
pointcut p() : args(int);
cflow – Trả lại các joint point trong luồng thực thi của một joint point khác.
Ví dụ:
pointcut p() : cflow(q());
pointcut q() : call(int ATMCard.withdrawMoney(..));
cflowbelow – Trả lại các joint point trong luồng thực thi của một join point
khác nhưng không bao gồm join point hiện tại. Ví dụ:
pointcut p() : cflowbelow(q());
pointcut q() : call(int ATMCard.withdrawMoney(..));
staticinitialization – So khớp sự thực thi của mã khởi tạo tĩnh của một lớp. Ví
dụ:
pointcut p() : staticinitialization(ATMCard);
withincode – So khớp các joint point bên trong một phương thức hay phương
thức khởi tạo. Ví dụ:
pointcut p(): withincode(int ATMCard.withdrawMoney(..));
within – So khớp các joint point bên trong một kiểu cụ thể. Ví dụ:
pointcut p(): within(ATMCard);
if – Cho phép một điều kiện động là một phần của một pointcut. Ví dụ:
pointcut p():
if( thisJoinPoint.getTarget() == null
26
&& thisJoinPoint.getThis() == null);
adviceexecution – So khớp trên các advice join point.
preinitialization – So khớp các joint point tiền khởi tạo.
1.4.4. Advice
Advice là một đoạn mã được thực thi tại một join point đã được lựa chọn bởi một
pointcut. Advice có thể được thực thi trước (before advice), sau (after advice) hoặc
“xung quanh” (around advice) join point. Around advice có thể chỉnh sửa đoạn mã tại
join point, nó có thể thay thế, thậm chí bỏ qua sự thực thi của đoạn mã đó. Sử dụng
advice, ta có thể đưa ra thông báo trước khi thực thi đoạn mã tại các điểm join point
xác định trên một vài mô-đun. Phần thân của advice gần giống với thân của phương
thức. Nó sẽ được thực thi khi một join point được so khớp.
Before advice: có dạng sau:
before(FormalParameters) : Pointcut {Body}
Thân của advice được thực thi trước khi joint point được chọn bới pointcut của
nó được đạt tới. Ta xét ví dụ sau:
public aspect AdviceBefore {
before() : call(* AdviceMain.*Str(..)) {
System.out.println(thisJoinPoint);
}
}
Trong ví dụ, advice không được đặt tên và chỉ được thực thi khi một pointcut
không tên chọn các lời gọi đối với các phương thức của lớp AdviceMain mà tên của nó
kết thúc bằng Str.
After advice: thân của advice này thực thi sau joint point tương ứng. Vấn đề là
không phải tất cả các trường hợp của after advice được tạo ra giống nhau. Để xác định
vấn đề này, AspectJ cung cấp ba phiên bản của after advcie: dạng đơn giản, dạng trả
lại giá trị (after returning advice), và dạng chỉ tương tác với các ngoại lệ (after
throwing advice).
Dạng đơn giản – luôn luôn chạy – có cú pháp giống như before advice
after(FormalParameters) : Pointcut {Body}
Ví dụ sau thực thi tương tự như AdviceBefore aspect nhưng chỉ sau khi các lời
gọi trở lại:
public aspect AdviceAfter {
after() : call(* AdviceMain.*Str(..)) {
27
System.out.println(thisJoinPoint);
}
}
After returning advice: chỉ chạy nếu đoạn mã tại các joint point thực thi bình
thường, không ném bất kỳ ngoài lệ nào. Cú pháp như sau:
after(FormalParameters) returning [(OneFormalParameter)]:
Pointcut {Body}
Ngoài các tham số được cung cấp bởi pointcut, advice có thêm một tham số. Nó
có thể có đối tượng được trả lại tại joint point nếu đối tượng đó được thể hiện bằng
việc cung cấp sự khai báo trực tiếp sau từ khóa returning. Ví dụ:
after() returning(Object o) : call(* AdviceMain.*Str(..)) {
System.out.println(“#1: “+thisJoinPoint+” Returning
Object: “+AdviceMain.className(o)+” - “+o);
}
After throwing advice: chạy một cách đúng đắn trong khi after returning advice
thì không khi có một ngoại lệ được ném tại joint point. Cú pháp cho phép ngoại lệ
được ném có trong thân của advice được đặt vào như các tham số hình thức khác. Cú
pháp như sau:
after(FormalParameters) throwing [(OneFormalParameter)]:
Pointcut {Body}
Sau đây là ví dụ về cách sử dụng after throwing advice:
after() throwing(Exception o): call(* AdviceMain.*Str(..)) {
System.out.println(“#1: “+thisJoinPoint+” Throwing
Exception: “+AdviceMain.className(o)+” - “+o);
}
Around advice: là một trong các đặc tính mạnh nhất của ngôn ngữ AspectJ.
Nó cho phép thay thế joint point bằng một đoạn mã tùy ý. Cú pháp như sau:
ReturnType around(FormalParameters) [throws
ListOfExceptionTypes]: Pointcut {Body}
Với around advice không nên ném các các ngoại lệ mà mã đích không thể xử lý
được. Bên trong thân của advice thường có một lời gọi đến hàm đặc biệt cho phép
around advice thực thi mã tại joint point gốc.
proceed(arguments);
Hàm proceed() có các tham số truyền vào là các tham số trong phần tên của
pointcut ứng với advice đó và kiểu giá trị trả về là kiểu đã được khai báo của advice.
28
Nếu không có các tham số trong pointcut, hàm proceed() không cần các tham số. Ví dụ
sử dụng hàm proceed() không có tham số:
Object around(): call(* AdviceMain.*Str(..)) {
Object result = proceed();
System.out.println(thisJoinPoint+” Result: “+
AdviceMain.className(result)+” - “+result);
return result;
}
và hàm proceed() có tham số:
Object around(String s):
call(* AdviceMain.*Str(String)) && args(s) {
Object result = proceed(s);
System.out.println(thisJoinPoint+” Parameter: [“ + s +
“] Result: “+AdviceMain.className(result)+” - “ +
result);
return result;
}
Thứ tự ưu tiên của advice: nếu hai hay nhiều advice cùng chia sẻ một joint
point, ta cần phải xem xét thứ tự ưu tiên thực hiện của các advice.
Đối với các advice giữa các aspect ta xác định thứ tự ưu tiên các advice như sau:
1) Khai báo thứ tự ưu tiên của các aspect bằng câu lệnh declare precedence. Ví
dụ sau nói lên rằng aspect A có thứ tự ưu tiên hơn aspect B.
declare precedence : A, B;
2) Nếu một aspect kế thừa một aspect khác thì advice trong aspect con nhận thứ
tự ưu tiên cao hơn advice trong aspect cha. Điều này cho phép aspect con ghi đè hành
vi của aspect cha.
3) Ngoài các trường hợp trên thì không xác định được thứ tự ưu tiên. Chúng sẽ
thực thi theo thứ tự không xác định.
Đối với các advice trong cùng một aspect thì thứ tự ưu tiên của chúng được xác
định bởi thứ tự và kiểu của chúng. Có hai tình huồng chính:
1) Nếu có một trong số advice là after advice thì advice được khai báo sau trong
tệp tin sẽ có thứ tự ưu tiên cao hơn.
29
2) Nếu không có advice nào là after advice thì advice nào được khai báo trước
trọng tệp tin sẽ có thứ tự ưu tiên cao hơn. Ví dụ có ba advice theo thứ tự sau:
Before1
Before2
After
Dựa vào luật 2 ta có Before1>Before2. Dựa vào luật 1 ta có After>Before1 và
After>Before2. Kết hợp hai kết quả trên ta có thứ tự ưu tiên như sau:
After > Before1 > Before2
Hiệu ứng của tính ưu tiên: tại một joint point cụ thể, advice được thực hiện
theo thứ tự ưu tiên.
Đoạn mã của around advice hiện tại có thể điều khiển việc có cho phép advice có
thứ tự ưu tiên thấp hơn chạy hay không. Để cho phép advice có độ ưu tiên thấp hơn
chạy bằng việc gọi hàm proceed(). Lời gọi đến hàm proceed() sẽ chạy advice có thứ tự
ưu tiên tiếp theo hoặc tính toán tại joint point nếu không có adviec nào nữa.
Đoạn mã của before advice có thể ngăn advice có thứ tự ưu tiên thấp hơn chạy
bằng việc ném một ngoại lệ. Nếu nó chạy bình thường mà không ném ngoại lệ thì
advice có thứ tự ưu tiên kế tiếp sẽ chạy hoặc tính toán tại joint point nếu không có
advice nào nữa.
Việc chạy after returning advice sẽ chạy advice có thứ tự ưu tiên tiếp theo hoặc
tính toán tại joint point nếu không có advice nào nữa. Sau đó nếu việc tính toán trả về
bình thường, thân của advice sẽ chạy.
Việc chạy after throwing advice sẽ chạy advice có độ ưu tiên tiếp theo hoặc tính
toán tại joint point nếu không có advice nào nữa. Sau đó nếu sự tính toán ném một
ngoại lệ có kiểu thích hợp, thân của advice sẽ chạy.
Việc chạy after advice sẽ chạy advice có thứ tự ưu tiên tiếp theo hoặc tính toán tại
joint point nếu không có advice nào nữa. Sau đó thân của advice sẽ chạy.
1.4.5. Introduction
Một introduction là kỹ thuật của AspectJ nhằm sửa đổi các lớp và thứ bậc của
chúng bằng việc đưa vào hay chèn mã mới vào một lớp đích của một ứng dụng, hay
bằng việc thay đổi tính thừa kế hay thực thi giao diện của một lớp hay tập các lớp.
Thông thường advice dùng để thực thi cắt ngang động, introduction dùng để thực thi
cắt ngang tĩnh và được đan kết hay thực thi tại thời điểm biên dịch.
Introduction có thể được sử dụng để:
1) Thêm các biến dữ liệu (hay thuộc tính mới) vào một lớp:
private int StockClient.numberOfStocks = 0;
30
Câu lệnh này thêm một thuộc tính mới có tên là numberOfStocks, kiểu integer và
được khởi tạo giá trị ban đầu bằng 0 vào lớp StockClient. Tên của thuộc tính mới được
thêm vào này phải không được trùng với tên các thuộc tính đã có. Điều này có nghĩa là
việc đặt tên cho nó cũng phải tuân theo một quy ước đặt tên để tránh xung đột trong
quá trình thực thi.
2) Thêm các phương thức vào một lớp:
public StockClient.new(String message);
Câu lệnh này đưa một phương thức khởi tạo mới vào lớp StockClient. Câu lệnh
sau thêm một phương thức mới có tên là getClientStock() vào lớp StockClient:
public StockClient.getClientStock(){
return numberOfStocks;
}
3) Thay đổi sự thừa kế hay thứ bậc giao diện của một lớp:
declare parents: StockClient implements newServiceInterface;
declare parents: StockClient extends Frame;
Hai câu lệnh này làm cho lớp StockClient thực hiện giao diện có tên là
newServiceInterface và kế thừa (extend) lớp có tên là Frame tương ứng.
4) Thêm cảnh báo hay lỗi: AspectJ cung cấp khả năng dò tìm một số pointcut tại
thời điểm biên dịch và sinh ra một lỗi hoặc cảnh báo. Một cảnh báo hướng trình biên
dịch đưa ra thông báo và vẫn tiếp tục quá trình biên dịch. Ngược lại với một lỗi, trình
biên dịch sẽ đưa ra một thông báo và dừng quá trình biên dịch. Cú pháp như sau:
declare warning : Pointcut : String;
declare error : Pointcut : String;
Trong đó String là chuỗi thông báo lỗi, Pointcut là bộ mô tả Pointcut. Những
pointcut này sẽ định vị các joint point trong mã nguồn tương ứng với các điểm khi
chương trình thực thi. Ví dụ aspect SCError dừng quá trình biên dịch chương trình khi
hàm khởi tạo của lớp SCMain được thực thi và sinh ra thông báo lỗi:
public aspect SCError {
declare error: execution(SCMain.new(..)): “Constructor
executed!”;
}
1.4.6. Aspect
AspectJ sử dụng từ khóa aspect để biểu thị một cấu trúc được thiết kế để đóng gói
tất cả các đoạn mã cần thiết để thực thi một mối quan tâm cắt ngang giống như từ khóa
class trong Java dùng để đóng gói một lớp. Cấu trúc được đóng gói đó được gọi là một
31
aspect. Tất cả các pointcut, advice và introduction đều được đóng gói bằng việc sử
dụng từ khóa aspect. Không có aspect, đoạn mã phục vụ cho việc thực thi một mối
quan tâm cắt ngang rất có thể sẽ đóng góp vào vấn đề lộn xộn mã nguồn mà chúng ta
đang cố gắng giải quyết.
Như vậy, các aspect là các đơn vị chủ yếu của các thực thi cắt ngang. Chúng
giống các lớp trong nhiều khía cạnh, nhưng sự khác nhau quan trọng nhất là các aspect
có thể gây ảnh hưởng và sửa đổi các lớp. Bảng sau tóm tắt những điểm giống và khác
nhau giữa aspect và lớp:
Bảng 1.1. So sánh giữa aspect và lớp
1 Chỉ các aspect trừu tượng mới được kế thừa
2 Phải được khai báo tĩnh (static)
Cấu trúc của aspect:
Một aspect giống và hoạt động gần giống một lớp Java bởi việc cung cấp một bộ
chứa cho sự đóng gói các mã pointcut, advice và introduction. Aspect có thể chứa các
thuộc tính của nó, các phương thức, các thành viên lớp lồng nhau giống như một lớp
bình thường trong Java để hỗ trợ thêm tính hướng đối tượng bên trong các mối quan
tâm mà aspect đại diện.
Dạng của một aspect như sau:
aspect ::= <access> [privilege] [static] aspect <identifier>
<class identifier><instantiation>
<access> ::= public | private [abstract]
<identifier> ::= letter { letter | digit }
<class identifier> ::= [dominates] [extends]
<instantiation> ::= [issingleton | perthis | pertarget |
percflow | perflowbelow]
Đặc điểm Lớp Aspect
Có thể thể hiện hóa trực tiếp Có Không
Có thể kế thừa các lớp Có Có
Có thể thực thi các giao diện Có Có
Có thể có các định danh truy cập Có Có
Có thể thừa kế các aspect Không Có1
Có thể được khai báo trong lớp, giao diện Yes Yes2
32
{
//pointcuts
//advice
//methods/attributes
}
Sau đây là một ví dụ về việc cài đặt một aspect:
public aspect ATMcardVerifier
{
pointcut checkwithdrawalAmount(ATMcard card, int amount):
call(* ATMcard.withdrawMoney(..)) &&
target(card) && args(amount);
void around(ATMcard card, int amount):
checkwithdrawalAmount(card, amount) {
if(amount<50) {
System.out.println(“withdrawal amount>=50”);
} else {
proceed(card, amount);
}
}
}
Aspect trên cài đặt một poitcut và một around advice dùng để kiểm tra số tiền rút
qua tham số hình thức amount của hàm withdrawMoney(int amount). Trước khi thực
hiện lệnh rút aspect sẽ kiểm tra nếu số tiền rút nhỏ hơn $50 thì đưa ra thông báo và
không cho thực hiện lệnh rút.
Tính kế thừa của aspect:
Trong AspectJ, giống như lớp, aspect có thể thừa kế lớp, thực thi giao diện và
thừa kế aspect trừu tượng khác. AspectJ thực hiện các luật thừa kế của các aspect như
đối với các lớp. Các pointcut và advice của aspect cha sẽ được aspect con thừa kế.
Ngoài ra, các pointcut được khai báo là trừu tượng sẽ bị ghi đè bởi pointcut tương ứng
ở lớp con.
Chú ý: Đối với các advice cùng chia sẻ một joint point thì advice ở aspect con có
thứ tự ưu tiên cao hơn advice ở aspect cha.
33
1.5. Kết luận
Trong chương này chúng tôi trình bày về phương pháp lập trình hướng khía cạnh
AOP, một kỹ thuật lập trình để đóng gói các mối quan tâm cắt ngang nhằm tách biệt
các mối quan tâm cắt ngang với các mối quan tâm nghiệp vụ chính. Phương pháp lập
trình này giúp cho việc thiết kế kiến trúc hệ thống, thực thi và bảo trì hệ thống được dễ
dàng hơn.
Chương này cũng trình bày chi tiết về AspectJ, một đặc tả ngôn ngữ AOP được
cài đặt phổ biến cho ngôn ngữ lập trình Java. Ở các phần sau chúng tôi sử dụng
AspectJ để cài đặt các aspect để kiểm chứng các bất biến đối tượng trong chương trình
hướng đối tượng Java.
34
Chương 2 - Công cụ kiểm chứng mô hình Java PathFinder
2.1. Giới thiệu
Công nghệ thông tin ngày càng phát triển, các hệ thống phần mềm càng ngày
càng phức tạp và phát triển nhanh chóng. Vì vậy chúng càng dễ có nhiều lỗi hơn. Số
lượng lỗi được phát hiện tăng theo cấp số nhân với số lượng tương tác giữa các thành
phần của hệ thống, đặc biệt trong các hệ thống tương tranh.
Trong các hệ thống phần mềm phức tạp, thời gian và công sức dành cho kiểm
chứng phần mềm ngày càng nhiều hơn so với việc viết phần mềm. Các kỹ thuật được
tìm kiếm để làm giảm và đơn giản hóa các công việc kiểm chứng. Các phương pháp
hình thức mở ra một tiềm năng lớn để đạt được sự tích hợp kiểm chứng trong quy trình
thiết kế, cung cấp các kỹ thuật kiểm chứng hiệu quả hơn và làm giảm thời gian kiểm
chứng.
Các kỹ thuật kiểm chứng hệ thống đang được áp dụng để thiết kế các hệ thống
phần mềm ngày càng trở nên đáng tin cậy hơn. Kiểm chứng mô hình [5] là một kỹ
thuật tự động để kiểm chứng các hệ thống tương tranh hữu hạn trạng thái được phát
triển độc lập bởi Clarke và Emerson tại Mỹ và Queille và Sifakis tại Pháp vào những
năm 1980. Kiểm chứng mô hình được chia làm 2 loại: Kiểm chứng mô hình phần cứng
và kiểm chứng mô hình phần mềm. Trong luận văn này, chúng tôi sẽ chỉ đề cập đến
kiểm chứng mô hình phần mềm.
Trong khi việc kiểm chứng mô hình phần mềm về lý thuyết nghe có vẻ là phương
pháp kiểm chứng an toàn và mạnh, thực tế chỉ ra rằng nó không thực sự mạnh. Để làm
cho phương pháp này thực tế hơn, một công cụ kiểm chứng mô hình phải tận dụng các
giải pháp kinh nghiệm và trừu tượng hóa trạng thái linh hoạt. Java PathFinder (JPF)
[19, 25, 30, 31] là công cụ độc nhất vô nhị về khả năng cấu hình và khả năng mở rộng
và vì vậy nó là một nền tảng tốt để khám phá các cách mới để cải thiện hiệu năng.
2.2. Công cụ kiểm chứng mô hình Java PathFinder
Java PathFinder (JPF) [19, 25, 30, 31] là một hệ thống để kiểm chứng mã thực thi
bytecode của các chương trình Java. Ở dạng đơn giản, nó là một máy ảo Java được sử
dụng như một công cụ kiểm chứng mô hình trạng thái phần mềm tường minh, khảo sát
tất cả các đường thực thi tiềm năng của một chương trình để tìm ra các vi phạm của
các thuộc tính như khóa chết (deadlock) hay các ngoại lệ không được xử lý (unhanled
exceptions). Không giống như các công cụ gỡ lỗi truyền thống, JPF thông báo đầy đủ
đường thực thi dẫn đến một một lỗi. JPF đặc biệt rất phù hợp cho việc tìm kiếm các lỗi
rất khó kiểm thử trong các chương trình đa luồng.
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf
Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf

More Related Content

Similar to Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf

Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdfNghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
Man_Ebook
 

Similar to Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf (20)

Luận văn: Yếu tố ảnh hưởng đến tiến độ hoàn thành dự án phần mềm tại các công...
Luận văn: Yếu tố ảnh hưởng đến tiến độ hoàn thành dự án phần mềm tại các công...Luận văn: Yếu tố ảnh hưởng đến tiến độ hoàn thành dự án phần mềm tại các công...
Luận văn: Yếu tố ảnh hưởng đến tiến độ hoàn thành dự án phần mềm tại các công...
 
Các Nhân Tố Ảnh Hưởng Đến Quyết Định Mua Bảo Hiểm Tại Công Ty
Các Nhân Tố Ảnh Hưởng Đến Quyết Định Mua Bảo Hiểm Tại Công TyCác Nhân Tố Ảnh Hưởng Đến Quyết Định Mua Bảo Hiểm Tại Công Ty
Các Nhân Tố Ảnh Hưởng Đến Quyết Định Mua Bảo Hiểm Tại Công Ty
 
Đề tài: Mô hình hóa và khảo sát sai số của robot công nghiệp, HOT
Đề tài: Mô hình hóa và khảo sát sai số của robot công nghiệp, HOTĐề tài: Mô hình hóa và khảo sát sai số của robot công nghiệp, HOT
Đề tài: Mô hình hóa và khảo sát sai số của robot công nghiệp, HOT
 
Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệm trong họ...
Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệm trong họ...Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệm trong họ...
Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệm trong họ...
 
Luận văn: Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệ...
Luận văn: Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệ...Luận văn: Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệ...
Luận văn: Rèn luyện cho sinh viên kỹ năng thiết kế và sử dụng thí nghiệ...
 
Luận văn: Thiết kế và sử dụng bài tập thực nghiệm hóa học lớp 10 trong dạy họ...
Luận văn: Thiết kế và sử dụng bài tập thực nghiệm hóa học lớp 10 trong dạy họ...Luận văn: Thiết kế và sử dụng bài tập thực nghiệm hóa học lớp 10 trong dạy họ...
Luận văn: Thiết kế và sử dụng bài tập thực nghiệm hóa học lớp 10 trong dạy họ...
 
Phát triển dịch vụ hỗ trợ quản lý chứng chỉ định giá đất ứng dụng công nghệ c...
Phát triển dịch vụ hỗ trợ quản lý chứng chỉ định giá đất ứng dụng công nghệ c...Phát triển dịch vụ hỗ trợ quản lý chứng chỉ định giá đất ứng dụng công nghệ c...
Phát triển dịch vụ hỗ trợ quản lý chứng chỉ định giá đất ứng dụng công nghệ c...
 
Luận văn thạc sĩ
Luận văn thạc sĩLuận văn thạc sĩ
Luận văn thạc sĩ
 
Nhận diện, đo lường văn hóa tổ chức tại Ngân hàng TMCP Sài Gòn Thương tín
Nhận diện, đo lường văn hóa tổ chức tại Ngân hàng TMCP Sài Gòn Thương tín Nhận diện, đo lường văn hóa tổ chức tại Ngân hàng TMCP Sài Gòn Thương tín
Nhận diện, đo lường văn hóa tổ chức tại Ngân hàng TMCP Sài Gòn Thương tín
 
Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdfNghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
Nghiên Cứu Kỹ Thuật Kiểm Thử Phần Mềm Và Ứng Dụng Trên Môi Trường DOT NET.pdf
 
Thiết kế, chế tạo thiết bị đo và cảnh báo nồng độ cồn trong hơi thở
Thiết kế, chế tạo thiết bị đo và cảnh báo nồng độ cồn trong hơi thởThiết kế, chế tạo thiết bị đo và cảnh báo nồng độ cồn trong hơi thở
Thiết kế, chế tạo thiết bị đo và cảnh báo nồng độ cồn trong hơi thở
 
Luận văn: Phân tích các yếu tố ảnh hưởng đến lòng trung thành của khách hàng
Luận văn: Phân tích các yếu tố ảnh hưởng đến lòng trung thành của khách hàngLuận văn: Phân tích các yếu tố ảnh hưởng đến lòng trung thành của khách hàng
Luận văn: Phân tích các yếu tố ảnh hưởng đến lòng trung thành của khách hàng
 
Luận án: Đánh giá năng lực giải quyết vấn đề của học sinh trong dạy học Toán ...
Luận án: Đánh giá năng lực giải quyết vấn đề của học sinh trong dạy học Toán ...Luận án: Đánh giá năng lực giải quyết vấn đề của học sinh trong dạy học Toán ...
Luận án: Đánh giá năng lực giải quyết vấn đề của học sinh trong dạy học Toán ...
 
Hiệu suất của mạng cảm biến không dây cho giám sát sức khỏe
Hiệu suất của mạng cảm biến không dây cho giám sát sức khỏeHiệu suất của mạng cảm biến không dây cho giám sát sức khỏe
Hiệu suất của mạng cảm biến không dây cho giám sát sức khỏe
 
Luận văn: An toàn giao thức định tuyến trong mạng manet, HOT
Luận văn: An toàn giao thức định tuyến trong mạng manet, HOTLuận văn: An toàn giao thức định tuyến trong mạng manet, HOT
Luận văn: An toàn giao thức định tuyến trong mạng manet, HOT
 
Luận văn: Nâng cao năng lực giải quyết vấn đề cho học sinh phổ thông qua dạy ...
Luận văn: Nâng cao năng lực giải quyết vấn đề cho học sinh phổ thông qua dạy ...Luận văn: Nâng cao năng lực giải quyết vấn đề cho học sinh phổ thông qua dạy ...
Luận văn: Nâng cao năng lực giải quyết vấn đề cho học sinh phổ thông qua dạy ...
 
Phân lập và tuyển chọn vi khuẩn phản nitrate chịu mặn xử lý nitơ trong nước t...
Phân lập và tuyển chọn vi khuẩn phản nitrate chịu mặn xử lý nitơ trong nước t...Phân lập và tuyển chọn vi khuẩn phản nitrate chịu mặn xử lý nitơ trong nước t...
Phân lập và tuyển chọn vi khuẩn phản nitrate chịu mặn xử lý nitơ trong nước t...
 
Khóa luận Đánh giá hiện trạng môi trường nước thải tại Bệnh Viện Đa Khoa Tỉnh...
Khóa luận Đánh giá hiện trạng môi trường nước thải tại Bệnh Viện Đa Khoa Tỉnh...Khóa luận Đánh giá hiện trạng môi trường nước thải tại Bệnh Viện Đa Khoa Tỉnh...
Khóa luận Đánh giá hiện trạng môi trường nước thải tại Bệnh Viện Đa Khoa Tỉnh...
 
Đề tài thực tập: Quy trình phục vụ tại phòng (khách sạn), HAY, 9 điểm!
Đề tài thực tập: Quy trình phục vụ tại phòng (khách sạn), HAY, 9 điểm!Đề tài thực tập: Quy trình phục vụ tại phòng (khách sạn), HAY, 9 điểm!
Đề tài thực tập: Quy trình phục vụ tại phòng (khách sạn), HAY, 9 điểm!
 
Luận án: Nghiên cứu phát hiện mẫu chất liệu trong ảnh, HAY
Luận án: Nghiên cứu phát hiện mẫu chất liệu trong ảnh, HAYLuận án: Nghiên cứu phát hiện mẫu chất liệu trong ảnh, HAY
Luận án: Nghiên cứu phát hiện mẫu chất liệu trong ảnh, HAY
 

More from TieuNgocLy

More from TieuNgocLy (20)

THI HÀNH ÁN HÌNH SỰ TỪ THỰC TIỄN TỈNH PHÚ THỌ.pdf
THI HÀNH ÁN HÌNH SỰ TỪ THỰC TIỄN TỈNH PHÚ THỌ.pdfTHI HÀNH ÁN HÌNH SỰ TỪ THỰC TIỄN TỈNH PHÚ THỌ.pdf
THI HÀNH ÁN HÌNH SỰ TỪ THỰC TIỄN TỈNH PHÚ THỌ.pdf
 
Cách trưng bày và bố trí sản phẩm của circle k tại Việt Nam 9870993.pdf
Cách trưng bày và bố trí sản phẩm của circle k tại Việt Nam 9870993.pdfCách trưng bày và bố trí sản phẩm của circle k tại Việt Nam 9870993.pdf
Cách trưng bày và bố trí sản phẩm của circle k tại Việt Nam 9870993.pdf
 
HẠ THÂN NHIỆT ĐIỀU TRỊ TRONG NGỪNG TUẦN HOÀN- THỰC TẾ TẠI VIỆT NAM.pdf
HẠ THÂN NHIỆT ĐIỀU TRỊ TRONG NGỪNG TUẦN HOÀN- THỰC TẾ TẠI VIỆT NAM.pdfHẠ THÂN NHIỆT ĐIỀU TRỊ TRONG NGỪNG TUẦN HOÀN- THỰC TẾ TẠI VIỆT NAM.pdf
HẠ THÂN NHIỆT ĐIỀU TRỊ TRONG NGỪNG TUẦN HOÀN- THỰC TẾ TẠI VIỆT NAM.pdf
 
BÁO CHÍ VỚI VẤN ĐỀ “GIẢI CỨU NÔNG SẢN” CHO NÔNG DÂN - Luận văn Thạc sĩ chuyên...
BÁO CHÍ VỚI VẤN ĐỀ “GIẢI CỨU NÔNG SẢN” CHO NÔNG DÂN - Luận văn Thạc sĩ chuyên...BÁO CHÍ VỚI VẤN ĐỀ “GIẢI CỨU NÔNG SẢN” CHO NÔNG DÂN - Luận văn Thạc sĩ chuyên...
BÁO CHÍ VỚI VẤN ĐỀ “GIẢI CỨU NÔNG SẢN” CHO NÔNG DÂN - Luận văn Thạc sĩ chuyên...
 
现代汉语广告中的成语研究 = Nghiên cứu thành ngữ trong ngôn ngữ quảng cáo của tiếng Hán hi...
现代汉语广告中的成语研究 = Nghiên cứu thành ngữ trong ngôn ngữ quảng cáo của tiếng Hán hi...现代汉语广告中的成语研究 = Nghiên cứu thành ngữ trong ngôn ngữ quảng cáo của tiếng Hán hi...
现代汉语广告中的成语研究 = Nghiên cứu thành ngữ trong ngôn ngữ quảng cáo của tiếng Hán hi...
 
Nghiên cứu hệ thống chống bó cứng phanh trên xe mazda CX 5 2013.pdf
Nghiên cứu hệ thống chống bó cứng phanh trên xe mazda CX 5 2013.pdfNghiên cứu hệ thống chống bó cứng phanh trên xe mazda CX 5 2013.pdf
Nghiên cứu hệ thống chống bó cứng phanh trên xe mazda CX 5 2013.pdf
 
Chức Năng Hoạch Định Quản Trị Học.pdf
Chức Năng Hoạch Định Quản Trị Học.pdfChức Năng Hoạch Định Quản Trị Học.pdf
Chức Năng Hoạch Định Quản Trị Học.pdf
 
NHẬN THỨC VỀ YẾU TỐ NGUY CƠ VÀ BIỂU HIỆN CẢNH BÁO ĐỘT QỤY NÃO CỦA NGƯỜI BỆNH ...
NHẬN THỨC VỀ YẾU TỐ NGUY CƠ VÀ BIỂU HIỆN CẢNH BÁO ĐỘT QỤY NÃO CỦA NGƯỜI BỆNH ...NHẬN THỨC VỀ YẾU TỐ NGUY CƠ VÀ BIỂU HIỆN CẢNH BÁO ĐỘT QỤY NÃO CỦA NGƯỜI BỆNH ...
NHẬN THỨC VỀ YẾU TỐ NGUY CƠ VÀ BIỂU HIỆN CẢNH BÁO ĐỘT QỤY NÃO CỦA NGƯỜI BỆNH ...
 
HỘI THẢO CƠ CHẾ CHÍNH SÁCH CUNG ỨNG DỊCH VỤ CÔNG ÍCH TẠI CÁC ĐÔ THỊ Ở VIỆT NA...
HỘI THẢO CƠ CHẾ CHÍNH SÁCH CUNG ỨNG DỊCH VỤ CÔNG ÍCH TẠI CÁC ĐÔ THỊ Ở VIỆT NA...HỘI THẢO CƠ CHẾ CHÍNH SÁCH CUNG ỨNG DỊCH VỤ CÔNG ÍCH TẠI CÁC ĐÔ THỊ Ở VIỆT NA...
HỘI THẢO CƠ CHẾ CHÍNH SÁCH CUNG ỨNG DỊCH VỤ CÔNG ÍCH TẠI CÁC ĐÔ THỊ Ở VIỆT NA...
 
Nghiên cứu quá trình thụ đắc từ li hợp trong tiếng Hán hiện đại của sinh viên...
Nghiên cứu quá trình thụ đắc từ li hợp trong tiếng Hán hiện đại của sinh viên...Nghiên cứu quá trình thụ đắc từ li hợp trong tiếng Hán hiện đại của sinh viên...
Nghiên cứu quá trình thụ đắc từ li hợp trong tiếng Hán hiện đại của sinh viên...
 
Báo Cáo Thực Tập Tốt Nghiệp Thông Tin Vô Tuyến, Chuyển Mạch Và Thông Tin Quan...
Báo Cáo Thực Tập Tốt Nghiệp Thông Tin Vô Tuyến, Chuyển Mạch Và Thông Tin Quan...Báo Cáo Thực Tập Tốt Nghiệp Thông Tin Vô Tuyến, Chuyển Mạch Và Thông Tin Quan...
Báo Cáo Thực Tập Tốt Nghiệp Thông Tin Vô Tuyến, Chuyển Mạch Và Thông Tin Quan...
 
HIỆP ĐỊNH THÀNH LẬP KHU VỰC THƯƠNG MẠI TỰ DO ASEAN – ÚC – NIU DILÂN (AANZFTA)...
HIỆP ĐỊNH THÀNH LẬP KHU VỰC THƯƠNG MẠI TỰ DO ASEAN – ÚC – NIU DILÂN (AANZFTA)...HIỆP ĐỊNH THÀNH LẬP KHU VỰC THƯƠNG MẠI TỰ DO ASEAN – ÚC – NIU DILÂN (AANZFTA)...
HIỆP ĐỊNH THÀNH LẬP KHU VỰC THƯƠNG MẠI TỰ DO ASEAN – ÚC – NIU DILÂN (AANZFTA)...
 
Những vấn đề pháp lý về chống bán phá giá hàng hóa nhập khẩu vào Việt Nam.pdf
Những vấn đề pháp lý về chống bán phá giá hàng hóa nhập khẩu vào Việt Nam.pdfNhững vấn đề pháp lý về chống bán phá giá hàng hóa nhập khẩu vào Việt Nam.pdf
Những vấn đề pháp lý về chống bán phá giá hàng hóa nhập khẩu vào Việt Nam.pdf
 
Pháp luật về quản lý chất thải nguy hại trong khu công nghiệp ở Việt Nam.pdf
Pháp luật về quản lý chất thải nguy hại trong khu công nghiệp ở Việt Nam.pdfPháp luật về quản lý chất thải nguy hại trong khu công nghiệp ở Việt Nam.pdf
Pháp luật về quản lý chất thải nguy hại trong khu công nghiệp ở Việt Nam.pdf
 
Thiết Kế Hệ Thống Cung Cấp Điện Cho Tòa Nhà Cao Tầng Có Ứng Dụng Các Phương P...
Thiết Kế Hệ Thống Cung Cấp Điện Cho Tòa Nhà Cao Tầng Có Ứng Dụng Các Phương P...Thiết Kế Hệ Thống Cung Cấp Điện Cho Tòa Nhà Cao Tầng Có Ứng Dụng Các Phương P...
Thiết Kế Hệ Thống Cung Cấp Điện Cho Tòa Nhà Cao Tầng Có Ứng Dụng Các Phương P...
 
Bài Giảng Chứng Khoán Phái Sinh.pdf
Bài Giảng Chứng Khoán Phái Sinh.pdfBài Giảng Chứng Khoán Phái Sinh.pdf
Bài Giảng Chứng Khoán Phái Sinh.pdf
 
Hội Thảo, Tập Huấn, Rút Kinh Nghiệm Dạy Học Theo Mô Hình Trường Học Mới Việt ...
Hội Thảo, Tập Huấn, Rút Kinh Nghiệm Dạy Học Theo Mô Hình Trường Học Mới Việt ...Hội Thảo, Tập Huấn, Rút Kinh Nghiệm Dạy Học Theo Mô Hình Trường Học Mới Việt ...
Hội Thảo, Tập Huấn, Rút Kinh Nghiệm Dạy Học Theo Mô Hình Trường Học Mới Việt ...
 
Intangible Values in Financial Accounting and Reporting An Analysis from the ...
Intangible Values in Financial Accounting and Reporting An Analysis from the ...Intangible Values in Financial Accounting and Reporting An Analysis from the ...
Intangible Values in Financial Accounting and Reporting An Analysis from the ...
 
Bài Giảng Các Phương Pháp Dạy Học Hiện Đại.pdf
Bài Giảng Các Phương Pháp Dạy Học Hiện Đại.pdfBài Giảng Các Phương Pháp Dạy Học Hiện Đại.pdf
Bài Giảng Các Phương Pháp Dạy Học Hiện Đại.pdf
 
Những Kiến Thức Cơ Bản Của Tâm Lý Học Lứa Tuổi Và Tâm Lý Học Sư Phạm.pdf
Những Kiến Thức Cơ Bản Của Tâm Lý Học Lứa Tuổi Và Tâm Lý Học Sư Phạm.pdfNhững Kiến Thức Cơ Bản Của Tâm Lý Học Lứa Tuổi Và Tâm Lý Học Sư Phạm.pdf
Những Kiến Thức Cơ Bản Của Tâm Lý Học Lứa Tuổi Và Tâm Lý Học Sư Phạm.pdf
 

Recently uploaded

sách các Bài tập kinh tế vi mô chọn lọc.
sách các Bài tập kinh tế vi mô chọn lọc.sách các Bài tập kinh tế vi mô chọn lọc.
sách các Bài tập kinh tế vi mô chọn lọc.
TunQuc54
 
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
LinhV602347
 
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜICHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
nguyendoan3122102508
 

Recently uploaded (20)

Báo cáo thực tập tốt nghiệp Kế toán tiền mặt tại Công ty trách nhiệm hữu hạn ...
Báo cáo thực tập tốt nghiệp Kế toán tiền mặt tại Công ty trách nhiệm hữu hạn ...Báo cáo thực tập tốt nghiệp Kế toán tiền mặt tại Công ty trách nhiệm hữu hạn ...
Báo cáo thực tập tốt nghiệp Kế toán tiền mặt tại Công ty trách nhiệm hữu hạn ...
 
Báo cáo tốt nghiệp Phát triển sản phẩm thẻ tại Ngân hàng thương mại cổ phần K...
Báo cáo tốt nghiệp Phát triển sản phẩm thẻ tại Ngân hàng thương mại cổ phần K...Báo cáo tốt nghiệp Phát triển sản phẩm thẻ tại Ngân hàng thương mại cổ phần K...
Báo cáo tốt nghiệp Phát triển sản phẩm thẻ tại Ngân hàng thương mại cổ phần K...
 
Tien De Ra Tien Dau Tu Tai Chinh Thong Minh - Duncan Bannatyne.pdf
Tien De Ra Tien Dau Tu Tai Chinh Thong Minh - Duncan Bannatyne.pdfTien De Ra Tien Dau Tu Tai Chinh Thong Minh - Duncan Bannatyne.pdf
Tien De Ra Tien Dau Tu Tai Chinh Thong Minh - Duncan Bannatyne.pdf
 
Đồ án Công Nghệ Truyền Số Liệu L3VPN MPLS
Đồ án Công Nghệ Truyền Số Liệu L3VPN MPLSĐồ án Công Nghệ Truyền Số Liệu L3VPN MPLS
Đồ án Công Nghệ Truyền Số Liệu L3VPN MPLS
 
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 11 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-...
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 11 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-...BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 11 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-...
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 11 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-...
 
Báo cáo thực tập tốt nghiệp Phân tích thực trạng hoạt động bán hàng tại Công ...
Báo cáo thực tập tốt nghiệp Phân tích thực trạng hoạt động bán hàng tại Công ...Báo cáo thực tập tốt nghiệp Phân tích thực trạng hoạt động bán hàng tại Công ...
Báo cáo thực tập tốt nghiệp Phân tích thực trạng hoạt động bán hàng tại Công ...
 
tiểu luận THỰC HÀNH QUẢN TRỊ TÀI CHÍNH 1.docx
tiểu luận THỰC HÀNH QUẢN TRỊ TÀI CHÍNH 1.docxtiểu luận THỰC HÀNH QUẢN TRỊ TÀI CHÍNH 1.docx
tiểu luận THỰC HÀNH QUẢN TRỊ TÀI CHÍNH 1.docx
 
Nghe Tay Trai Hai Ra Tien - Chris Guillebeau (1).pdf
Nghe Tay Trai Hai Ra Tien - Chris Guillebeau (1).pdfNghe Tay Trai Hai Ra Tien - Chris Guillebeau (1).pdf
Nghe Tay Trai Hai Ra Tien - Chris Guillebeau (1).pdf
 
sách các Bài tập kinh tế vi mô chọn lọc.
sách các Bài tập kinh tế vi mô chọn lọc.sách các Bài tập kinh tế vi mô chọn lọc.
sách các Bài tập kinh tế vi mô chọn lọc.
 
TỔNG HỢP HƠN 100 ĐỀ THI THỬ TỐT NGHIỆP THPT VẬT LÝ 2024 - TỪ CÁC TRƯỜNG, TRƯ...
TỔNG HỢP HƠN 100 ĐỀ THI THỬ TỐT NGHIỆP THPT VẬT LÝ 2024 - TỪ CÁC TRƯỜNG, TRƯ...TỔNG HỢP HƠN 100 ĐỀ THI THỬ TỐT NGHIỆP THPT VẬT LÝ 2024 - TỪ CÁC TRƯỜNG, TRƯ...
TỔNG HỢP HƠN 100 ĐỀ THI THỬ TỐT NGHIỆP THPT VẬT LÝ 2024 - TỪ CÁC TRƯỜNG, TRƯ...
 
BÀI TẬP DẠY THÊM HÓA HỌC LỚP 12 - CẢ NĂM - THEO FORM THI MỚI BGD 2025 (DÙNG C...
BÀI TẬP DẠY THÊM HÓA HỌC LỚP 12 - CẢ NĂM - THEO FORM THI MỚI BGD 2025 (DÙNG C...BÀI TẬP DẠY THÊM HÓA HỌC LỚP 12 - CẢ NĂM - THEO FORM THI MỚI BGD 2025 (DÙNG C...
BÀI TẬP DẠY THÊM HÓA HỌC LỚP 12 - CẢ NĂM - THEO FORM THI MỚI BGD 2025 (DÙNG C...
 
BÀI GIẢNG HÀNG HÓA VẬN TẢI 3TC-24.1.2021.FULL.docx
BÀI GIẢNG HÀNG HÓA VẬN TẢI 3TC-24.1.2021.FULL.docxBÀI GIẢNG HÀNG HÓA VẬN TẢI 3TC-24.1.2021.FULL.docx
BÀI GIẢNG HÀNG HÓA VẬN TẢI 3TC-24.1.2021.FULL.docx
 
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
Đề cương môn Xã hội Chủ nghĩa Khoa học (sơ lược)
 
15 ĐỀ THI THỬ TUYỂN SINH VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 SỞ GIÁO...
15 ĐỀ THI THỬ TUYỂN SINH VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 SỞ GIÁO...15 ĐỀ THI THỬ TUYỂN SINH VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 SỞ GIÁO...
15 ĐỀ THI THỬ TUYỂN SINH VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 SỞ GIÁO...
 
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 31-39)...
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 31-39)...40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 31-39)...
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 31-39)...
 
nghiên cứu một số kĩ thuật chiết xuất dược liệu (1).docx
nghiên cứu một số kĩ thuật chiết xuất dược liệu (1).docxnghiên cứu một số kĩ thuật chiết xuất dược liệu (1).docx
nghiên cứu một số kĩ thuật chiết xuất dược liệu (1).docx
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
Báo cáo thực tập tốt nghiệp Phân tích hiệu quả hoạt động huy động và cho vay ...
Báo cáo thực tập tốt nghiệp Phân tích hiệu quả hoạt động huy động và cho vay ...Báo cáo thực tập tốt nghiệp Phân tích hiệu quả hoạt động huy động và cho vay ...
Báo cáo thực tập tốt nghiệp Phân tích hiệu quả hoạt động huy động và cho vay ...
 
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜICHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
CHƯƠNG 5. TTHCM VỀ VĂN HÓA, ĐẠO ĐỨC, CON NGƯỜI
 
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 21-30)...
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 21-30)...40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 21-30)...
40 ĐỀ LUYỆN THI ĐÁNH GIÁ NĂNG LỰC ĐẠI HỌC QUỐC GIA HÀ NỘI NĂM 2024 (ĐỀ 21-30)...
 

Nghiên cứu về kiểm chứng bất biến của đối tượng sử dụng lập trình hướng khía cạnh.pdf

  • 1. ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ PHẠM ĐÌNH PHONG NGHIÊN CỨU VỀ KIỂM CHỨNG BẤT BIẾN CỦA ĐỐI TƯỢNG SỬ DỤNG LẬP TRÌNH HƯỚNG KHÍA CẠNH Ngành: Công nghệ thông tin Chuyên ngành: Công nghệ phần mềm Mã số: 60 48 10 LUẬN VĂN THẠC SĨ NGƯỜI HƯỚNG DẪN KHOA HỌC: PGS. TS. Nguyễn Việt Hà Hà Nội – 2010
  • 2. ii Lời cảm ơn Với lòng biết ơn sâu sắc, em xin chân thành cảm ơn thầy giáo PGS. TS. Nguyễn Việt Hà, người đã trực tiếp định hướng đề tài và tận tình hướng dẫn em hoàn thành luận văn này. Em cũng chân thành cảm ơn thầy TS. Phạm Ngọc Hùng đã có những nhận xét, đánh giá trong quá trình hoàn thiện luận văn. Em xin được bày tỏ lòng biết ơn đối với các thầy giáo, cô giáo Khoa Công nghệ thông tin Trường Đại học Công nghệ đã tận tình chỉ bảo, giảng dạy em suốt thời gian học tại trường cũng như việc hoàn thành luận văn này. Cuối cùng, xin được bày tỏ tình cảm tới những người thân trong gia đình, các bạn bè trong tập thể lớp Cao học K15T2, K15T3 và K15CNPM đã động viên, hỗ trợ em về mọi mặt. Em xin chân thành cảm ơn! Hà Nội, tháng 09 năm 2010 Phạm Đình Phong
  • 3. iii Lời cam đoan Tôi xin cam đoan rằng, ngoại trừ các nội dung được trích từ tài liệu tham khảo hoặc các công trình khác như đã ghi rõ trong luận văn, các kết quả nêu trong luận văn này là do chính tôi thực hiện. Hà Nội, tháng 09 năm 2010 Phạm Đình Phong
  • 4. iv MỤC LỤC Lời cảm ơn ..................................................................................................................ii Lời cam đoan............................................................................................................. iii MỤC LỤC..................................................................................................................iv Danh mục bảng biểu ...................................................................................................vi Danh mục hình vẽ......................................................................................................vii Danh mục ký hiệu, từ viết tắt ....................................................................................viii MỞ ĐẦU.....................................................................................................................1 Chương 1 – Lập trình hướng khía cạnh........................................................................4 1.1. Giới thiệu ......................................................................................................4 1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng ........................................5 1.2.1. Các mối quan tâm của hệ thống..............................................................5 1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP .................................7 1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP8 1.3. Lập trình hướng khía cạnh...........................................................................10 1.3.1. Lịch sử hình thành................................................................................10 1.3.2. Cú pháp của AOP và mô hình lập trình ................................................11 1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh...................12 1.3.4. Đan kết.................................................................................................13 1.3.5. Phương pháp lập trình hướng khía cạnh ...............................................14 1.3.6. Lợi ích của lập trình hướng khía cạnh...................................................15 1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh .....................17 1.3.8. Các công cụ AOP.................................................................................18 1.4. AspectJ........................................................................................................19 1.4.1. Thực thi cắt ngang................................................................................19 1.4.2. Joint Point ............................................................................................20 1.4.3. Pointcut................................................................................................22 1.4.4. Advice..................................................................................................26 1.4.5. Introduction..........................................................................................29 1.4.6. Aspect ..................................................................................................30 1.5. Kết luận.......................................................................................................33 Chương 2 - Công cụ kiểm chứng mô hình Java PathFinder........................................34 2.1. Giới thiệu ....................................................................................................34 2.2. Công cụ kiểm chứng mô hình Java PathFinder ............................................34 2.2.1. Lịch sử của Java PathFinder .................................................................35 2.2.2. Các thành phần của Java PathFinder.....................................................35 2.2.3. Những gì có thể được kiểm chứng bởi Java PathFinder ........................37 2.2.4. Kiểm chứng mô hình trong Java PathFinder.........................................37 2.3. Các đề án mở rộng của Java PathFinder.......................................................40 2.4. Kết luận.......................................................................................................41 Chương 3 – Kiểm chứng bất biến của chương trình Java sử dụng lập trình hướng khía cạnh...........................................................................................................................42 3.1. Đặt vấn đề ...................................................................................................42 3.2. Ngôn ngữ mô hình hóa thống nhất UML .....................................................43 3.2.1. Thuộc tính............................................................................................43
  • 5. v 3.2.2. Liên kết................................................................................................44 3.2.3. Thao tác ...............................................................................................44 3.3. Ngôn ngữ ràng buộc đối tượng OCL ...........................................................45 3.3.1. Biểu diễn biểu thức OCL......................................................................45 3.3.2. Bất biến (invariant)...............................................................................46 3.4. Ví dụ minh họa............................................................................................48 3.5. Kiểm chứng bất biến sử dụng AOP .............................................................50 3.6. Vấn đề kế thừa các bất biến ở lớp con .........................................................51 3.7. Kiểm chứng bất biến của lớp con có ràng buộc thay đổi so với lớp cha .......55 3.8. Kiểm chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con ..60 3.9. Thực nghiệm ...............................................................................................62 3.10. Kết luận ...................................................................................................64 Chương 4 – Sinh tự động các ca kiểm thử bằng công cụ Java PathFinder ..................65 4.1. Tổng quan ...................................................................................................65 4.2. Thực thi ký hiệu ..........................................................................................65 4.3. Sinh tự động các ca kiểm thử bằng thực thi ký hiệu.....................................67 4.4. Kiểm chứng bất biến bằng việc chèn khẳng định .........................................71 4.4.1. Khẳng định trong Java và Java PathFinder ...........................................71 4.4.2. Xác định các bất biến ...........................................................................72 4.4.2.1. Đặt khẳng định trong đoạn mã.......................................................72 4.4.2.2. Kiểm tra bất biến trong phương thức main ....................................72 4.4.2.3. Bất biến như là một tiến trình (Invariant as a Thread)....................74 4.4.3. So sánh phương pháp AOP và phương pháp chèn khẳng định ..............75 4.5. Kết quả thực nghiệm ...................................................................................76 4.5.1. Kết quả thực nghiệm sinh các ca kiểm thử tự động...............................76 4.5.2. Kết quả thực nghiệm kiểm chứng bất biến bằng chèn khẳng định.........79 4.6. Kết luận.......................................................................................................80 KẾT LUẬN ...............................................................................................................81 TÀI LIỆU THAM KHẢO..........................................................................................83
  • 6. vi Danh mục bảng biểu Bảng 1.1. So sánh giữa aspect và lớp Bảng 3.1. Một số kết quả thực nghiệm
  • 7. vii Danh mục hình vẽ Hình 1.1. Các mối quan tâm trong một hệ thống Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP Hình 1.3. Chồng chéo mã nguồn Hình 1.4. Dàn trải mã nguồn Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP Hình 1.8. Các giai đoạn phát triển AOP Hình 1.9. Ví dụ về định nghĩa pointcut Hình 2.1. Sự bố trí các tầng của JPF Hình 2.2. Các thành phần của JPF Hình 2.3. Bùng nổ không gian trạng thái do sự đan xen giữa các luồng Hình 3.1. Biểu diễn các ràng buộc trên sơ đồ UML Hình 3.2. Ví dụ biểu đồ lớp của hệ thống card ATM Hình 3.3. Quy trình kiểm chứng bất biến Hình 4.1. Thực thi ký hiệu
  • 8. viii Danh mục ký hiệu, từ viết tắt Từ viết tắt Thuật ngữ Ý nghĩa AOP Aspect-Oriented Programming Lập trình hướng khía cạnh API Application Programming Interface Giao diện lập trình ứng dụng ASCII American Standard Code for Information Interchange Bộ mã chuẩn cho trao đổi thông tin của Mỹ AWT Abstract Window Toolkit Bộ công cụ đồ họa độc lập nền tảng của Java CTW Compile-time Weaving Đan kết lúc biên dịch Eclipse Bộ công cụ phát triển phần mềm IBM International Business Machines Corp Một trong những nhà sản xuất máy tính lớn nhất thế giới JDK Java Development Kit Bộ phát triển ứng dụng Java JPF Java PathFinder Bộ công cụ kiểm chứng mô hình cho ngôn ngữ Java JVM Java Virtual Machine Máy ảo Java LTW Load-time Weaving Đan kết lúc nạp chương trình MJI Model Java Interface Giao diện Java mẫu OCL Object Constraint Language Ngôn ngữ ràng buộc đối tượng OOP Object-Oriented Programming Lập trình hướng đối tượng RTW Run-time Weaving Đan kết lúc thực thi SPIN Simple Promela INterpreter Công cụ thông dịch ngôn ngữ Promela (trong kiểm chứng mô hình) SUT System Under Test Hệ thống được kiểm thử Syntropy Một phương pháp phân tích và thiết kế hướng đối tượng thế hệ thứ hai UML Unified Modeling Language Ngôn ngữ mô hình hóa thống nhất VM Virtual Machine Máy ảo XML eXtensible Markup Language Ngôn ngữ đánh dấu mở rộng
  • 9. 1 MỞ ĐẦU Những năm gần nay, với sự phát triển của phương pháp lập trình hướng đối tượng (OOP) [1, 2, 12] đã mang lại nhiều bước tiến mới cho lập trình nói chung và đưa ngành Công nghệ phần mềm lên một bước phát triển mới. Ưu điểm lớn nhất của lập trình hướng đối tượng là một hệ thống phần mềm được xây dựng bởi tập các lớp rời rạc. Mỗi lớp có nhiệm vụ hoàn toàn xác định, các nhiệm vụ của nó được vạch ra một cách rõ ràng. Trong một ứng dụng hướng đối tượng, các lớp cộng tác với nhau để đạt được mục tiêu chung của ứng dụng. Tuy nhiên, có các phần của một hệ thống không chỉ gánh nhiệm vụ giới hạn trong một lớp, chúng cắt ngang toàn bộ hệ thống và ảnh hưởng đến nhiều lớp. Đó chính là sự đan nhau phức tạp giữa các thành phần bên trong ứng dụng. Bên cạnh đó, tính tĩnh trong cách tiếp cận hướng đối tượng không cho phép phần mềm thích ứng với những thay đổi mới đáp ứng yêu cầu người dùng. Một hướng tiếp cận mới trong việc phát triển phần mềm là lập trình hướng khía cạnh (AOP: Aspect-Oriented Programming) [10, 22, 3]. Hướng tiếp cận này còn khá mới mẻ nhưng hứa hẹn những lợi điểm giải quyết được những yêu cầu có tính đan xen phức tạp, đồng thời mang lại cho phần mềm khả năng thay đổi và bổ sung yêu cầu mới sau khi đã hoàn chỉnh hay thậm chí đã đưa vào sử dụng. Ngôn ngữ mô hình hóa thống nhất (Unified Modelling Language - UML [4]) được chấp nhận rộng rãi như là một chuẩn cho phân tích và thiết kế hướng đối tượng. Việc biểu diễn và mô hình hóa cấu trúc tĩnh của hệ thống hướng đối tượng được dùng phổ biến trong các sơ đồ lớp UML. Tuy nhiên, không phải các cấu trúc chi tiết nào cũng có thể được biểu diễn một cách dễ dàng trong một sơ đồ lớp. Ngôn ngữ ràng buộc đối tượng (Object Constraint Language - OCL [29]), một phần của UML, là ngôn ngữ dùng cho việc mô tả các ràng buộc thêm vào trên các mô hình hướng đối tượng. Các ràng buộc OCL được sử dụng để mô tả các bất biến trên các lớp và các kiểu, các tiền điều kiện và hậu điều kiện của các thao tác. Các ràng buộc OCL luôn luôn được kết nối tới một mô hình hướng đối tượng UML. Một bất biến (invariant) là một ràng buộc liên quan đến một lớp, kiểu hay giao diện trong một mô hình UML. Bất biến được biểu diễn như một biểu thức lôgic giới hạn giá trị của một thuộc tính hay liên kết hay nó có thể biểu diễn mối quan hệ giữa các giá trị của các thuộc tính, các liên kết. Kết quả của biểu thức phải là đúng đối với tất cả các thể hiện của lớp được tham chiếu. Giai đoạn đảm bảo chất lượng phần mềm ngày càng trở nên quan trọng. Trong giai đoạn này, các đặc tả UML và các ràng buộc OCL đã được tạo ra bởi các nhà thiết kế phần mềm, chương trình chính đã được cài đặt bởi các nhà phát triển phần mềm dựa trên các đặc tả UML. Như vậy làm thế nào để kiểm chứng được bất biến của các đối tượng được thể hiện bằng các ràng buộc OCL có bị vi phạm tại thời điểm thực thi hay không. Sau khi nghiên cứu phương pháp AOP, chúng tôi thấy có thể sử dụng
  • 10. 2 phương pháp này để cài đặt các mã kiểm chứng để kiểm chứng các bất biến của các phần mềm được thiết kế theo phương pháp hướng đối tượng dựa trên các ràng buộc OCL đã được thiết kế. Đã có những nghiên cứu trước đó liên quan đến phương pháp này [3, 23]. Theo đó, công việc kiểm chứng được tách biệt hoàn toàn khỏi chương trình chính bằng cách tạo ra các aspect chứa mã kiểm chứng. Các aspect này sẽ được đan tự động vào chương trình chính và khi chương trình được thực thi, công việc kiểm chứng sẽ được thực hiện tự động. Tuy nhiên các nghiên cứu chưa xem xét việc kiểm chứng bất biến cho các lớp con được kế thừa bên dưới. Chúng tôi quan tâm tới việc xem xét các bất biến của các đối tượng theo quan hệ kế thừa, cụ thể là nghiên cứu kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào lớp con và bất biến của lớp con có ràng buộc thay đổi so với lớp cha. Việc kiểm thử tính đúng đắn của các phương thức cần có bộ dữ liệu làm đầu vào cho các phương thức cần kiểm thử. Một bộ dữ liệu vào như vậy được gọi là một ca kiểm thử (test case). Việc chọn các bộ dữ liệu như thế nào để có thể phủ toàn bộ các đường thực thi có thể (possible execution path) là rất khó. Nếu có công cụ sinh tự động các ca kiểm thử phủ toàn bộ các đường thực thi có thể thì ta có thể chứng minh tính đúng đắn của phương thức thông qua các ca kiểm thử được sinh ra. Java PathFinder (JPF) [19, 25, 30, 31] với phần mở rộng của nó là thực thi ký hiệu dùng để sinh tự động các ca kiểm thử phủ được toàn bộ các đường thực thi có thể cho các phương thức của các đối tượng trong chương trình được cài đặt bằng ngôn ngữ Java. Chúng tôi sử dụng công cụ thực thi ký hiệu để sinh tự động các ca kiểm thử nhằm kiểm tra lại phương pháp kiểm chứng bất biến bằng AOP. Nội dung nghiên cứu: Tìm hiểu và nghiên cứu về kiểm chứng phần mềm, lập trình hướng khía cạnh (Aspect Oriented Programming - AOP) và sử dụng AOP để kiểm chứng bất biến của đối tượng bao gồm: Nghiên cứu về lý thuyết kiểm chứng phần mềm, các phương pháp, công cụ kiểm chứng phần mềm. Nghiên cứu phương pháp lập trình hướng khía cạnh và AspectJ - một đặc tả ngôn ngữ cho việc cài đặt các aspect bằng ngôn ngữ lập trình Java. Mở rộng phương pháp sử dụng AOP để kiểm chứng các bất biến của đối tượng trong chương trình Java tại thời điểm thực thi được đề xuất trong [23] bao gồm kiểm chứng bất biến liên quan đến các thuộc tính được thêm mới vào ở lớp con và bất biến của lớp con có ràng buộc thay đổi so với lớp cha. Để kiểm tra tính đúng đắn của các phương thức cần có các ca kiểm thử làm dữ liệu đầu vào. Do đó chúng tôi nghiên cứu công cụ kiểm chứng mô hình Java PathFinder và phần mở rộng thực thi ký hiệu (Symbolic Execution) [15] của nó để sinh tự động các ca kiểm thử cho các phương thức của các đối tượng trong chương trình hướng đối tượng Java.
  • 11. 3 Sử dụng công cụ Java PathFinder để kiểm chứng bất biến được khai báo dưới dạng các khẳng định (assertion) trong chương trình Java và so sánh với phương pháp kiểm chứng bất biến sử dụng AOP. Cấu trúc luận văn: Luận văn gồm các phần: Mở đầu, 4 chương, kết luận và tài liệu tham khảo: Chương 1 giới thiệu phương pháp lập trình hướng khía cạnh. Chúng tôi trình bày quá trình hình thành phương pháp lập trình hướng khía cạnh, ưu điểm và nhược điểm của nó đồng thời trình bày về AspectJ – một cài đặt phổ biến của AOP trên ngôn ngữ lập trình hướng đối tượng Java. Chương 2 trình bày tổng quan về công cụ kiểm chứng mô hình Java PathFinder (JPF) và các mở rộng của nó. Chương 3 trình bày và mở rộng kỹ thuật kiểm chứng bất biến của đối tượng trong chương trình hướng đối tượng Java tại thời điểm thực thi sử dụng phương pháp AOP. Chúng tôi trình bày kỹ thuật sử dụng AOP để kiểm chứng bất biến của đối tượng Java. Phương pháp này đã có các nghiên cứu được công bố [23, 3] và chúng tôi mở rộng xem xét các bất biến theo quan hệ kế thừa. Cụ thể là chúng tôi đề xuất kỹ thuật kiểm chứng bất biến liên quan đến các thuộc tính được thêm vào lớp con và bất biến của lớp con có ràng buộc thay đổi so với lớp cha. Chương 4 trình bày phương pháp sử dụng công cụ thực thi ký hiệu là một mở rộng của JPF để sinh các ca kiểm thử tự động cho các phương thức của đối tượng trong chương trình hướng đối tượng Java nhằm mục đích kiểm tra lại phương pháp kiểm chứng sử dụng AOP. Chương này cũng trình bày phương pháp kiểm chứng bất biến được khai báo dưới dạng các khẳng định trong chương trình Java sử dụng JPF và so sánh với phương pháp kiểm chứng bất biến sử dụng AOP. Một vài thực nghiệm của thực thi ký hiệu và của kiểm chứng bất biến bằng việc chèn các khẳng định cũng được trình bày.
  • 12. 4 Chương 1 – Lập trình hướng khía cạnh 1.1. Giới thiệu Hệ thống phần mềm có thể được xem là một thể hiện kết hợp nhiều vấn đề. Một hệ thống tiêu biểu có thể gồm nhiều dạng vấn đề như xử lý nghiệp vụ, hiệu suất, bảo toàn dữ liệu, bảo mật, bẫy lỗi, … và còn có những vấn đề của quá trình phát triển hệ thống như tính dễ quản lý, dễ bảo trì và phát triển. Trong việc thiết kế phần mềm, các nhà thiết kế phần mềm thường tập chung sự quan tâm vào các chức năng chính, cơ bản của hệ thống. Trong ứng dụng của các doanh nghiệp, đó chính là các logic nhiệp vụ cơ bản. Ví dụ như trong ứng dụng quản lý nhgiệp vụ bảo hiểm, các mô-đun chức năng chính được thiết kế cho việc quản lý các giao dịch bảo hiểm do khách hàng hoặc nhân viên phòng nghiệp vụ thực hiện. Trong ứng dụng quản lý nhân sự, các mô-đun quản lý chính là quản lý hồ sơ nhân viên, tính toán lương và các chế độ cho nhân viên. Trong hai ứng dụng trên, các mô-đun xử lý nghiệp vụ chính có thể được thực hiện riêng rẽ nhưng có những mối quan tâm liên quan đến nhiều mô-đun như tính năng lưu vết, xác thực quyền hạn, truy cập cơ sở dữ liệu, bẫy lỗi, … Các tính năng đó là cần thiết đối với mỗi mô-đun chính của hệ thống và dàn trải trên nhiều môđun của hệ thống. Các mối quan tâm dàn trải trên nhiều mô-đun của hệ thống đó được gọi là các mối quan tâm cắt ngang (cross-cutting concerns). Do vậy đối với mỗi mô-đun, lập trình viên ngoài việc quan tâm đến những vấn đề cơ bản còn phải tính đến những mối quan tâm cắt ngang và sự trộn lẫn nhiều đoạn mã để xử lý những yêu cầu khác nhau. Sự trộn lẫn nhiều đoạn mã như vậy gọi là vấn đề đan nhau. Do vấn đề đan nhau có ở nhiều mô-đun nên các đoạn xử lý liên quan cũng xuất hiện ở nhiều mô-đun. Những vấn đề này ảnh hưởng đến vấn đề thiết kế và phát triển phần mềm như hệ thống khó xây dựng, khó quản lý, phát triển và tái sử dụng kém. Lập trình hướng đối tượng (Object-Oriented Programming - OOP) [1, 2, 12] là phương pháp lập trình phổ biến nhất hiện nay được sử dụng để quản lý các mối quan tâm nghiệp vụ chính, tuy nhiên phương pháp này chưa đủ mạnh để xử lý hiệu quả rất nhiều các mối quan tâm cắt ngang hệ thống, đặc biệt là các ứng dụng phức tạp. Phương pháp lập trình hướng khía cạnh (Aspect-Oriented Programming - AOP) [10, 22, 3] là phương pháp lập trình mới cho phép chúng ta thực hiện các vấn đề riêng biệt một cách linh hoạt và kết hợp chúng lại để tạo nên hệ thống sau cùng. AOP bổ sung cho kỹ thuật lập trình hướng đối tượng bằng việc cung cấp một dạng mô-đun khác bằng cách kéo các mối quan tâm cắt ngang vào một khối, đó chính là aspect. Với AOP, ta có thể cài đặt các mối quan tâm cắt ngang hệ thống trong các aspect thay vì dàn trải chúng trên các mô-đun nghiệp vụ chính liên quan. Quá trình bộ đan aspect (weaver) kết hợp các mô-đun nghiệp vụ chính với các aspect thành hệ thống cuối cùng
  • 13. 5 được gọi là quá trình đan (weaving). Như vậy, AOP đã mô-đun hóa các mối quan tâm cắt ngang một cách rõ ràng, tách biệt với các mô-đun nghiệp vụ chính giúp cho việc thiết kế, thực thi và bảo trì hệ thống dễ dàng hơn và tốn ít chi phí, công sức. Các aspect của hệ thống có thể thay đổi, thêm hoặc xóa lúc biên dịch và có thể tái sử dụng. Lập trình hướng khía cạnh là kỹ thuật lập trình mới cho phép đóng gói những hành vi liên quan đến nhiều đối tượng và rất có thể sẽ là bước phát triển kế tiếp trong phương pháp lập trình. Tuy nhiên AOP không thay thế OOP mà nó là sự bổ sung cho OOP, cho phép chúng ta giải quyết các bài toán phức tạp tốt hơn và hiệu quả hơn. Trong các phần tiếp theo, chúng ta sẽ khảo sát những vấn đề mà lập trình hướng đối tượng làm tốt và những vấn đề phát sinh từ các đối tượng và làm thế nào AOP có thể lấp khoảng trống này. AspectJ [11, 13, 26], một cài đặt phổ biến của AOP trên ngôn ngữ Java cũng được giới thiệu trong chương này. 1.2. Các vấn đề tồn tại trong lập trình hướng đối tượng Phát triển phần mềm đã đi được một quãng đường khá dài. Khi sự hữu ích của phát triển phần mềm được phát hiện, sự cải tiến nó đã trở nên bắt buộc để tìm kiếm các kỹ thuật để mô hình hóa các bài toán của thế giới thực một cách hiệu quả hơn. Nhiều năm trước, phương pháp luận chung cho việc giải quyết một bài toán là chia nó thành các môđun chức năng nhỏ hơn và mỗi chức năng được cấu thành từ nhiều dòng lệnh. Phương pháp luận này đã làm việc tốt nhưng một trạng thái hệ thống được điều khiển bởi một số lượng lớn các biến toàn cục mà chúng có thể được thay đổi bởi bất kỳ dòng lệnh nào trong ứng dụng. Sự xuất hiện của phương pháp luận hướng đối tượng kéo trạng thái của hệ thống vào các đối tượng riêng lẻ, chúng có thể trở nên riêng tư và được điều khiển thông qua các phương thức truy cập và logic. Kỹ thuật OOP rất xuất xắc trong việc đóng gói các hành vi vào chủ thể lớp (class), miễn là chúng riêng biệt. Tuy nhiên, trong các bài toán thực tế có những hành vi dàn trải trên nhiều lớp. Trong hầu hết các ngôn ngữ lập trình hướng đối tượng truyền thống như C++ [2] hay Java [1, 12] đều không hỗ trợ việc đóng gói các hành vi dàn trải trên nhiều môđun, dẫn đến mã chương trình có thể nằm lẫn lộn, rải rác và khó quản lý. Hiện tại, OOP được lựa chọn cho hầu hết các dự án phần mềm. Nó tập chung vào giải quyết các nghiệp vụ chính nhưng nó không phải là phương pháp tốt để quản lý các hành vi dàn trải trên nhiều mô-đun. 1.2.1. Các mối quan tâm của hệ thống Sự chia tách các mối quan tâm là một nguyên lý cơ bản của kỹ nghệ phần mềm. Nguyên lý này giúp quản lý tính phức tạp của phát triển phần mềm bằng việc khai báo, đóng gói và khai thác các phần của phần mềm liên quan đến một mối quan tâm đặc thù. Một mối quan tâm (concern) là một yêu cầu cụ thể hoặc một sự cân nhắc nào đó cần phải được đưa ra nhằm thỏa mãn mục đích chung của toàn hệ thống. Một hệ thống phần mềm là việc thực thi tập các mối quan tâm đó. Ví dụ trong một hệ thống quản lý
  • 14. 6 nghiệp vụ bảo hiểm bao gồm việc thực thi các mối quan tâm sau: quản lý khách hàng, quản lý hợp đồng bảo hiểm, tính lãi suất cho các hợp đồng bảo hiểm có yếu tố tiết kiệm, thực hiện chi trả bảo hiểm, tạo báo cáo, xác thực quyền hạn, lưu vết giao dịch, … Bên cạnh các mối quan tâm của hệ thống, một dự án phần mềm cần chỉ ra được các mối quan tâm khác liên quan đến toàn bộ các thuộc tính chất lượng của hệ thống như tính dễ hiểu, dễ quản lý, dễ bảo trì và phát triển. Các mối quan tâm được chia thành hai loại: mối quan tâm chính được cài đặt chức năng chính của một mô-đun và mối quan tâm cắt ngang là yêu cầu ngoài, mức hệ thống và dàn trải trên nhiều mô-đun. Một ứng dụng của một doanh nghiệp không những quan tâm đến các mối quan tâm nghiệp vụ chính mà còn phải quan tâm đến các mối quan tâm cắt ngang hệ thống như xác thực quyền hạn, lưu vết giao dịch, bẫy lỗi, truy cập tài nguyên chung, đảm bảo tính toàn vẹn của giao dịch, … Tất cả các mối quan tâm này đều cắt ngang một số mô-đun. Ví dụ như mối quan tâm về việc lưu vết giao dịch liên quan đến tất cả các môđun giao dịch chính, mối quan tâm về truy cập dữ liệu liên quan đến các mô-đun có truy xuất cơ sở dữ liệu, mối quan tâm về xác thực quyền hạn liên quan đến các mô-đun có yêu cầu về quản lý quyền truy cập. Hình 1.1 minh họa việc thực thi các mô-đun trong một hệ thống chứa cả các mối quan tâm mức hệ thống và các mối quan tâm nghiệp vụ. Ở đây, một hệ thống được mô tả như một sự tổng hợp của nhiều mối quan tâm. Hệ thống trở nên chồng chéo lên nhau bởi các kỹ thuật cài đặt hiện tại, chính vì thế, sự độc lập giữa các mối quan tâm không được đảm bảo. Hình 1.1. Các mối quan tâm trong một hệ thống.
  • 15. 7 1.2.2. Giải quyết các mối quan tâm cắt ngang bằng OOP Trong quá trình phát triển phần mềm các nhà phát triển thường xác định các mối quan tâm và sau đó chia tách chúng cho các nhóm phát triển khác nhau để mô-đun hóa chúng. Có những trở ngại lớn cho các nhóm phát triển khi mô-đun hóa các mối quan tâm là làm sao xử lý hiệu quả các mối quan tâm cắt ngang hệ thống. Trong thực tế, phương pháp OOP thường được sử dụng để mô-đun hóa các mối quan tâm của một hệ thống phần mềm. Tuy nhiên, thực tế thì, mặc dù OOP giải quyết rất tốt trong việc mô- đun hóa các mối quan tâm nghiệp vụ chính nhưng lại gặp khó khăn trong việc mô-đun hóa các mối quan tâm cắt ngang hệ thống. Trong OOP, các mô-đun chính có thể được kết nối lỏng với nhau thông qua giao diện, nhưng không dễ gì làm việc này với các mối quan tâm cắt ngang hệ thống. Lý do chính là một mối quan tâm được thực thi thành hai phần: Phần phía server (phần phục vụ) và phần phía client (phần được phục vụ). OOP mô-đun hóa phần client khá tốt bằng các lớp và các giao diện. Tuy nhiên, ở phía server, một mối quan tâm lại là một loại cắt ngang hệ thống, bao gồm các yêu cầu gửi đến server, dàn trải trên các client. Hình 1.2. Thực thi các mối quan tâm cắt ngang bằng OOP. Xét một ví dụ điển hình về việc thực thi một mối quan tâm cắt ngang hệ thống trong OOP: Một mô-đun lưu vết cung cấp các dịch vụ thông qua một giao diện trừu tượng. Việc sử dụng giao diện nới lỏng kết nối giữa các client và việc thực thi các giao diện. Các client sử dụng các dịch vụ lưu vết thông qua giao diện dành cho hầu hết các phần không quan tâm đến chi tiết cài đặt mà họ đang sử dụng. Khi có bất cứ thay đổi nào đến các cài đặt mà chúng đang sử dụng sẽ không yêu cầu thay đổi đến bản thân các client. Tương tự như thế, việc thay thế sự thực thi lưu vết bằng một sự thực thi khác chỉ là vấn đề về việc khởi tạo đúng loại thực thi. Kết quả là một sự thực thi về lưu vết có thể được chuyển đổi với sự thực thi khác với ít hoặc không thay đổi cho các
  • 16. 8 mô-đun client riêng lẻ. Tuy nhiên, trong cấu hình này, các client vẫn phải chứa các đoạn mã để gọi các API. Những lời gọi này cần phải có trong tất cả các mô-đun có yêu cầu cần lưu vết và được trộn lẫn với các đoạn mã dành cho logic nghiệp vụ chính. Hình 1.2 minh họa cách thực thi mối quan tâm lưu vết trong một hệ thống phần mềm quản lý nghiệp vụ bảo hiểm sử dụng các kỹ thuật truyền thống như OOP. Thậm chí khi sử dụng mô-đun lưu vết được thiết kế tốt đưa ra API trừu tượng và che giấu chi tiết về việc định dạng và phân lớp các thông điệp lưu vết, thì mỗi mô-đun client như mô-đun Subscribing, Claim hay Database đều phải chứa các đoạn mã để triệu gọi API lưu vết. Kết quả tổng thể là gây ra sự lộn xộn, chồng chéo giữa các mô-đun cần lưu vết và bản thân các mô-đun lưu vết. 1.2.3. Các vấn đề gặp phải khi thực thi các mối quan tâm cắt ngang bằng OOP Khi thực thi các mối quan tâm cắt ngang bằng phương pháp OOP, hệ thống sẽ gặp phải một số vấn đề trong đó có hai vấn đề chính là sự chồng chéo mã nguồn và dàn trải mã nguồn. Chồng chéo mã nguồn (Code tangling): Các mô-đun trong hệ thống có thể đồng thời phải thực hiện nhiều yêu cầu khác nhau. Ví dụ như trong quá trình phát triển một mô-đun nào đó, ngoài việc đảm bảo yêu cầu chính của mô-đun đó, lập trình viên luôn phải tính tới các mối quan tâm khác như hiệu năng, đồng bộ, an ninh, lưu vết, lưu trữ,... Các mối quan tâm này làm cho việc xuất hiện rất nhiều loại mã chương trình của các mối quan tâm khác nhau trong quá trình cài đặt mô-đun. Hiện tượng này gọi là chồng chéo mã nguồn. Hình 1.3 minh họa vấn đề chồng chéo mã nguồn do sự thực thi của nhiều mối quan tâm trên cùng một mô-đun. Hình 1.3. Chồng chéo mã nguồn. Dàn trải mã nguồn (Code scattering): Mã nguồn của các yêu cầu mức hệ thống (an ninh, lưu vết, lưu trữ,...) được cài đặt ở trong rất nhiều mô-đun. Ví dụ như chức năng lưu vết được cài đặt ở tất các các mô-đun quan trọng cần lưu vết. Như vậy việc cài đặt mã nguồn cho một mối quan tâm bị xé nhỏ vào rất nhiều mô-đun khác
  • 17. 9 nhau. Hiện tượng này gọi là dàn trải mã nguồn. Hình 1.4 minh họa vấn đề dàn trải mã nguồn do đặt nhiều đoạn mã giống nhau trong nhiều mô-đun khác nhau nhằm thực thi một chức năng nào đó. Ở đây, trong ví dụ hệ thống quản lý nghiệp vụ bảo hiểm, nhiều mô-đun trong hệ thống phải chứa đoạn mã để đảm bảo rằng những người dùng hợp lệ mới có thể truy cập các các chức năng nghiệp vụ của hệ thống. Hình 1.4. Dàn trải mã nguồn. Với các vấn đề đã phân tích ở trên, quá trình phát triển phần mềm sẽ bị ảnh hưởng với một số vấn đề sau: Ánh xạ giữa các mối quan tâm và cài đặt kém: Việc đồng thời cài đặt nhiều mối quan tâm cũng gây ra hiệu ứng làm giảm thiểu khả năng tư duy ánh xạ giữa một mối quan tâm và mã nguồn cài đặt của nó cho lập trình viên cũng như người kiểm duyệt mã nguồn. Hiệu suất làm việc thấp: Việc đồng thời cài đặt nhiều mối quan tâm làm cho lập trình viên phải phân tán tư tưởng vào nhiều mối quan tâm một lúc, giảm hiệu suất làm việc. Khả năng sử dụng lại mã nguồn kém: Một mô-đun thực tế đã cài đặt rất nhiều mối quan tâm một lúc, nếu như hệ thống khác có nhu cầu sử dụng chức năng tương tự có thể chưa chắc đã sử dụng lại mô-đun này do nó còn phụ thuộc vào các mối quan tâm khác. Chất lượng mã nguồn thấp: Việc chồng chéo mã nguồn trong quá trình cài đặt sẽ gây ra những vấn đề tiềm ẩn mà lập trình viên có thể không phát hiện ra được khi lập trình, do sự chú ý của mình bị ảnh hưởng bởi quả nhiều mối quan tâm.
  • 18. 10 Khó bảo trì hệ thống: Việc xây dựng hệ thống tại thời điểm nào đó thường bị giới hạn trong một khung nhìn với những yêu cầu cụ thể nào đó, thể hiện ở các mối quan tâm hiện có của hệ thống. Nếu như trong tương lai có sự thay đổi nào đó cần bổ sung vào hệ thống, do việc cài đặt không được mô-đun hóa nên việc sửa đổi sẽ làm ảnh hưởng tới rất nhiều mô-đun, có thể gây ra những sửa đổi không đồng bộ và không thống nhất với nhau. Vì thế đòi hỏi thêm chí phí và thời gian để kiểm thử và đảm bảo việc thay đổi trên là không gây ra lỗi. 1.3. Lập trình hướng khía cạnh 1.3.1. Lịch sử hình thành Lập trình hướng khía cạnh (AOP) là một tiếp cận thiết kế phần mềm được phát minh tại trung tâm nghiên cứu Xerox Palo Alto trong những năm 1990. Nó kế thừa các kết quả của các phương pháp lập trình khác như lập trình tự sinh (generative programming), siêu lập trình (meta-programming), lập trình tự điều chỉnh (reflective programming), lập trình có khả năng thích ứng (adaptive programming), lập trình hướng chủ đề (subject-oriented programming), lập trình có mục đích (intentional programming), … Mục đích của AOP là để các nhà thiết kế và các nhà phát triển tách các mối quan tâm cắt ngang mà một hệ thống phần mềm gặp phải tốt hơn. Các mối quan tâm cắt ngang là các phần tử của một hành vi hệ thống không được xác định một cách dễ dàng đối với các thành phần cụ thể trong một kiến trúc ứng dụng. Các mối quan tâm cắt ngang thông thường là xử lý lỗi, các kiểm tra bảo mật, lưu vết các sự kiện, xử lý giao dịch, … Mỗi thành phần trong ứng dụng phải chứa mã đặc trưng cho mỗi mối quan tâm cắt ngang, tạo ra mã của thành phần phức tạp hơn và khó thay đổi hơn. Hình 1.5. Sự khác nhau giữa biên dịch chương trình thông thường và có aspect Để xác định các mối quan tâm cắt ngang, AOP cũng cấp các kỹ thuật cho sự nhận dạng có hệ thống, sự chia tách, sự biểu diễn và kết cấu. Mỗi quan tâm cắt ngang được đóng gói trong các mô-đun riêng gọi là các aspect. Trong quá trình thực thi, các aspect
  • 19. 11 được đan kết vào chương trình thực thi để thực thi các mối quan tâm cắt ngang hệ thống. 1.3.2. Cú pháp của AOP và mô hình lập trình Cắt ngang là một kỹ thuật AOP cho phép nhận dạng các mối quan tâm và cấu trúc chúng vào trong các mô-đun bằng cách chúng có thể được triệu gọi tại các điểm khác nhau thông qua ứng dụng. Có hai loại cắt ngang, tĩnh và động. Cắt ngang động sửa đổi hành vi thực thi của một đối tượng bằng việc đan kết hành vi mới tại các điểm quan tâm cụ thể. Cắt ngang tĩnh thay thế cấu trúc tĩnh của một thành phần bằng việc xen thêm các phương thức và các thuộc tính tại thời điểm thực thi. Các cấu trúc ngôn ngữ cơ bản và cú pháp được sử dụng để khai báo cắt ngang trong AOP như sau: Joint point là một điểm thực thi có thể nhận dạng trong một chương trình. Nó có thể là một lời gọi tới một phương thức hay một lệnh gán cho một thuộc tính của đối tượng. Các joint point là quan trọng, chúng là nơi mà các hành vi của aspect được đan kết vào trong chương trình. Pointcut là một cấu trúc chương trình lựa chọn ra một nhóm các join point và tập hợp ngữ cảnh tại các join point này. Hay nói cách khác, pointcut nhận dạng một joint point trong chương trình mà tại đó một mối quan tâm cắt ngang cần được áp dụng. Ví dụ như, một pointcut có thể lựa chọn một join point là lời gọi tới một phương thức, nó cũng có thể nắm bắt ngữ cảnh của phương thức đó, chẳng hạn như đối tượng đích chứa phương thức được gọi và các tham số của phương thức đó. Pointcut dùng để chỉ ra các quy tắc đan còn join point là các vị trí thỏa mãn các quy tắc đó. Ví dụ sau khai báo một pointcut khi phương thức setValue của lớp Stock được gọi: pointcut log(String msg): args(msg) & execution(void Stock.setValue(float)); Advice là một đoạn mã thực thi logic một mối quan tâm cắt ngang. Nó được thực thi khi một pointcut cụ thể được đạt tới. Advice có thể được thực thi trước (before advice), sau (after advice) hoặc “xung quanh” (around advice) join point. Ví dụ một before advice được cài đặt trong AspectJ: before (String msg): log(msg){ //Đoạn mã thực thi } Introduction là chỉ thị cắt ngang có thể tạo các thay đổi tĩnh đối với các thành phần ứng dụng. Một introduction có thể tạo ra các thay đổi tĩnh cho các mô-đun mà không ảnh hưởng trực tiếp đến các hành vi của chúng. Ví dụ, một instruction có thể thêm một phương thức hoặc một trường vào một lớp trong ứng dụng.
  • 20. 12 Aspect trong AOP tương ứng với một lớp trong lập trình hướng đối tượng. Nó đóng gói các pointcut, các advice và các intruction. Ví dụ một aspect được cài đặt bằng AspectJ: public aspect LoggingModule { pointcut log(String msg):args(msg) & execution(void Stock.setValue(float)); before (String msg): log(msg){ //Đoạn mã thực thi } } Hình 1.6. Mối quan hệ giữa các thuật ngữ AOP 1.3.3. Quản lý các mối quan tâm bằng lập trình hướng khía cạnh Với việc sử dụng các kỹ thuật thiết kế thông thường, một mối quan tâm cắt ngang có thể được mô-đun hóa bằng việc sử dụng một giao diện để đóng gói sự thực hiện mối quan tâm từ việc triệu gọi các thành phần phía client. Mặc dù giao diện làm giảm sự móc nối giữa các client và sự thực thi mối quan tâm, các client vẫn cần mã nhúng để triệu gọi các phương thức giao diện từ bên trong logic nghiệp vụ. Với thiết kế và lập trình hướng khía cạnh, mỗi mối quan tâm cắt ngang được cài đặt một cách riêng rẽ trong một thành phần là aspect. Aspect định nghĩa các điểm thực thi trong các thành phần phía client đòi hỏi sự thực hiện mối quan tâm cắt ngang. Đối với mỗi điểm thực thi, aspect định nghĩa các hành vi cần thiết để thực hiện hành vi của aspect, ví dụ như gọi một API lưu vết. Trong hình 1.7, mối quan tâm cắt ngang là việc
  • 21. 13 lưu vết sự thực thi các mô-đun Subscribing, Claim và Database được cài đặt trong một aspect là Logging aspect. Tiếp đó, Logging aspect có các lời gọi API tới Logging module để thực thi các phương thức cần thiết. Trong quá trình thực thi ứng dụng, Logging aspect được đan tự động vào các mô-đun nghiệp vụ chính để thực hiện việc lưu vết giao dịch. Bộ phận phát triển các mô-đun Subscribing, Claim và Database không cần quan tâm đến việc thực thi việc lưu vết trong quá trình phát triển. Hình 1.7. Thực thi các mối quan tâm cắt ngang bằng AOP. Quan trọng hơn là các mô-đun phía client không chứa bất kỳ mã để triệu gọi sự thực thi aspect nào. Điều này dẫn đến các thành phần phía client không bị xen lẫn bởi các lời gọi để thực thi một hoặc nhiều mối quan tâm. Việc sử dụng một aspect được xác định theo một quy tắc nhất định gọi là quy tắc đan. Các quy tắc đan là đầu vào cho một tiện ích lập trình gọi là bộ đan. Một bộ đan kết hợp mã ứng dụng với các aspect để tạo ra hệ thống cuối cùng. Các ngôn ngữ lập trình hướng khía cạnh như AspectJ cung cấp các công cụ đan kết và vì thế các ngôn ngữ AOP và các công cụ là cần thiết để thực hiện hiệu quả các thiết kế hướng khía cạnh. 1.3.4. Đan kết Việc thực hiện một thiết kế hướng khía cạnh đòi hỏi sự hỗ trợ của ngôn ngữ lập trình để thực thi các aspect riêng lẻ. Ngôn ngữ cũng định nghĩa các luật cho việc đan kết một thực thi của aspect với toàn bộ mã chương trình. Việc đan kết có thể tuân theo một số chiến lược: 1) một bộ tiền xử lý mã nguồn đặc biệt được thực thi trong qua trình biên dịch.
  • 22. 14 2) một bộ hậu xử lý vá các tệp nhị phân. 3) một trình biên dịch nhận biết AOP sinh ra các tệp nhị phân được đan kết. 4) đan kết lúc nạp (load-time weaving – LTW): ví dụ, trong Java việc đan kết advice liên quan bằng việc nạp từng lớp advice vào trong JVM. 5) đan kết lúc thực thi (run-time weaving – RTW): bằng việc chặn từng join point tại thời điểm thực thi và thực thi tất cả các advice liên quan. Hầu hết các ngôn ngữ AOP hỗ trợ việc đan kết lúc biên dịch (CTW) sử dụng một trong ba tùy chọn đầu. Trong Java, trình biên dịch sinh ra các tệp lớp nhị phân Java chuẩn mà bất kỳ JVM chuẩn nào cũng có thể thực thi. Sau đó các tệp .class được sửa đổi dựa trên các aspect đã được định nghĩa. CTW không phải lúc nào cũng là lựa chọn tốt và đôi khi không khả thi (ví dụ với Java Server Page). LTW đưa ra giải pháp tốt hơn và mềm dẻo hơn. Trong Java, LTW đòi hỏi trình nạp JVM để có thể biến đổi các lớp lúc thực thi. JDK v5.0 hỗ trợ tính năng này thông qua một kỹ thuật chuẩn đơn giản. LTW phải xử lý mã bytecode của Java lúc thực thi và tạo các cấu trúc dữ liệu biểu diễn bytecode của một lớp cụ thể. Quá trình xử lý này có thể diễn ra chậm. Một khi tất cả các lớp được nạp, LTW không có ảnh hưởng gì đến tốc độ thực thi của ứng dụng. AspectJ [11, 13, 26], JBoss AOP [27] và AspectWerkz [28] hiện hỗ trợ LTW. RTW là một lựa chọn tốt nếu các aspect phải có hiệu lực lúc đang chạy. Tuy nhiên, như LTW, RTW có thể có những nhược điểm về mặt hiệu suất tại thời điểm thực thi trong khi các aspect đang được đan kết. 1.3.5. Phương pháp lập trình hướng khía cạnh Hiện nay phương pháp lập trình hướng khía cạnh đang được quan tâm phát triển và đang dần được hoàn thiện. Phương pháp này không phải thay thế các phương pháp lập trình truyền thống mà là bổ sung và làm phong phú thêm phương pháp lập trình truyền thống. AOP cung cấp một giải pháp cho việc pháp triển các hệ thống bằng việc tách các mối quan tâm cắt ngang thành các mô-đun và ghép nối lỏng các mô-đun này vào các mối quan tâm nghiệp vụ chính của hệ thống. Về cơ bản quá trình phát triển phần mềm theo AOP gồm có 3 bước sau đây: 1) Phân tích các yêu cầu để xác định vấn đề chung và vấn đề đan nhau: trong bước này ta sử dụng phương pháp phân tích và thiết kế hướng khía cạnh (Aspect- Oriented Analyis and Design) để phân tích các yêu cầu của bài toán nhằm tách các mối quan tâm nghiệp vụ chính và mối quan tâm cắt ngang hệ thống. Sau bước này ta thu được bản phân tích mà các mối quan tâm nghiệp vụ chính và các mối quan tâm cắt ngang được tách riêng. 2) Xây dựng thể hiện từng vấn đề riêng biệt: sau khi các mối quan tâm cắt ngang được tách ra khỏi các mối quan tâm nghiệp vụ chính thì ta có thể dùng phương pháp lập trình truyền thống như lập trình hướng thủ tục hoặc lập trình hướng đối tượng để
  • 23. 15 cài đặt các mối quan tâm nghiệp vụ chính, còn các mối quan tâm cắt ngang thì được cài đặt trong một aspect theo quy tắc mà công cụ AOP được sử dụng quy định. Như vậy, mối quan tâm nghiệp vụ chính được xây dựng độc lập với các mối quan tâm cắt ngang. Hình 1.8. Các giai đoạn phát triển AOP 3) Tổng hợp các thể hiện: sau khi các mối quan tâm nghiệp vụ chính và các mối quan tâm cắt ngang được cài đặt một các riêng rẽ, để hệ thống có thể hoạt động được thì các mối quan tâm cần phải được kết hợp theo một số quy tắc nào đó. Quá trình kết hợp này gọi là quá trình tích hợp hay quá trình đan được thực hiện bằng cách sử dụng các quy tắc đan. Sau quá trình đan ta nhận được hệ thống cuối cùng mà các mối quan tâm nghiệp vụ chính và mối quan tâm cắt ngang đã được đan kết với nhau để thực hiện mục tiêu theo yêu cầu. Ví dụ một luật tích hợp: “Tất cả các hoạt động của hệ thống cần phải được lưu vết lại” sẽ được cài đặt trên một ngôn ngữ AOP nào đó để chỉ ra các quy tắc đan. Như vậy, mối quan tâm lưu vết sẽ được bộ đan tích hợp vào các mô-đun nghiệp vụ theo đúng quy tắc chỉ ra. 1.3.6. Lợi ích của lập trình hướng khía cạnh AOP là một kỹ thuật mới đầy triển vọng, hứa hẹn đem lại nhiều lợi ích cho việc phát triển phần mềm. Việc cấu trúc hóa các ứng dụng với các aspect và thực thi trực tiếp bằng sử các ngôn ngữ lập trình hướng khía cạnh có khả năng cải thiện chất lượng các hệ thống phần mềm. Các aspect tạo ra các hệ thống phần mềm lớn và phức tạp có thể được sản xuất và tổ chức lại đơn giản hơn và cho chất lượng cao hơn. Dưới đây là một số lợi ích chính của AOP: Có thể nhận dạng và miêu tả một cách rõ ràng các mối quan tâm cắt ngang giúp các kiến trúc sư có thể xem xét các hành vi cắt ngang dưới dạng các aspect tại giai đoạn sớm của vòng đời dự án. Phân chia trách nhiệm rõ ràng cho các mô-đun riêng lẻ: AOP cho phép tách các mối quan tâm cắt ngang ra khỏi các mối quan tâm nghiệp vụ chính. Do vậy một
  • 24. 16 mô-đun chỉ nhận trách nhiệm với mối quan tâm nghiệp vụ chính của nó mà không cần có nghĩa vụ gì với các mối quan tâm cắt ngang nó. Ví dụ như, một mô-đun thực hiện một giao dịch nghiệp vụ chính và các thông tin thay đổi trong quá trình thực hiện giao dịch phải được lưu lại thì nó chỉ cần quan tâm đến việc thực hiện giao dịch mà không cần quan tâm đến thao tác lưu vết giao dịch. Việc lưu vết giao dịch sẽ được thực hiện trong một aspect bằng AOP. Điều này giúp cho việc phân chia trách nhiệm rõ ràng hơn và khả năng theo dõi được cải thiện. Dễ dàng phát triển hệ thống: AOP mô-đun hóa các aspect riêng lẻ do đó khi hệ thống cần chức năng mới, nhà phát triển chỉ cần tạo ra một aspect thực hiện các yêu cầu mới đó mà không cần thay đổi các mô-đun nghiệp vụ chính. Khi thêm mô-đun mới đó vào hệ thống, các aspect hiện có sẽ đan kết với chúng và tạo nên sự phát triển chặt chẽ. Như vậy hệ thống sẽ đáp ứng nhanh hơn với những yêu cầu mới. Tái sử dụng mã nguồn: AOP cho phép các nhà phát triển dễ dàng sử dụng lại mã nguồn của một aspect trong nhiều thành phần và do đó giảm các nỗ lực thể hiện mã chương trình. Khả năng mô-đun hóa và đóng gói: AOP làm tăng tính mô-đun hóa và đóng gói như mã thành phần tốt hơn ngắn gọn và gọn gàng. Cho phép để lại quyết định thiết kế tương lai: Một thiết kế tốt phải tính đến cả yêu cầu hiện tại và tương lai, việc xác định yêu cầu tương lai là một công việc khó khăn. Nếu bỏ sót những yêu cầu tương lai có thể sẽ phải thay đổi hay thực hiện lại nhiều phần hệ thống. Với AOP, người thiết kế hệ thống có thể để lại các quyết định thiết kế cho những yêu cầu tương lai nhờ thực hiện theo các aspect riêng biệt. Rút ngắn thời gian bàn giao sản phẩm: Việc kết nối muộn các giải pháp thiết kế giúp cho chu trình thiết kế được nhanh hơn. Bên cạnh đó, việc tách biệt rõ ràng các trách nhiệm của các mô-đun giúp cho người lập trình không gặp nhiều khó khăn trong việc thực thi các mô-đun, từ đó tăng năng suất làm việc của các nhà lập trình. Việc tái sử dụng mã nguồn tốt hơn giúp giảm thời gian phát triển hệ thống. Hơn thế nữa, hệ thống tiến triển dễ dàng hơn giúp cho hệ thống có thể đáp ứng nhanh hơn với các yêu cầu mới. Tất cả những điều trên giúp cho hệ thống có thể phát triển và triển khai nhanh hơn. Giảm thiểu chi phí thực thi: Bằng cách tránh việc sửa đổi nhiều mô-đun khi phải cài đặt một chức năng cắt ngang, AOP giúp giảm chi phí cài đặt các chức năng cắt ngang. Với AOP, các lập trình viên có thể tập trung vào các chức năng chính của của các mô-đun nghiệp vụ và tận dụng được khả năng chuyên môn của họ vào các công việc chính nên chi phí của các yêu cầu nghiệp vụ chính cũng được giảm xuống. Như vậy, việc thực thi các chức năng của toàn hệ thống sẽ được giảm thiểu đáng kể.
  • 25. 17 1.3.7. Nhược điểm của phương pháp lập trình hướng khía cạnh Phương pháp lập trình hướng khía cạnh có nhiều ưu điểm kể trên, tuy nhiên nó cũng có một số hạn chế sau: Liệu các aspect có phá vỡ tính đóng gói của các đối tượng? Bình thường các aspect tuân theo các luật điều khiển truy cập. Bằng cách này hay cách khác, các aspect có thể phá vỡ tính đóng gói của các đối tượng. Nhưng chúng làm theo cách có thể kiểm soát được. Các aspect có thể truy cập đến phần riêng tư của các đối tượng mà chúng tham chiếu đến nhưng không làm tổn hại đến sự đóng gói giữa các đối tượng của các lớp khác nhau. Ví dụ trong AspectJ, để bỏ qua các luật truy cập ta thêm bổ ngữ đặc biệt privileged vào trước từ khóa aspect: privileged aspect EmployeeVerifier { pointcut verify_experience(Manager staff, int val): target(staff)&& set(int Manager.experience)&& args(val); void around(Manager staff, int val): verify_experience(staff, val) { if(val<3) { System.out.println("Manager.experience>=3"); } else{ proceed(staff, val); } } } Trong ví dụ này, ta có thể truy cập đến thuộc tính experience của lớp Manager cho dù nó có được bảo vệ bởi từ khóa private hoặc protected hay không. Giảm hiệu suất thực thi trong trường hợp thực hiện đan kết lúc thực thi hoặc tốn thời gian nạp chương trình trong trường hợp thực hiện đan kết lúc nạp chương trình. Khi chúng ta mắc sai lầm trong việc diễn đạt thực thi cắt ngang có thể gây lỗi tràn ngập toàn chương trình. Việc thay đổi các joint point của một chương trình (ví dụ như đổi tên hay di chuyển các phương thức) mà không được lường trước bởi người viết aspect sẽ gây ra các lỗi. Vấn đề bảo mật có thể bị phá vỡ bởi việc sử dụng AOP để cài thêm các đoạn mã tại các vị trí phù hợp.
  • 26. 18 1.3.8. Các công cụ AOP Mô hình cơ sở của AOP là mô hình join point. Tất cả các công cụ dùng mô hình này để cung cấp phương tiện nhận dạng nơi mà các mối quan tâm cắt ngang được áp dụng. Tuy nhiên, các công cụ khác nhau thực hiện các mô hình aspect theo cách của nó và đưa ra các ngữ nghĩa và kỹ thuật đan kết các aspect mới. Ví dụ, trong JBoss AOP [27], các advice được thực thi thông qua bộ chặn (interceptor) sử dụng Java reflection và các pointcut được khai báo trong một tập XML mô tả nơi để đan kết trong một advice một cách tự động tại thời điểm thực thi. Trong AspectJ, cả advice và pointcut được khai báo trong một lớp aspect và được đan kết tĩnh. Tính đa dạng này trong các công cụ AOP là khó giải quyết đối với phát triển phần mềm sử dụng aspect vì sự khác nhau về ngữ nghĩa của các mô hình AOP và các cách khác nhau một aspect được đan kết với các lớp khác. Khó có thể phát triển lại một cách đơn giản một aspect đang tồn tại để nó có thể đan kết với các aspect được phát triển bởi mô hình AOP khác. Để giải quyết vấn đề này, AspectWerkz [28] đã đề xuất một mô hình kiến trúc mở cho một bộ chứa aspect (aspect container) đối với các công cụ Java dựa trên AOP. Ý tướng cơ bản là để cung cấp một bộ đan và một bộ chứa (container) có thể đan, triển khai và chạy bất kỳ aspect không quan tâm đến việc nó được cài đặt và khai báo như thế nào. Nó có trách nhiệm giải quyết sự khác nhau giữa các mô hình aspect. Một bể chứa như vậy có thể cho phép các aspect được phát triển bởi các mô hình AOP và công cụ khác nhau cùng tồn tại trong một môi trường thực thi. Hiện tại, AspectWerkz đã thực hiện một mô hình mở rộng cho các aspect thực hiện các giao tiếp AOP Alliance, Spring AOP [8, 24] và AspectJ [11, 13, 26]. Thiết kế và thực thi hướng khía cạnh đòi hỏi sự hỗ trợ của các công cụ AOP hiệu quả. Với các công cụ này, các nghiên cứu và phát triển đang tiến hành đang cố gắng cung cấp các giải pháp tốt hơn trong một số phạm vi như bảo trì, hiệu suất, tích hợp, … Bảo trì: việc thiết kế các hệ thống hướng khía cạnh chất lượng có nghĩa là chú tâm đến việc định nghĩa các pointcut lan tỏa và việc sử dụng quyền thừa kế các aspect một cách hợp lý. Các pointcut bắt giữ nhiều joint point hơn mong đợi hay bỏ xót các joint point mong muốn có thể gây đổ vỡ hệ thống khi được cải tiến. Do vậy một công cụ gỡ lỗi hiệu quả là cần thiết để dò tìm sự thực thi các joint point và các point cut lỗi. Hiệu suất: việc sử dụng AOP tăng thêm các chi phí về hiệu suất trong các ứng dụng, cả trong quá trình đan kết và tiềm tàng lúc thực thi. AOP cần giảm thời đan kết và biên dịch đông thời tăng hiệu suất thực thi.
  • 27. 19 Tích hợp: việc sử dụng lại các aspect không được khám phá đầy đủ sẽ khiến các các nhà phát triển các thư viện aspect từ các aspect bị lỗi. Mỗi công cụ AOP chỉ cung cấp sự thực hiện các aspect cho mô hình của công cụ đó. Một aspect được thực hiện bằng một mô hình AOP cụ thể không thể được đan kết một cách dễ dàng bằng một mô hình AOP khác. Đây là chướng ngại vật lớn trong việc phát triển phần mềm hướng khía cạnh. 1.4. AspectJ Lập trình hướng khía cạnh là cách mô-đun hóa các mối quan tâm cắt ngang giống như lập trình hướng đối tượng là cách để mô-đun hóa các mối quan tâm thông thường. AspectJ [11, 13, 26] là một thực thi lập trình hướng đối tượng cho ngôn ngữ lập trình Java. AspectJ mở rộng một số khái niệm của ngôn ngữ Java. Trình biên dịch AspectJ sẽ biên dịch các từ khóa cụ thể của AspectJ thành byte-code và tạo điều kiện thuận lợi cho việc đan kết các byte-code vào trong một tệp lớp (.class). Một aspect sẽ được biên dịch thành mã aspect được chứa trong một lớp và các cấu trúc cụ thể khác của AspectJ được chuyển đổi thành Java chuẩn. Trình biên dịch AspectJ đan kết aspect dưới dạng byte-code vào trong byte-code của ứng dụng chính và tạo ra các tệp lớp Java phù hợp có thể thực thi được bởi máy ảo Java. Để thực hiện AOP bằng AspectJ nhà phát triển tách biệt hai phần: Phần đặc tả ngôn ngữ và phần thực thi ngôn ngữ. Phần đặc tả ngôn ngữ định nghĩa ngôn ngữ viết mã chương trình. Với AspectJ, các mối quan tâm nghiệp vụ chính được cài đặt trên ngôn ngữ lập trình Java còn các mối quan tâm cắt ngang và các quy tắc đan được cài đặt trên các mở rộng của AspectJ. Phần thực thi ngôn ngữ cung cấp các công cụ biên dịch, gỡ lỗi và tích hợp với các môi trường phát triển tích hợp khác phổ biến [11, 13]. Trong AOP, công việc kết hợp (đan - weaving) mối quan tâm cắt ngang với các mối quan tâm nghiệp vụ chính được thực hiện dựa trên các quy tắc đan. Các quy tắc đan chỉ ra hành động nào được thực hiện khi một số điểm nào đó trong quá trình thực thi chương trình xảy ra. Với AspectJ khi thực thi AOP, trình biên dịch AspectJ sử dụng các mô-đun cài đặt các mối quan tâm cắt ngang chứa các quy tắc đan (các aspect) để chèn thêm hành vi mới cho các mô-đun cài đặt các mối quan tâm nghiệp vụ chính mà không cần thay đổi mã nguồn của các mô-đun nghiệp vụ chính. Việc đan mã nguồn nghiệp vụ chính với các aspect chỉ thực hiện trong byte-code mà trình biên dịch sinh ra. 1.4.1. Thực thi cắt ngang Như ở phần trên đã trình bày về các loại đan kết. AspectJ hỗ trợ tất cả các loại đan kết bao gồm đan kết lúc biên dịch (CTW), đan kết lúc nạp chương trình (LTW) và đan kết lúc chương trình đang thực thi (RTW). Việc đan kết này còn được gọi là thực thi cắt ngang (crosscutting). Việc đan kết phải tuân theo các quy tắc nhất định gọi là các quy tắc đan. Các quy tắc đan này cắt ngang nhiều mô-đun một cách có hệ thống
  • 28. 20 nhằm mô-đun hóa các mối quan tâm cắt ngang. AspectJ định nghĩa ra hai loại thực thi cắt ngang, đó là thực thi cắt ngang tĩnh (static crosscutting) và thực thi cắt ngang động (dynamic crosscutting). Thực thi cắt ngang tĩnh: là việc đan hay chèn thêm các sửa đổi vào trong một lớp, giao diện hay aspect của hệ thống hoặc thay đổi tính thừa kế hay thực thi giao diện của các lớp trong cây thừa kế. Thực thi cắt ngang tĩnh còn được sử dụng để khai báo các cảnh báo và lỗi tại thời điểm biên dịch. Thông thường thực thi cắt ngang tĩnh là để chuẩn bị hay hỗ trợ cho thực thi cắt ngang động. Thực thi cắt ngang động: là việc đan hành vi mới vào quá trình thực thi của chương trình. Việc đan hành vi mới theo cách cắt ngang nhiều môđun vì thế làm thay đổi hành vi của hệ thống. Ví dụ muốn chèn thêm một hành động lưu vết sau khi lưu dữ liệu vào cơ sở dữ liệu ta chỉ cần chỉ ra điểm đan là điểm sau thao tác lưu dữ liệu kết thúc. AspectJ sử dụng các cú pháp mở rộng cho ngôn ngữ lập trình Java để chỉ ra các quy tắc đan cho việc thực thi cắt ngang động và thực thi cắt ngang tĩnh. Để thực hiện các quy tắc đan một cách tự động, AspectJ sử dụng các cấu trúc và bộ mô tả sau để mô tả việc cài đặt các mối quan tâm cắt ngang hệ thống như: Join point, point cut, advice, introduction, chỉ thị biên dịch và aspect. 1.4.2. Joint Point Bộ biên dịch AspectJ cần tìm các vị trí trong mã nguồn hoặc byte-code nơi mà các hành vi mới được đan vào được thực thi. Những điểm có thể xác định đó được gọi là các joint point. Đó có thể là một lời gọi đến một phương thức hoặc lệnh đọc hay gán đối với một thành viên của một đối tượng. Một số join point chính trong AspectJ như sau: Joint point triệu gọi phương thức (Method call join point): xảy ra khi bất kỳ lời gọi phương thức nào được thiết lập bởi một đối tượng hay một phương thức tĩnh. Joint point này nằm trong một đối tượng hay ứng dụng triệu gọi phương thức, thường là nằm trong các phương thức triệu gọi phương thức đang xét. Chúng ta xem xét ví dụ sau: ATMcard c=new ATMcard (0, 3000); c.withdrawMoney(4000);//<--withdrawMoney() method call joint point Trong ví dụ này, một joint point triệu gọi phương thức được thiết lập tại vị trí triệu gọi phương thức c.withdrawMoney(4000) đang xét. Joint point triệu gọi phương thức khởi tạo (Constructor call joint point): xảy ra khi một phương thức khởi tạo đối tượng được triệu gọi trong quá trình tạo mới một
  • 29. 21 đối tượng. Joint point này xảy ra bên trong đối tượng hay ứng dụng triệu gọi phương phức khởi tạo đối tượng. Chúng ta xem xét đoạn mã sau: ATMcard c = new ATMcard (0, 3000); Trong ví dụ này, một joint point xảy ra khi lệnh new kích hoạt một joint point triệu gọi phương thức. Join point thực thi phương thức (Method execution joint point): xảy ra khi một phương thức của một đối tượng được triệu và chuyển điều khiển cho phương thức được triệu gọi đó. Joint point này xảy ra trên đối tượng nhận lời gọi phương thức và trước khi các đoạn mã của phương thức được thực thi. Joint point thực thi phương thức khởi tạo (Constructor execution joint point): giống như joint point thực thi phương thức nhưng xảy ra trước khi đoạn mã khởi tạo được thực thi. Field get joint point: xảy ra khi một thuộc tính của một đối tượng được đọc, tham chiếu hay lấy giá trị. Đoạn mã sau đây minh họa một field get joint point xảy ra khi thuộc tính balanceAmount của lớp ATMCard được lấy giá trị: class ATMCard { int balanceAmount; … public void printAccountBalance(){ System.out.print(“Balance amount is “ + balanceAmount // <-- field get joint point + …); } … } Field set joint point: xảy ra khi một thuộc tính của một đối tượng được gán giá trị. Đoạn mã sau minh họa một field set joint point xảy ra khi thuộc tính balanceAmount được gán giá trị mới: class ATMCard { int balanceAmount; … public void withdrawMoney(int amount){ balanceAmount-=amount; <-- field set joint point } …
  • 30. 22 } Exception handler execution joint point: xảy ra khi một xử lý ngoại lệ được thực thi. Ngoài ra còn một số loại join point khác như: Class initialization join point, Object initialization join point, Object pre-initialization join point, Advice execution join point. Chi tiết các loại join point này có thể xem chi tiết trong các tài liệu [11, 13]. 1.4.3. Pointcut Pointcut là một cấu trúc chương trình lựa chọn ra một nhóm các join point và tập hợp ngữ cảnh tại các join point này. Nó chỉ ra một cách trực tiếp một mối quan tâm sẽ cắt ngang ứng dụng chính như thế nào. Pointcut hợp lệ ngang qua tất cả các đối tượng được thể hiện từ các lớp và nếu bạn có một số lượng lớn các đối tượng, bạn nên lường trước một số lượng lớn các so khớp. Pointcut dùng để chỉ ra các quy tắc đan còn join point là các vị trí thỏa mãn các quy tắc đó. Một bộ mô tả pointcut (pointcut designator) dùng để xác định pointcut bằng tên hoặc bằng một biểu thức. Ta có thể khai báo một pointcut trong một aspect, một lớp hoặc một giao diện. Giống như dữ liệu và phương thức, ta có thể sử dụng một định danh phạm vi truy cập (public, private,...) để giới hạn quyền truy cập đến pointcut. Định dạng tổng quát của pointcut như sau: <pointcut> ::= <access_type> <pointcut_name> ({ <parameters> }) : { designator [ && | || ] }; <access_type> ::= public | private [abstract] <pointcut_name> ::= { <identifier> } <parameters> ::= { <identifier> <type> } <designator> ::= [!]Call | execution | target | args | cflow | cflowbelow | staticinitialization | within | if | adviceexecution | preinitialization <identifier> ::= ký tự { ký tự | số } <type> ::= kiểu Java hợp lệ Chúng ta đặt pointcut vào bên trong một cấu trúc aspect và sử dụng nó để so khớp các joint point trong mã. Kiểu truy cập của pointcut có thể là public hoặc private (tùy thuộc vào các lưu ý thiết kế) và chỉ ra phạm vi của pointcut trong aspect/class. Phạm vi truy cập mặc định là trong phạm vi gói (package) và do vậy chúng ta phải cung cấp kiểu truy cập cụ thể cần thiết cho pointcut. Sau kiểu truy cập là tên của pointcut. Tên này là chuỗi được sử dụng để biểu diễn pointcut bên trong aspect/class.
  • 31. 23 Tên tương tự như tên phương thức được sử dụng trong một lớp Java truyền thống. Bên trong ngữ cảnh của một aspect hay class, tất cả các pointcut phải có một tên duy nhất, điều đó có nghĩa là không nập chồng được pointcut trong AspectJ. Tên của pointcut có thể chứa một số tham số. Các tham số này được sử dụng để chuyển giao ngữ cảnh được kéo từ một joint point. Ngữ cảnh có thể được chuyển giao tới một cấu trúc aspect hoặc các joint point khác. Sau các tham số của pointcut là dấu hai chấm và một hoặc nhiều bộ mô tả pointcut. Bộ mô tả cung cấp một định nghĩa xung quanh joint point được sử dụng trong pointcut. Nếu một pointcut muốn có nhiều bộ mô tả, bạn phải sử dụng các toán tử lôgic để tạo sự kết nối. Java cũng cấp khả năng tạo các cấu trúc không được đặt tên hay nặc danh. AspectJ cũng cung cấp khả năng này, trong một cấu trúc được gọi là pointcut nguyên bản (primitive pointcut). Pointcut nguyên bản không có tên và chỉ bao gồm các bộ mô tả joint point. Như ta đã đề cập, pointcut lựa chọn một tập một hay nhiều joint point để xác định hành động dự định của chúng. Khi joint point được đạt tới trong mã ứng dụng chính, pointcut sẽ được kích hoạt và một số đoạn mã (advice) được thực thi tiềm tàng. Chúng ta sẽ chỉ ra bộ miêu tả hành động như thế nào trong một ứng dụng AspectJ. Tất cả các bộ mô tả được viết dưới định dạng sau: designator ::= designator_identifier(<signature> | <typePattern> | <pointcut>) <designator_identifier> ::= Call | execution | target | args | cflow | cflowbelow | staticinitialization | within | if | adviceexecution | preinitialization <typePattern> ::= Kiểu lớp Java <pointcut> - được định nghĩa ở trên Tham số trong bộ miêu tả là một joint point signature hay một kiểu lớp joint point hay một pointcut khác. Một joint point signature nhìn chung biểu diễn chữ ký (signature) của một phương thức, một phương thức khởi tạo trong một lớp hay một kiểu. Có thể có một số ký tự đại diện trong chữ ký. Trong trường hợp một joint point khởi tạo phương thức, chữ ký bao gồm lời gọi hàm new(). Đối với một joint point kiểu lớp, tham số là tên của một lớp trong ứng dụng. Chúng ta cũng có thể sử dụng các ký tự đại diện với các kiểu lớp.
  • 32. 24 Để chỉ ra một nhóm các join point, phần chữ ký (signature) của pointcut chứa các ký tự đại diện (wildcard) và các toán tử. Trong AspectJ, có 3 loại ký tự đại diện và 2 loại toán tử. Ký tự đại diện: “*”: Chỉ ra số lượng bất kỳ các ký tự trừ dấu chấm (“.”). “..”: Chỉ ra số lượng bất kỳ các ký tự, chứa cả dấu chấm. “+”: Chỉ ra bất kỳ lớp con hoặc giao diện con nào. Toán tử: Toán tử một ngôi: AspectJ chỉ cung cấp duy nhất một toán tử một ngôi “!” cho point cut: Toán tử phủ định cho phép phù hợp tất cả các join point trừ join point mà point cut chỉ ra bằng toán tử “!”. Toán tử hai ngôi: “||” (Hoặc) và “&&” (Và) để kết nối các pointcut với nhau. Hình 1.9 minh họa ví dụ về định nghĩa pointcut với tên accountOperations(). Point cut này sẽ nắm bắt toàn bộ các phương thức trong lớp Account. Hình 1.9. Ví dụ về định nghĩa pointcut Sau đây chúng tôi liệt kê các bộ mô tả pointcut một cách ngắn ngọn, chi tiết về các bộ mô tả này có thể xem trong các tài liệu [11, 13]: execution – So khớp sự thực thi của một phương thức hay một phương thức khởi tạo. Ví dụ: pointcut p(): execution(int ATMCard.withdrawMoney(..)); call – So khớp các lời gọi tới một phương thức hay một phương thức khởi tạo. Ví dụ: pointcut p(): call(int ATMCard.withdrawMoney(..)); initialization – So khớp sự thực thi của phương thức khởi tạo đầu tiên tới một lớp. Ví dụ: pointcut p() : initialization(ATMCard.new(..));
  • 33. 25 handler – So khớp các ngoại lệ. Ví dụ: pointcut p() : handler(Throwable+); get – So khớp sự tham chiếu tới một thuộc tính của lớp. Ví dụ: pointcut p() : get(int ATMCard.accountBalance); set – So khớp sự gán giá trị của một thuộc tính của lớp. pointcut p() : set(int ATMCard.accountBalance); this – Trả lại đối tượng liên kết với một joint point cụ thể. Ví dụ: pointcut p() : this(ATMCard); target – Trả lại đối tượng đích của một join point. Ví dụ: pointcut p() : target(ATMCard); args – Đặt các tham số cho các joint point. Ví dụ: pointcut p() : args(int); cflow – Trả lại các joint point trong luồng thực thi của một joint point khác. Ví dụ: pointcut p() : cflow(q()); pointcut q() : call(int ATMCard.withdrawMoney(..)); cflowbelow – Trả lại các joint point trong luồng thực thi của một join point khác nhưng không bao gồm join point hiện tại. Ví dụ: pointcut p() : cflowbelow(q()); pointcut q() : call(int ATMCard.withdrawMoney(..)); staticinitialization – So khớp sự thực thi của mã khởi tạo tĩnh của một lớp. Ví dụ: pointcut p() : staticinitialization(ATMCard); withincode – So khớp các joint point bên trong một phương thức hay phương thức khởi tạo. Ví dụ: pointcut p(): withincode(int ATMCard.withdrawMoney(..)); within – So khớp các joint point bên trong một kiểu cụ thể. Ví dụ: pointcut p(): within(ATMCard); if – Cho phép một điều kiện động là một phần của một pointcut. Ví dụ: pointcut p(): if( thisJoinPoint.getTarget() == null
  • 34. 26 && thisJoinPoint.getThis() == null); adviceexecution – So khớp trên các advice join point. preinitialization – So khớp các joint point tiền khởi tạo. 1.4.4. Advice Advice là một đoạn mã được thực thi tại một join point đã được lựa chọn bởi một pointcut. Advice có thể được thực thi trước (before advice), sau (after advice) hoặc “xung quanh” (around advice) join point. Around advice có thể chỉnh sửa đoạn mã tại join point, nó có thể thay thế, thậm chí bỏ qua sự thực thi của đoạn mã đó. Sử dụng advice, ta có thể đưa ra thông báo trước khi thực thi đoạn mã tại các điểm join point xác định trên một vài mô-đun. Phần thân của advice gần giống với thân của phương thức. Nó sẽ được thực thi khi một join point được so khớp. Before advice: có dạng sau: before(FormalParameters) : Pointcut {Body} Thân của advice được thực thi trước khi joint point được chọn bới pointcut của nó được đạt tới. Ta xét ví dụ sau: public aspect AdviceBefore { before() : call(* AdviceMain.*Str(..)) { System.out.println(thisJoinPoint); } } Trong ví dụ, advice không được đặt tên và chỉ được thực thi khi một pointcut không tên chọn các lời gọi đối với các phương thức của lớp AdviceMain mà tên của nó kết thúc bằng Str. After advice: thân của advice này thực thi sau joint point tương ứng. Vấn đề là không phải tất cả các trường hợp của after advice được tạo ra giống nhau. Để xác định vấn đề này, AspectJ cung cấp ba phiên bản của after advcie: dạng đơn giản, dạng trả lại giá trị (after returning advice), và dạng chỉ tương tác với các ngoại lệ (after throwing advice). Dạng đơn giản – luôn luôn chạy – có cú pháp giống như before advice after(FormalParameters) : Pointcut {Body} Ví dụ sau thực thi tương tự như AdviceBefore aspect nhưng chỉ sau khi các lời gọi trở lại: public aspect AdviceAfter { after() : call(* AdviceMain.*Str(..)) {
  • 35. 27 System.out.println(thisJoinPoint); } } After returning advice: chỉ chạy nếu đoạn mã tại các joint point thực thi bình thường, không ném bất kỳ ngoài lệ nào. Cú pháp như sau: after(FormalParameters) returning [(OneFormalParameter)]: Pointcut {Body} Ngoài các tham số được cung cấp bởi pointcut, advice có thêm một tham số. Nó có thể có đối tượng được trả lại tại joint point nếu đối tượng đó được thể hiện bằng việc cung cấp sự khai báo trực tiếp sau từ khóa returning. Ví dụ: after() returning(Object o) : call(* AdviceMain.*Str(..)) { System.out.println(“#1: “+thisJoinPoint+” Returning Object: “+AdviceMain.className(o)+” - “+o); } After throwing advice: chạy một cách đúng đắn trong khi after returning advice thì không khi có một ngoại lệ được ném tại joint point. Cú pháp cho phép ngoại lệ được ném có trong thân của advice được đặt vào như các tham số hình thức khác. Cú pháp như sau: after(FormalParameters) throwing [(OneFormalParameter)]: Pointcut {Body} Sau đây là ví dụ về cách sử dụng after throwing advice: after() throwing(Exception o): call(* AdviceMain.*Str(..)) { System.out.println(“#1: “+thisJoinPoint+” Throwing Exception: “+AdviceMain.className(o)+” - “+o); } Around advice: là một trong các đặc tính mạnh nhất của ngôn ngữ AspectJ. Nó cho phép thay thế joint point bằng một đoạn mã tùy ý. Cú pháp như sau: ReturnType around(FormalParameters) [throws ListOfExceptionTypes]: Pointcut {Body} Với around advice không nên ném các các ngoại lệ mà mã đích không thể xử lý được. Bên trong thân của advice thường có một lời gọi đến hàm đặc biệt cho phép around advice thực thi mã tại joint point gốc. proceed(arguments); Hàm proceed() có các tham số truyền vào là các tham số trong phần tên của pointcut ứng với advice đó và kiểu giá trị trả về là kiểu đã được khai báo của advice.
  • 36. 28 Nếu không có các tham số trong pointcut, hàm proceed() không cần các tham số. Ví dụ sử dụng hàm proceed() không có tham số: Object around(): call(* AdviceMain.*Str(..)) { Object result = proceed(); System.out.println(thisJoinPoint+” Result: “+ AdviceMain.className(result)+” - “+result); return result; } và hàm proceed() có tham số: Object around(String s): call(* AdviceMain.*Str(String)) && args(s) { Object result = proceed(s); System.out.println(thisJoinPoint+” Parameter: [“ + s + “] Result: “+AdviceMain.className(result)+” - “ + result); return result; } Thứ tự ưu tiên của advice: nếu hai hay nhiều advice cùng chia sẻ một joint point, ta cần phải xem xét thứ tự ưu tiên thực hiện của các advice. Đối với các advice giữa các aspect ta xác định thứ tự ưu tiên các advice như sau: 1) Khai báo thứ tự ưu tiên của các aspect bằng câu lệnh declare precedence. Ví dụ sau nói lên rằng aspect A có thứ tự ưu tiên hơn aspect B. declare precedence : A, B; 2) Nếu một aspect kế thừa một aspect khác thì advice trong aspect con nhận thứ tự ưu tiên cao hơn advice trong aspect cha. Điều này cho phép aspect con ghi đè hành vi của aspect cha. 3) Ngoài các trường hợp trên thì không xác định được thứ tự ưu tiên. Chúng sẽ thực thi theo thứ tự không xác định. Đối với các advice trong cùng một aspect thì thứ tự ưu tiên của chúng được xác định bởi thứ tự và kiểu của chúng. Có hai tình huồng chính: 1) Nếu có một trong số advice là after advice thì advice được khai báo sau trong tệp tin sẽ có thứ tự ưu tiên cao hơn.
  • 37. 29 2) Nếu không có advice nào là after advice thì advice nào được khai báo trước trọng tệp tin sẽ có thứ tự ưu tiên cao hơn. Ví dụ có ba advice theo thứ tự sau: Before1 Before2 After Dựa vào luật 2 ta có Before1>Before2. Dựa vào luật 1 ta có After>Before1 và After>Before2. Kết hợp hai kết quả trên ta có thứ tự ưu tiên như sau: After > Before1 > Before2 Hiệu ứng của tính ưu tiên: tại một joint point cụ thể, advice được thực hiện theo thứ tự ưu tiên. Đoạn mã của around advice hiện tại có thể điều khiển việc có cho phép advice có thứ tự ưu tiên thấp hơn chạy hay không. Để cho phép advice có độ ưu tiên thấp hơn chạy bằng việc gọi hàm proceed(). Lời gọi đến hàm proceed() sẽ chạy advice có thứ tự ưu tiên tiếp theo hoặc tính toán tại joint point nếu không có adviec nào nữa. Đoạn mã của before advice có thể ngăn advice có thứ tự ưu tiên thấp hơn chạy bằng việc ném một ngoại lệ. Nếu nó chạy bình thường mà không ném ngoại lệ thì advice có thứ tự ưu tiên kế tiếp sẽ chạy hoặc tính toán tại joint point nếu không có advice nào nữa. Việc chạy after returning advice sẽ chạy advice có thứ tự ưu tiên tiếp theo hoặc tính toán tại joint point nếu không có advice nào nữa. Sau đó nếu việc tính toán trả về bình thường, thân của advice sẽ chạy. Việc chạy after throwing advice sẽ chạy advice có độ ưu tiên tiếp theo hoặc tính toán tại joint point nếu không có advice nào nữa. Sau đó nếu sự tính toán ném một ngoại lệ có kiểu thích hợp, thân của advice sẽ chạy. Việc chạy after advice sẽ chạy advice có thứ tự ưu tiên tiếp theo hoặc tính toán tại joint point nếu không có advice nào nữa. Sau đó thân của advice sẽ chạy. 1.4.5. Introduction Một introduction là kỹ thuật của AspectJ nhằm sửa đổi các lớp và thứ bậc của chúng bằng việc đưa vào hay chèn mã mới vào một lớp đích của một ứng dụng, hay bằng việc thay đổi tính thừa kế hay thực thi giao diện của một lớp hay tập các lớp. Thông thường advice dùng để thực thi cắt ngang động, introduction dùng để thực thi cắt ngang tĩnh và được đan kết hay thực thi tại thời điểm biên dịch. Introduction có thể được sử dụng để: 1) Thêm các biến dữ liệu (hay thuộc tính mới) vào một lớp: private int StockClient.numberOfStocks = 0;
  • 38. 30 Câu lệnh này thêm một thuộc tính mới có tên là numberOfStocks, kiểu integer và được khởi tạo giá trị ban đầu bằng 0 vào lớp StockClient. Tên của thuộc tính mới được thêm vào này phải không được trùng với tên các thuộc tính đã có. Điều này có nghĩa là việc đặt tên cho nó cũng phải tuân theo một quy ước đặt tên để tránh xung đột trong quá trình thực thi. 2) Thêm các phương thức vào một lớp: public StockClient.new(String message); Câu lệnh này đưa một phương thức khởi tạo mới vào lớp StockClient. Câu lệnh sau thêm một phương thức mới có tên là getClientStock() vào lớp StockClient: public StockClient.getClientStock(){ return numberOfStocks; } 3) Thay đổi sự thừa kế hay thứ bậc giao diện của một lớp: declare parents: StockClient implements newServiceInterface; declare parents: StockClient extends Frame; Hai câu lệnh này làm cho lớp StockClient thực hiện giao diện có tên là newServiceInterface và kế thừa (extend) lớp có tên là Frame tương ứng. 4) Thêm cảnh báo hay lỗi: AspectJ cung cấp khả năng dò tìm một số pointcut tại thời điểm biên dịch và sinh ra một lỗi hoặc cảnh báo. Một cảnh báo hướng trình biên dịch đưa ra thông báo và vẫn tiếp tục quá trình biên dịch. Ngược lại với một lỗi, trình biên dịch sẽ đưa ra một thông báo và dừng quá trình biên dịch. Cú pháp như sau: declare warning : Pointcut : String; declare error : Pointcut : String; Trong đó String là chuỗi thông báo lỗi, Pointcut là bộ mô tả Pointcut. Những pointcut này sẽ định vị các joint point trong mã nguồn tương ứng với các điểm khi chương trình thực thi. Ví dụ aspect SCError dừng quá trình biên dịch chương trình khi hàm khởi tạo của lớp SCMain được thực thi và sinh ra thông báo lỗi: public aspect SCError { declare error: execution(SCMain.new(..)): “Constructor executed!”; } 1.4.6. Aspect AspectJ sử dụng từ khóa aspect để biểu thị một cấu trúc được thiết kế để đóng gói tất cả các đoạn mã cần thiết để thực thi một mối quan tâm cắt ngang giống như từ khóa class trong Java dùng để đóng gói một lớp. Cấu trúc được đóng gói đó được gọi là một
  • 39. 31 aspect. Tất cả các pointcut, advice và introduction đều được đóng gói bằng việc sử dụng từ khóa aspect. Không có aspect, đoạn mã phục vụ cho việc thực thi một mối quan tâm cắt ngang rất có thể sẽ đóng góp vào vấn đề lộn xộn mã nguồn mà chúng ta đang cố gắng giải quyết. Như vậy, các aspect là các đơn vị chủ yếu của các thực thi cắt ngang. Chúng giống các lớp trong nhiều khía cạnh, nhưng sự khác nhau quan trọng nhất là các aspect có thể gây ảnh hưởng và sửa đổi các lớp. Bảng sau tóm tắt những điểm giống và khác nhau giữa aspect và lớp: Bảng 1.1. So sánh giữa aspect và lớp 1 Chỉ các aspect trừu tượng mới được kế thừa 2 Phải được khai báo tĩnh (static) Cấu trúc của aspect: Một aspect giống và hoạt động gần giống một lớp Java bởi việc cung cấp một bộ chứa cho sự đóng gói các mã pointcut, advice và introduction. Aspect có thể chứa các thuộc tính của nó, các phương thức, các thành viên lớp lồng nhau giống như một lớp bình thường trong Java để hỗ trợ thêm tính hướng đối tượng bên trong các mối quan tâm mà aspect đại diện. Dạng của một aspect như sau: aspect ::= <access> [privilege] [static] aspect <identifier> <class identifier><instantiation> <access> ::= public | private [abstract] <identifier> ::= letter { letter | digit } <class identifier> ::= [dominates] [extends] <instantiation> ::= [issingleton | perthis | pertarget | percflow | perflowbelow] Đặc điểm Lớp Aspect Có thể thể hiện hóa trực tiếp Có Không Có thể kế thừa các lớp Có Có Có thể thực thi các giao diện Có Có Có thể có các định danh truy cập Có Có Có thể thừa kế các aspect Không Có1 Có thể được khai báo trong lớp, giao diện Yes Yes2
  • 40. 32 { //pointcuts //advice //methods/attributes } Sau đây là một ví dụ về việc cài đặt một aspect: public aspect ATMcardVerifier { pointcut checkwithdrawalAmount(ATMcard card, int amount): call(* ATMcard.withdrawMoney(..)) && target(card) && args(amount); void around(ATMcard card, int amount): checkwithdrawalAmount(card, amount) { if(amount<50) { System.out.println(“withdrawal amount>=50”); } else { proceed(card, amount); } } } Aspect trên cài đặt một poitcut và một around advice dùng để kiểm tra số tiền rút qua tham số hình thức amount của hàm withdrawMoney(int amount). Trước khi thực hiện lệnh rút aspect sẽ kiểm tra nếu số tiền rút nhỏ hơn $50 thì đưa ra thông báo và không cho thực hiện lệnh rút. Tính kế thừa của aspect: Trong AspectJ, giống như lớp, aspect có thể thừa kế lớp, thực thi giao diện và thừa kế aspect trừu tượng khác. AspectJ thực hiện các luật thừa kế của các aspect như đối với các lớp. Các pointcut và advice của aspect cha sẽ được aspect con thừa kế. Ngoài ra, các pointcut được khai báo là trừu tượng sẽ bị ghi đè bởi pointcut tương ứng ở lớp con. Chú ý: Đối với các advice cùng chia sẻ một joint point thì advice ở aspect con có thứ tự ưu tiên cao hơn advice ở aspect cha.
  • 41. 33 1.5. Kết luận Trong chương này chúng tôi trình bày về phương pháp lập trình hướng khía cạnh AOP, một kỹ thuật lập trình để đóng gói các mối quan tâm cắt ngang nhằm tách biệt các mối quan tâm cắt ngang với các mối quan tâm nghiệp vụ chính. Phương pháp lập trình này giúp cho việc thiết kế kiến trúc hệ thống, thực thi và bảo trì hệ thống được dễ dàng hơn. Chương này cũng trình bày chi tiết về AspectJ, một đặc tả ngôn ngữ AOP được cài đặt phổ biến cho ngôn ngữ lập trình Java. Ở các phần sau chúng tôi sử dụng AspectJ để cài đặt các aspect để kiểm chứng các bất biến đối tượng trong chương trình hướng đối tượng Java.
  • 42. 34 Chương 2 - Công cụ kiểm chứng mô hình Java PathFinder 2.1. Giới thiệu Công nghệ thông tin ngày càng phát triển, các hệ thống phần mềm càng ngày càng phức tạp và phát triển nhanh chóng. Vì vậy chúng càng dễ có nhiều lỗi hơn. Số lượng lỗi được phát hiện tăng theo cấp số nhân với số lượng tương tác giữa các thành phần của hệ thống, đặc biệt trong các hệ thống tương tranh. Trong các hệ thống phần mềm phức tạp, thời gian và công sức dành cho kiểm chứng phần mềm ngày càng nhiều hơn so với việc viết phần mềm. Các kỹ thuật được tìm kiếm để làm giảm và đơn giản hóa các công việc kiểm chứng. Các phương pháp hình thức mở ra một tiềm năng lớn để đạt được sự tích hợp kiểm chứng trong quy trình thiết kế, cung cấp các kỹ thuật kiểm chứng hiệu quả hơn và làm giảm thời gian kiểm chứng. Các kỹ thuật kiểm chứng hệ thống đang được áp dụng để thiết kế các hệ thống phần mềm ngày càng trở nên đáng tin cậy hơn. Kiểm chứng mô hình [5] là một kỹ thuật tự động để kiểm chứng các hệ thống tương tranh hữu hạn trạng thái được phát triển độc lập bởi Clarke và Emerson tại Mỹ và Queille và Sifakis tại Pháp vào những năm 1980. Kiểm chứng mô hình được chia làm 2 loại: Kiểm chứng mô hình phần cứng và kiểm chứng mô hình phần mềm. Trong luận văn này, chúng tôi sẽ chỉ đề cập đến kiểm chứng mô hình phần mềm. Trong khi việc kiểm chứng mô hình phần mềm về lý thuyết nghe có vẻ là phương pháp kiểm chứng an toàn và mạnh, thực tế chỉ ra rằng nó không thực sự mạnh. Để làm cho phương pháp này thực tế hơn, một công cụ kiểm chứng mô hình phải tận dụng các giải pháp kinh nghiệm và trừu tượng hóa trạng thái linh hoạt. Java PathFinder (JPF) [19, 25, 30, 31] là công cụ độc nhất vô nhị về khả năng cấu hình và khả năng mở rộng và vì vậy nó là một nền tảng tốt để khám phá các cách mới để cải thiện hiệu năng. 2.2. Công cụ kiểm chứng mô hình Java PathFinder Java PathFinder (JPF) [19, 25, 30, 31] là một hệ thống để kiểm chứng mã thực thi bytecode của các chương trình Java. Ở dạng đơn giản, nó là một máy ảo Java được sử dụng như một công cụ kiểm chứng mô hình trạng thái phần mềm tường minh, khảo sát tất cả các đường thực thi tiềm năng của một chương trình để tìm ra các vi phạm của các thuộc tính như khóa chết (deadlock) hay các ngoại lệ không được xử lý (unhanled exceptions). Không giống như các công cụ gỡ lỗi truyền thống, JPF thông báo đầy đủ đường thực thi dẫn đến một một lỗi. JPF đặc biệt rất phù hợp cho việc tìm kiếm các lỗi rất khó kiểm thử trong các chương trình đa luồng.