Tải bản đầy đủ (.pdf) (76 trang)

Kiểm tra ràng buộc thời gian sử dụng phương pháp AOP

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.62 MB, 76 trang )


ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ




VŨ THỊ HỒNG HẠNH


KIỂM TRA RÀNG BUỘC THỜI GIAN SỬ DỤNG
PHƯƠNG PHÁP AOP







LUẬN VĂN THẠC SĨ






HÀ NỘI - 2010





4
MỤC LỤC
Lời cam đoan 1
Tóm tắt nội dung 3
MỤC LỤC 4
DANH MỤC KÍ HIỆU – TỪ VIẾT TẮT 6
DANH MỤC HÌNH VẼ 7
Mở đầu 8
Chương 1. Giới thiệu lập trình hướng khía cạnh (Aspect-Oriented Programming) . 10
1.1 Giới thiệu 10
1.2 Lập trình hướng khía cạnh – AOP 11
1.2.1 Lịch sử hình thành 12
1.2.2 Phương pháp lập trình hướng khía cạnh 13
1.3 Ngôn ngữ lập trình hướng khía cạnh AspectJ 15
1.3.1 Các khái niệm cơ bản 15
1.3.2 Cơ chế hoạt động của AspectJ 16
1.3.2.1 Thực thi cắt ngang 16
1.3.2.2 Join point 17
1.3.2.3 Point cut 20
1.3.2.4 Advice 22
1.3.2.5 Introduction 24
1.3.2.6 Compile-time declaration 25
1.3.2.7 Aspect 25
1.3.3 Kết luận 27
Chương 2. Ngôn ngữ mô hình hoá đặc tả ràng buộc thời gian 28
2.1 Giới thiệu 28
2.2 Một số biểu đồ UML 28
2.2.1 Biểu đồ trạng thái 30
2.2.2 Biểu đồ trình tự 31
2.2.3 Biểu đồ thiết lập thời gian 31

2.2.3.1 Vấn đề đặc tả 31
2.2.3.2 Định nghĩa ràng buộc thời gian 33
2.2.3.3 Tầm quan trọng 33
2.3 Ngôn ngữ XML (eXtensible Markup Language) 34
2.3.1 Cơ bản về XML 34
2.3.2 XML DOM 36
2.3.2.1 DOM 36
2.3.2.2 XML DOM 37
2.3.2.3 XML DOM Parser 37
2.3.2.4 XML DOM API 38
2.4 XMI (XML Metadata Interchange) 39
2.5 Kết luận 40

5
Chương 3. Kiểm tra sự tuân thủ giữa thực thi và đặc tả ràng buộc thời gian 41
3.1 Phương pháp đặc tả 41
3.2 Đặc tả làm quy tắc sinh mã Aspect tự động 43
3.3 Kết luận 45
Chương 4. Tự động sinh mã Aspect từ máy trạng thái 46
4.1 Mô tả biểu đồ trình tự UML bằng các đối tượng trong Java 46
4.2 Xây dựng FSM mô tả biểu đồ trình tự UML 47
4.2.1 Máy trạng thái 47
4.2.2 Thuật toán xây dựng máy trạng thái mô tả biểu đồ trình tự UML 47
4.3 Sinh aspect từ FSM mô tả biểu đồ trạng thái UML 49
4.4 Kết luận 50
Chương 5. Thực nghiệm 51
5.1 Hệ thống thực nghiệm 51
5.1.1 Module sinh máy trạng thái từ đặc tả UML Timing diagram 51
5.1.1.1 Xây dựng cấu trúc dữ liệu mô tả biểu đồ trình tự 51
5.1.1.2 Đọc thông tin từ XML 54

5.1.1.3 Lấy ràng buộc thời gian từ file xml 55
5.1.2 Module sinh aspect từ biểu đồ trạng thái 58
5.1.2.1 Xây dựng mã aspect tạo khuân mẫu (template ) 58
5.1.2.2 Template tổng hợp cho kiểm tra tính tuần tự và ràng buộc thời gian. 59
5.1.2.3 Sinh mã Aspect tự động từ máy trạng thái và Template 63
5.2 Một ví dụ chạy thử nghiệm 64
5.2.1 Biểu đồ tuần tự và ràng buộc thời gian 64
5.2.2 chương trình sinh mã Aspect từ đặc tả UML 66
5.2.3 Một số giao dịch cụ thể 67
5.2.4 Kiểm tra kịch bản 68
5.2.4.1 Gọi đúng chuỗi trong biểu đồ tuần tự. 68
5.2.4.2 Chuỗi gọi không đúng tuần tự. 70
5.3 Kết luận 71
Kết luận 72
Kết luận về khóa luận 72
Hướng phát triển trong tương lai 73











6
DANH MỤC KÍ HIỆU – TỪ VIẾT TẮT
AIS Account Information System

AOP Aspect-Oriented Programming
API Application Programming Interface
ATM Automatic Teller Machine
BDD Binary Decision Diagram
CMU Carnegie Mellon University
CTL Computation Tree Logic
ERP Enterprise Resource Planning
FSM Finite State Machine
HR Human Resource
IRST Istituto per la Ricerca Scientifica e Tecnolgica
JAC Java Aspect Component
LTL Linear Time Logic
NIST National Institute of Standards and Technology
OCL Object Constraint Language
OOP Object-Oriented Programming
PLTL Past Linear Time Logic
PARC Palo Alto Research Center

SPIN Simple Promela Interpreter
UML Unified Modeling Language

7
DANH MỤC HÌNH VẼ

Hình 1.1 Thực thi các mối quan tâm cắt ngang bằng AOP 12
Hình 1.2: Các giai đoạn phát triển AOP 15
Hình 1.3: Ví dụ về định nghĩa point cut. 21
Hình 1.4 các điểm khác nhau khi chèn vào join point 23
Hình 2.1 Biểu đồ UML 2.0 29
Hình 2.2: Biểu đồ trạng thái thực hiện hóa đơn 30

Hình 2.3: Biểu đồ tuần tự rút tiền từ máy ATM 31
Hình 2.4 UML Concise Timing Diagram 32
Hình 2.5 Minh họa biểu đồ ràng buộc thời gian 33
Hình 2.6: XML DOM Parser 38
Hình 2.7 Sử dụng XMI trao đổi thông tin giữa các công cụ khác nhau. 40
Hình 3.1: Tiến trình kiểm chứng chung 42
Hình 3.2: Biểu đồ trình tự UML Timing Diagram 44
Hình 4.1 Mô tả các đối tượng trong java 46
Hình 4.2 Mô Hình Máy trạng thái 47
Hình 5. 1 Mô tả việc thông điệp từ XML 54
Hình 5.2 Lớp đọc ràng buộc thời gian. 55
Hình 5.3 Cài đặt sinh máy trạng thái 58
Hình 5.4 Mã Aspect cho kiểm tra tính ràng buộc thời gian 59
Hinh 5.5. Biểu đồ tuần tự giao dịch rút tiền từ máy ATM 64
Hình 5.7. Chương trình sinh mã Aspects 66
Hình 5.8 Demo generate aspects. 67
Hình 5.9 Chương trình mô phỏng giao dịch để kiểm tra bằng mã aspect đã sinh. 67

8
Mở đầu
1. Đặt vấn đề
Ngày nay công nghệ thông tin đã được ứng dụng vào tất cả các lĩnh vực của đời
sống xã hội. Nó đã tạo ra một diện mạo mới cho xã hội và nhờ đó nền văn minh nhân loại
đã được nâng lên một tầm cao mới. Nói đến công nghệ thông tin là nói đến công nghệ
phần mềm – một phần không thể tách rời của công nghệ thông tin. Hiện nay ngành công
nghệ phần mềm trên thế giới đã và đang phát triển như vũ bão. Những tiến bộ vượt bậc
của khoa học kỹ thuật phần cứng đã tạo điều kiện thuận lợi cho công nghệ phần mềm
ngày càng phát triển không ngừng.
Phần mềm được coi là sản phẩm chính của công nghệ phần mềm, được phát triển
theo các mô hình, quy trình phát triển đặc biệt. Quá trình phát triển phần mềm bao gồm

rất nhiều giai đoạn: Thu thập yêu cầu, phân tích, thiết kế, xây dựng, kiểm tra, triển khai và
bảo trì phần mềm. Trong các giai đoạn đó giai đoạn kiểm tra, phát hiện, xác định và sửa
các lỗi phần mềm là rất quan trọng để đảm bảo chất lượng của một phần mềm. Các lỗi
phần mềm có thể gây thiệt hại to lớn về tiền bạc, thời gian và công sức của con người. Lỗi
phần mềm được phát hiện càng muộn thì càng gây hậu quả nghiêm trọng, tốn rất nhiều
thời gian và công sức để sửa chữa lỗi, thậm chí có thể phải xây dựng lại toàn bộ hệ thống
từ đầu. Chính vì vậy cần có các phương pháp phát hiện lỗi sớm nhằm giảm thiểu công sức
để sửa chúng. Để phát hiện ra những lỗi phần mềm, phần mềm cần phải được kiểm chứng
(Verification) và thẩm định (Valication) [13]. Kiểm chứng phần mềm là kiểm tra xem
phần mềm có được thiết kế đúng và thực thi đúng như đặc tả yêu cầu hay không. Thẩm
định phần mềm là giai đoạn có sự hỗ trợ của khách hàng nhằm kiểm tra xem phần mềm
có đáp ứng được các yêu cầu của họ hay không.
Mục đích chính của kiểm chứng phần mềm là làm giảm thiểu lỗi phần mềm tới mức
có thể chấp nhận được. Chính vì vậy, nó có vai trò vô cùng quan trọng trong toàn bộ quy
trình phát triển phần mềm và trong ngành công nghệ phần mềm hiện nay. Nó đã và đang
thu hút được mối quan tâm của rất nhiều nhà nghiên cứu.
Giai đoạn kiểm thử trong quy trình phát triển phần mềm có mục đích kiểm tra tính
đúng đắn của sản phầm phần mềm. Trên thực tế, các thao tác kiểm thử đơn vị chỉ đánh
giá được tính đúng sai của đầu vào và đầu ra của chương trình, không kiểm tra được quá

9
trình hoạt động logic của chương trình có theo đúng đặc tả ban đầu hay không. Những
đơn vị chương trình nhỏ này nếu không được kiểm tra kỹ sẽ có thể gây ra thiệt hại nặng
nề khi tích hợp chúng để tạo thành chương trình hoàn chỉnh. Vấn đề đặt ra là cần có
phương pháp kiểm chứng các đặc tả giao thức giữa các đối tượng, các tác tử ngay trong
thời gian chạy, đánh giá xem trong thời gian chạy đối tượng hay tác tử phần mềm có vi
phạm các giao thức ràng buộc đã được đặc tả hay không, và từ đó đảm bảo chắc chắn hơn
tính đúng đắn của sản phầm phần mềm. Trong luận văn này, tôi xin giới thiệu phương
pháp tự động sinh mã aspect kiểm chứng đặc tả giao thức trong thời gian chạy, dựa trên
phương pháp lập trình hướng khía cạnh (Aspect – Oriented Programming).

2. Nội dung bài toán

Hiện nay có rất nhiều phương pháp kiểm chứng phần mềm như giả lập hay kiểm
chứng mô hình. Trong phạm vi bài toán được đặt ra ở đây, tôi muốn đề cập tới phương
pháp kiểm chứng phần mềm dựa trên phương pháp lập trình hướng khía cạnh (AOP) [7,
12]. Lĩnh vực kiểm chứng cụ thể trong phạm vi bài toán là kiểm tra tự động tính tuần tự
của các phương thức trong giao thức, kiểm tra ràng buộc thời gian của các phương thức
trong giao thức có tuân theo thiết kế đặc tả hay không. Trong cách tiếp cận này, một ứng
dụng hướng đối tượng được đặc tả bằng mô hình UML và được cài đặt bằng ngôn ngữ
Java;. Các aspect sau đó sẽ được đan vào khung mã Java để kiểm tra tại bất kỳ thời điểm
nào trong thời gian chạy (aspect là mô-đun cắt ngang hệ thống). Bài toán có nhiệm vụ là
tạo ra được các aspect từ biểu đồ ràng buộc thời gian (Timing Diagram); dùng công cụ
AspectJ để đan các aspect này vào khung chương trình Java chính. Khi đó, trong quá trình
chạy của chương trình, các đoạn mã aspect sẽ tự động kiểm tra các đặc tả giao thức và
đưa ra thông báo lỗi khi có bất kỳ vi phạm nào xảy ra.
Nhiệm vụ chính của bài toán là xây dựng phương pháp tạo ra các đoạn mã aspect để
kiểm chứng, xây dựng công cụ tự động sinh mã aspect kiểm chứng từ đặc tả giao thức
bằng biểu đồ ràng buộc thời gian. Các tài liệu XMI chính là đầu vào cho công cụ cần xây
dựng. Dựa vào các kiến thức về UML, XML tôi sẽ phân tích tài liệu XMI, xây dựng máy
trạng thái (FSM) mô tả các biểu đồ UML. Sử dụng máy trạng thái vừa tạo để sinh ra mã
aspect phục vụ cho việc kiểm chứng sau này. Mã aspect chính là đầu ra cuối cùng của
công cụ.


10
Chương 1. Giới thiệu lập trình hướng khía cạnh
(Aspect-Oriented Programming)
1.1 Giới thiệu
Khi kiến trúc sư thiết kế một ngôi nhà, những mối quan tâm chính nhất mà kiến trúc
sư đó nghĩ tới đầu tiên là việc lựa chọn các tính năng cơ bản của ngôi nhà: Thiết kế nền

móng, chiều cao của tường, độ dốc của mái, vị trí và kích thước của phòng Các vấn đề
được quan tâm tiếp theo là các tính năng đều cần thiết và được chia sẻ bởi các tính năng
cơ bản trên, ví dụ như thiết kế điện nước. Khi thiết kế một chiếc cầu, các mối quan tâm cơ
bản là trụ cầu, giàn kéo, xà dầm, dây cáp; còn các mối quan tâm theo tiếp theo gồm các
tính năng dàn trải toàn bộ công trình là lắp đặt hệ thống điện.Việc thiết kế phần mềm
cũng dựa trên tư tưởng tương tự như thế.Một nhà thiết kế phần mềm đầu tiên bao giờ
cũng quan tâm đến các chức năng chính, cơ bản của hệ thống, mà trong ứng dụng doanh
nghiệp chính là các logic nghiệp vụ cơ bản. Ví dụ như trong một ứng dụng về ngân hàng,
các mô-đun chính được thiết kế để quản lý các giao dịch ngân hàng cho các khách hàng
thực hiện. Trong ứng dụng bán hàng, mô-đun chính quản lý việc bán hàng và quản lý
hàng trong kho.Trong cả hai ứng dụng trên, các mối quan tâm trải khắp hệ thống liên
quan đến các tính năng như lưu vết (logging), thẩm định quyền hạn (authorization), lưu
trữ dữ liệu (persistence) và các tính năng khác đều cần được chia sẻ và cần thiết cho các
các mô-đun nghiệp vụ chính. Các mối quan tâm dàn trải trên rất nhiều các mô-đun nghiệp
vụ chính được gọi là các mối quan tâm cắt ngang hệ thống (crosscutting concern).
Mặc dù lập trình hướng đối tượng (Object-Oriented Programming -OOP) là phương
pháp phổ biến nhất hiện nay được sử dụng để quảnlý các mối quan tâm nghiệp vụ chính
nhưng phương pháp này chưa đủ cho 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, 16, 22] là phương pháp lập trình mới cung cấp sự tách biệt các
mối quan tâm cắt ngang hệ thống bằng cách đưa ra một đơn vị mô-đun mới cắt ngang các
mô-đun khác, đó 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 được gọi là quá trình đan (weaving). Như vậy, AOP đã

11
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. Chương này giới thiệu về phương pháp lập trình hướng khía cạnh

AOP. Chương này cũng trình bày về AspectJ, một cài đặt phổ biến của AOP trên ngôn
ngữ Java.
1.2 Lập trình hướng khía cạnh – AOP
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. Phương pháp AOP được phát triển để giải quyết khó khăn này của OOP.
Trong AOP, các mối quan tâm cắt ngang hệ thống được mô-đun hóa bằng cách xác định
rành mạch vai trò của mỗi mối quan tâm trong hệ thống, thực thi mỗi vai trò đó trong mô-
đun riêng của chúng, và kết nối lỏng mỗi mô-đun chỉ với một số hữu hạn các mô-đun
khác. Hình 1 minh họa việc thực thi các mối quan tâm cắt ngang bằng AOP. Ở đây, các
lời triệu gọi tới các mối quan tâm cắt ngang được tự động đan vào các mô-đun nghiệp vụ
chính thông qua aspect. Aspect là một đơn vị mô-đun mới cho phép định nghĩa các quy
tắc đan cũng như hành động đan vào các mô-đun nghiệp vụ chính.AOP phát triển dựa trên
các phương pháp lập trình khác như OOP và lập trình hướng thủ tục, bổ sung thêm các
khái niệm và các tổ chức mới nhằm mô-đun hóa các mối quan tâm cắt ngang hệ thống.
Với AOP, ta có thể cài đặt các mối quan tâm nghiệp vụ chính bằng phương pháp lập trình
chính đã chọn. Ví dụ như, nếu OOP là phương pháp lập trình chính thì ta có thể cài đặt
các mối quan tâm bằng các lớp. Các aspect trong hệ thống đóng gói các mối quan tâm cắt
ngang hệ thống; chúng quy định các mô-đun khác nhau trong hệ thống cần phải được đan
với nhau như thế nào để thu được hệ thống cuối cùng. Điểm khác biệt cơ bản nhất giữa
AOP và OOP chính là việc quản lý các mối quan tâm cắt ngang hệ thống trong AOP,

12
người lập trình cài đặt các mối quan



Hình 1.1 Thực thi các mối quan tâm cắt ngang bằng AOP
tâm nghiệp vụ chính mà không cần quan tâm đến các hành vi cắt ngang chúng sẽ
được đan vào như thế nào. Ví dụ như một mô-đun nghiệp vụ chính không cần biết các

hoạt động của nó đang được lưu vết hoặc thẩm định quyền hạn. Như thế, việc cài đặt các
mối quan tâm riêng lẻ là độc lập với nhau.
1.2.1 Lịch sử hình thành
Trong nhiều năm gần đây, nhiều nhà lí luận đã cho rằng cách tốt nhất để tạo ra được
các hệ thống có thể quản lý được là nhận biết và tách biệt các mối quan tâm của hệ thống.
Chủ đề này được biết đến với tên là “tách biệt các mối quan tâm” (Separation Of
Concerns - SOC). Trong một bài báo vào năm 1972, David Parnas đã đề xuất rằng cách
tốt nhất để có được SOC là thông qua mô-đun hóa - quá trình tạo ra các mô-đun trong đó
che giấu cách giải quyết của mô-đun này với các mô-đun khác. Những năm tiếp theo, các

13
nhà nghiên cứu đã đưa ra nhiều cách khác nhau để quản lý các mối quan tâm. OOP cung
cấp một cách thức hiệu quả để tách biệt các mối quan tâm nghiệp vụ chính. Tuy nhiên,
phương pháp này lại gặp khó khăn khi xuất hiện các mối quan cắt ngang hệ thống. Một số
phương pháp 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 hướng khía cạnh (aspect-oriented programming) và lập trình có
mục đích (intentional programming) đã nổi lên như các cách tiếp cận khả dĩ nhằm mô-đun
hóa các mối quan tâm cắt ngang hệ thống. Tuy nhiên trong đó, AOP là phương pháp phổ
biến nhất và tỏ ra hiệu quả nhất khi giải quyết vấn đề này. Hầu hết các hoạt động ban đầu
tạo nên AOP hiện nay đã được làm tại nhiều trường đại học trên toàn thế giới. Cristina
Lopes và Gregor Kiczales của trung tâm nghiên cứu Palo Alto (Palo Alto Research Center
- PARC), một công ty con của hãng Xerox, là những người đóng góp đầu tiên cho AOP.
Gregor đưa ra thuật ngữ AOP vào năm 1996. Ông đã quản lý một nhóm nghiên cứu tại
Xerox và phát triển thành công AspectJ, một trong những cài đặt thực tế đầu tiên của
AOP, vào cuối những năm 1990. Gần đây, Xerox đã chuyển dự án AspectJ cho cộng đồng
mã nguồn mở tại eclipse.org để tổ chức này tiếp tục cải thiện và hỗ trợ cho dự án. AspectJ
là một cài đặt của AOP cũng giống như Java và SmallTalk là các cài đặt của OOP.
AspectJ dựa trên ngôn ngữ Java nhưng cũng có rất nhiều cài đặt của AOP trên các ngôn

ngữ khác từ AspectC cho C đến Pythius cho Python. Những cài đặt này cũng áp dụng các
khái niệm tương tự trong AspectJ cho các ngôn ngữ khác. Bên cạnh đó, cũng có một số
cài đặt khác cho ngôn ngữ Java ngoài AspectJ như Java Aspect Component (JAC) của
AOPSYS, AspectWerkz của BEA Systems, JBoss AOP hoặc Spring AOP [20]. Các cài
đặt này khác nhau về cách thức biểu diễn các mối quan tâm cắt ngang hệ thống và dịch
các mối quan tâm này để tạo ra hệ thống cuối cùng.
1.2.2 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 vẫn còn trong giai đoạn đầu của sự phát
triển và đang dần hoàn thiện. Thực tế có rất nhiều nhóm nghiên cứu lĩnh vực này, cũng có
những sự hợp nhất nhưng cũng còn nhiều vấn đề chưa thống nhất, kể cả những thuật ngữ
như các khái niệm của AOP, tuỳ thuộc vào ngữ cảnh sử dụng các kỹ thuật AOP riêng.
Tuy nhiên, 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:

14
• Phân rã bài toán theo khía cạnh (Aspectual decomposition): Trong
bước này, cần phân rã yêu cầu của bài toán thành các mối quan tâm nghiệp vụ chính
và các mối quan tâm cắt ngang hệ thống. Nói một cách khác, bước này nhằm tách biệt các
mối quan tâm mức mô-đun nghiệp vụ với các mối quan tâm cắt ngang, mức hệ thống. Ví
dụ trong bài toán quản lý sử dụng thẻ ATM, các mối quan tâm nghiệp vụ như rút tiền,
chuyển khoản. Các mối quan tâm cắt ngang là lưu vết, lưu trữ, thẩm định quyền hạn, vì
chúng cần thiết cho nhiều mô-đun khác.
• Cài đặt các mối quan tâm (Concern implementation): Sau khi phân rã, các mối
quan tâm được cài đặt một cách riêng rẽ. Trong ví dụ về bài toán quản lý sử dụng thẻ
ATM, lập trình viên sẽ cài đặt các mô-đun nghiệp vụ chính bao gồm rút tiền và chuyển
khoản; đồng thời cài đặt các mô-đun cắt ngang như lưu vết, lưu trữ, thẩm định quyền
hạn, Ta có thể tận dụng các kỹ thuật 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 để cài đặt các mô-đun này.
• Kết hợp lại các khía cạnh (Aspectual recomposition): Sau quá trình phân rã và cài
đặt các mối quan tâm, để 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 đó. Người tích hợp (Aspect Integrator) sẽ cần phải

chỉ ra các quy tắc để hợp nhất bằng cách xây dựng các thành phần mô-đun hóa gọi là
aspect. Quá trình kết hợp này được gọi là “tích hợp” hay “đan” (weaving) bằng cách sử
dụng các quy tắc trên để hình thành nên hệ thống cuối cùng. Ví dụ một luật tích hợp: “Tất
cá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
(weaver) tích hợp
vào các mô-đun nghiệp vụ theo đúng quy tắc chỉ ra.
Hình 1. 2 minh họa các giai đoạn phát triển các ứng dụng AOP.[22]

15

Hình 1.2: Các giai đoạn phát triển AOP
1.3 Ngôn ngữ lập trình hướng khía cạnh AspectJ
1.3.1 Các khái niệm cơ bản
AspectJ [1, 10, 16, 22] là một mở rộng hướng khía cạnh cho ngôn ngữ lập trình
Java. Chính vì thế, mọi chương trình Java hợp lệ đều là một chương trình AspectJ hợp lệ.
Trình biên dịch AspectJ sẽ kết hợp chương trình Java chính với các aspect thành các tệp
.class phù hợp với các đặc tả Java byte-code, cho phép máy ảo Java có thể thực thi các tệp
này. Bằng các sử dụng Java là ngôn ngữ cơ sở, AspectJ có được toàn bộ các ưu điểm của
Java và giúp cho các nhà lập trình Java dễ dàng hiểu ngôn ngữ AspectJ.
AspectJ bao gồm 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. Các phần tiếp theo trong chương này sẽ trình bày về phần đặc tả ngôn
ngữ, các thông tin về phần thực thi ngôn ngữ (trình biên dịch, môi trường phát triển, ) có
thể xem trong các tài liệu [10, 16, 22].
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

16
trình xảy a. 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 ghiệ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.3.2 Cơ chế hoạt động của AspectJ
1.3.2.1 Thực thi cắt ngang
Trong AspectJ, việc thực thi các quy tắc đan bởi trình biên dịch được gọi là thực thi
cắt ngang (crosscutting). Các quy tắc đan này cắt ngang nhiều mô-đun một cách có hệ
thống 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 và thực thi cắt ngang động.
• Thực thi cắt ngang động (dynamic crosscutting): Thực thi cắt ngang động là việc
đan hành vi mới vào quá trình thực thi một chương trình. Hầu hết việc thực thi cắt ngang
trong AspectJ đều là thực thi cắt ngang động. Thực thi cắt ngang động chèn thêm hoặc
thay thế luồng thực thi chương trình chính theo cách cắt ngang nhiều mô-đun, chính vì thế
làm thay đổi hành vi của hệ thống. Ví dụ như nếu muốn chỉ ra rằng một hành động nào đó
được thực hiện trước sự thực thi của một vài phương thức hoặc trước khi xử lý ngoại lệ
trong một số lớp nào đó thì chỉ cần chỉ ra các điểm đan và hành động được thực hiện khi
các điểm này thỏa mãn trong một mô-đun riêng lẻ.
• Thực thi cắt ngang tĩnh (static crosscutting): Thực thi cắt ngang tĩnh là việc đan
các sửa đổi vào cấu trúc tĩnh như lớp, giao diện hay các aspect của hệ thống. Chức năng
chính của thực thi cắt ngang tĩnh là hỗ trợ cho thực thi cắt ngang động. Ví dụ như khi
thêm dữ liệu và phương thức mới vào lớp và phương thức đã có nhằm định nghĩa ra các
trạng thái và các hành vi của một lớp nào đó sử ụng trong các hành động của thực thi cắt
ngang động. Thực thi cắt ngang tĩnh còn được sử dụng nhằm khai báo các cảnh báo và lỗi
tại thời điểm biên dịch cho nhiều mô-đun.
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. Các cú pháp mở rộng
này được thiết kế theo cách mà một lập trình viên Java cảm thấy quen thuộc khi sử dụng.
Để xác định các quy tắc đan một cách tự động các mối quan tâm cắt ngang vào các mô-

17
đun nghiệp vụ chính, AspectJ sử dụng các cấu trúc sau để diễn tả việc cài đặt các mối
quan tâm cắt ngang hệ thống: Join point, pointcut, advice, introduction, compile-time
declaration và aspect
1.3.2.2 Join point
Join point là một điểm có thể xác định trong quá trình thực thi một chương trình. Đó
có thể là một lời gọi đến một phương thức hoặc lệnh gán cho một thành viên của một đối
tượng. Trong AspectJ, mọi thứ đều xoay quanh các join point, bởi vì chúng là những vị trí
mà các hành động thực thi cắt ngang được đan vào.Sau đây một số loại join point chính
trong AspectJ:
• Method join point: Có hai loại join point mà AspectJ dành cho các phương thức.
Đó là join point thực thi phương thức (method execution join point) và join point triệu gọi
phương thức (method call join point). Join point thực thi phương thức nằm trên chính
phần thân của phương thức thực thi. Trong khi đó, join point triệu gọi phương thức lại
nằm trên các phần khác của chương trình, thường là các phương thức gọi phương thức
đang xét.Join point thực thi phương thức bao gồm sự thực thi của tất cả các mã trong
phần thân của bản thân phương thức đang xét. Đoạn mã sau đây minh họa cho join point
thực thi cho phương thức debit()
public class Account {

public void debit(float amount)
throws InsufficientBalanceException {
if (_balance < amount) { //
throw new InsufficientBalanceException( //
"Total balance not sufficient");//
} else { //

_balance -= amount; //
} //
}

18
}
Trong đoạn mã trên, join point thực thi cho phương thức debit() là toàn bộ phần thân
của phương thức.
Join point triệu gọi phương thức xảy ra tại vị trí phương thức đang xét được triệu
gọi. Đoạn mã sau minh họa cho join point gọi cho phương thức debit() :
Account account = ;
account.debit(100); // < debit() method call join point
• Constructor join point: Các join point trên một phương thức khởi tạo gần giống với
emphmethod join point, chỉ khác là chúng biểu diễn sự thực thi và triệu gọi việc tạo ra
một đối tượng của một lớp. Đoạn mã sau đây minh họa cho join point thực thi cho khởi
tạo cho lớp Account :
public class Account {

public Account(int accountNumber) {
_accountNumber = accountNumber;
}

}
Dưới đây là đoạn mã sau minh họa cho join point triệu gọi phương thức khởi tạo của
lớp Account :
Account account = new Account(199);
• Field access join point: Các field access join point nắm bắt việc truy cập các
trường dữ liệu bao gồm truy cập đọc và truy cập ghi các trường dữ liệu. Các join point
này chỉ có hiệu lực với thành viên dữ liệu của tới một thành viên dữ liệu của một lớp chứ
không có hiệu lực với các biến cục bộ của một phương thức.

•Field read access join point nắm bắt việc truy cập đọc tới một thể hiện hoặc một
thành viên dữ liệu của một lớp. Đoạn mã dưới đây minh họa một field read access join
point tới trường accountNumber của lớp Account :

19
public class Account {
int _accountNumber;

public String toString() {
return "Account: "
+ _accountNumber // < Read access join point
+
}

}
Dưới đây là đoạn mã minh họa cho field write access join point tới trường
accountNumber của lớp Account :
public class Account {
int _accountNumber;

public Account(int accountNumber) {
_accountNumber = accountNumber;//< Write access join point
}

}
• Exception handler execution join point: Các join point thực thi việc xử lý ngoại lệ
biểu diễn khối xử lý một loại ngoại lệ nào đó. Các join point này giống như khối catch với
một loại ngoại lệ nào đó.Dưới đây là đoạn mã minh họa join point thực thi việc xử lý
ngoại lệ:
try {

account.debit(amount);

20
} catch (InsufficientBalanceException ex) { //
postMessage(ex); //
OverdraftManager.applyOverdraftProtection(account, //
amount); //
}
Trong ví dụ trên, các join point thực thi việc xử lý ngoại lệ bao gồm toàn bộ khối
catch . 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 [16] và [22].
1.3.2.3 Point cut
Point cut 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. Ví dụ như, một point cut 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 đó. Point cut 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 point cut designator dùng để xác định point cut bằng tên hoặc bằng một biểu
thức. Ta có thể khai báo một point cut 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 point cut.
Trong AspectJ, các point cut có thể có tên hoặc không. Các point cut không tên,
giống như các lớp không tên, được định nghĩa tại nơi sử dụng. Các point cut được đặt tên
là các thành phần có thể được tham chiếu từ nhiều nơi khác khiến cho chúng có thể tái sử
dụng được. Tên của các point cut sử dụng cú pháp sau:
[access specifier] pointcut pointcut-name([args]) : pointcut-definition
Hình 1.3 minh họa ví dụ về định nghĩa point cut 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.


21


Hình 1.3: Ví dụ về định nghĩa point cut.
Kết luận Để chỉ ra một nhóm các join point, phần Signature của point cut
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 point
cut với nhau.
Bảng 2.1 chỉ ra ánh xạ giữa các loại join point tương ứng với các cú
pháp point cut designator. Cú pháp chi tiết của point cut có thể xem
trong tài liệu [16] và [22].



22

Loại join point
Cú pháp join point
Method execution
execution(MethodSignature)

Method call
call(MethodSignature)
Constructor
execution
execution(ConstructorSignature)
Constructor call
call(ConstructorSignature)
Class initialization
staticinitialization(TypeSignature)
Field read access
get(FieldSignature)
Field write access
set(FieldSignature)
Exeception handler
execution
Handler(TypeSignature)
Object pre-initialization
preinitialization(ConstructorSignatur
e)
Advice execution
adviceexecution()
1.3.2.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
point cut. 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 thỏa mãn.
Hình 1.4 minh họa các điểm khác nhau trong chuỗi thực thi join point triệu gọi và

thực thi phương thức debit(), ta có thể chèn thêm một hành vi mới thông qua các loại
advice.


23

Hình 1.4 các điểm khác nhau khi chèn vào join point

Dưới đây là ví dụ về before advice. Advice này có nhiệm vụ thẩm định quyền hạn
của người dùng khi sử dụng bất cứ phương thức nào của lớp Account.
before() : call(* Account.*( )) {
// authenticate the user
}
Đoạn mã dưới đây minh họa after advice dùng để lưu vết lại khi bất kỳ phương thức
nào của lớp Account được triệu gọi.
after() : call(* Account.*( )) {
// log the return from operation

24
}
Dưới đây là ví dụ minh họa về around advice dùng để kiểm tra việc rút tài khoản.
Nếu số tiền rút vượt quá số dư tài khoản thì không cho phép rút.
void around(Account account, float amount)
throws InsufficientBalanceException :
call(* Account.debit(float) throws InsufficientBalanceException)
&& target(account)
&& args(amount) {
try {
proceed(account, amount);
} catch (InsufficientBalanceException ex) {

// overdraft protection logic
}
}
Poincut và advice cùng nhau tạo nên các quy tắc thực thi cắt ngang động. Trong khi
các point cut xác định các join point cần thiết thì advice cung cấp hành động sẽ xảy ra tại
các join point đó.
1.3.2.5 Introduction
Introduction là lệnh để thực thi cắt ngang tĩnh nhằm đưa vào các thay đổi cho lớp,
giao diện và aspect của hệ thống. Điều này 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ụ như, ta có thể thêm một
phương thức hoặc một trường vào một lớp (được gọi là inter-type declaration).
Introduction sau khai báo lớp Account thực thi giao diện BankingEntity đồng thời khai
báo thêm trường dữ liệu minimumBalance và phương thức getAvailableBalance() cho
lớp Account:
declare parents: Account implements BankingEntity;
private float Account._minimumBalance;

25
public float Account.getAvailableBalance() {
return getBalance() - _minimumBalance;
}
1.3.2.6 Compile-time declaration
Compile-time declaration là một lệnh thực thi cắt ngang tĩnh cho phép thêm các
cảnh báo và các lỗi tại thời điểm biên dịch nhờ phát hiện các mẫu thông dụng nào đó.
Khai báo sau làm cho trình biên dịch đưa ra một cảnh báo nếu bất kỳ phần nào của hệ
thống gọi phương thức save() trong lớp Persistence. Việc sử dụng point cut call() để nắm
bắt lời gọi phương thức:
declare warning : call(void Persistence.saveObject))
: "Consider using Persistence.saveOptimized()";
1.3.2.7 Aspect

Aspect là đơn vị trung tâm trong AspectJ, giống như lớp là đơn vị trung tâm trong
Java. Nó chứa đoạn mã diễn tả các quy tắc đan cho cả thực thi cắt ngang động và thực thi
cắt ngang tĩnh. Poincut, advice, introduction và declaration kết hợp thành aspect. Bên
cạnh các phần tử của AspectJ, aspect còn có thể chứa cả dữ liệu, 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. Aspect tương tự như một
lớp thông thường trong Java ở các điểm:
• Aspect có thể chứa các thành phần dữ liệu và các phương thức giống như
lớp.
• Aspect có thể có các định danh về phạm vi truy cập giống như lớp và giao
diện bao gồm: public, mặc định (mức package), protected và private.
• Aspect có thể khai báo chúng là dạng trừu tượng bằng từ khóa abstract.
• Aspect có thể kế thừa các lớp và các aspect trừu tượng khác, và có thể thực
thi các giao diện.
• Aspect có thể nằm trong các lớp và các giao diện.Tuy nhiên, aspect không
phải một lớp. Dưới đây là các điểm khác của aspect với lớp:
• Aspect không thể được thể hiện hóa trực tiếp.

26
• Aspect không thể kế thừa từ các aspect cụ thể (không trừu tượng).
• Aspect có thể được đánh dấu là có đặc quyền bằng định danh phạm vi truy
cập privileged. Điều này làm cho các aspect có thể truy cập được đến các thành
viên private của các lớp mà chúng cắt ngang.
Ta có thể kết hợp các phần thực thi cắt ngang tĩnh và thực thi cắt ngang độngvào
thành một aspect dưới đây:
public aspect MinimumBalanceRuleAspect {
// Introduction
declare parents: Account implements BankingEntity;
// Compile-time declaration
declare warning : call(void Persistence.save(Object))
: "Consider using Persistence.saveOptimized()";

// Inter-type declaration
private float Account._minimumBalance;
public float Account.getAvailableBalance() {
return getBalance() - _minimumBalance;
}
// After advice cho point cut không đặt tên
after(Account account) :
execution(SavingsAccount.new( )) && this(account){
account._minimumBalance = 25;
}
//Pointcut debitOperations
pointcut debitOperations(Account account, float amount):
execution(* Account.debit())
&& this(account) && args(amount)
//Before advice cho pointcut debitOperations
before(Account account, float amount)
throws InsufficientBalanceException :
debitOperations(account, amount){
if (account.getAvailableBalance() < amount) {
throw new InsufficientBalanceException(

27
"Insufficient available balance");
}
}
}
1.3.3 Kết luận
Chương này đã trình bày về AOP, một phương pháp lập trình mới cung cấp sự tách
biệt các mối quan tâm cắt ngang hệ thống với các mô-đun nghiệp vụ chính. Phương pháp
lập trình mới này giúp cho kiến trúc của hệ thống dễ dàng hơn trong việc thiết kế, thực thi

cũng như bảo trì. Bên cạnh đó, chương này cũng đã trình bày AspectJ, cài đặt phổ biến
nhất của AOP trên ngôn ngữ lập trình Java.














×