โจทย์คือ "สร้าง aspect สำหรับจับเวลาให้เมธอดในคลาส Target" ครับ
1. ให้สร้่าง aspect เป็นชื่อ TimeMeasurement ตั้ง package เป็นอะไรก็ได้ เช่น net.ckblog.aspect.TimeMeasurement จะได้ไฟล์ชื่อ TimeMeasurement.aj ซึ่งจะคอมไพล์ได้ด้วยตัวคอมไพเลอร์ของ AspectJ
2. ให้สร้างคลาส ชื่อ Target อาจจะเป็น net.ckblog.Target แล้วให้มี 2 เมธอด ชื่อ compute1000() กับ compute2000() แล้วลองเขียนโค้ดให้วนรอบใน 2 เมธอดนั้น 1000 รอบ และ 2000 รอบ ตามลำดับ
จากนั้นให้เตรียมคลาส Main เพื่อสร้าง object ของ Target แล้วทำการเรียกใช้ทั้งสองเมธอดดังกล่างใน main()
3. กลับมาที่ aspect TimeMeasurement ให้ประกาศ pointcut โดยเราจะใช้ pointcut designator (PCD) ชื่อ execution() ในการเลือก join point 2 จุด ณ ตำแหน่งการทำงานของเมธอด ของ compute1000() และ compute2000()
ซึ่งเหตุผลในการใช้ PCD มาจากวิธีคิดแบบนี้ครับ
- การทำงานของเมธอด คือ execution of method (ต่างจากการเรียกใช้ คือ call)
- นั่นคือความหมายของ PCD ชื่อ execution(...) (ถ้าเป็นการเรียกใช้ก็จะเป็น PCD ชื่อ call())
และเป้าหมายของเราคือเมธอด compute1000() และ compute2000
จะได้ pointcut ดังต่อไปนี้
execution(public Target.compute1000()) ||
execution(public Target.compute2000())
ความหมายคือ เราสร้าง pointcut จาก PCD มากกว่า 1 ตัว และในกรณีนี้ เราใช้ PCD 2 ตัวทำการ or กัน
ในการใช้งานจริง จะสามารถยุบรวมให้เป็น PCD เดียวโดยใช้ wildcard ซึ่งจะเป็นตามโค้ดต่อไปนี้ครับ
execution(public Target.compute*())
(หมายเหตุ: pointcut นี้จะเลือกทุก ๆเมธอดของคลาส Target ที่ชื่อเมธอด ขึ้นต้นด้วย compute นะครับ
นั่นคือถ้าเีราเพิ่ม compute3000() เข้าไป method ใหม่ก็จะโดนเลือกด้วย ซึ่งจะทำให้ความหมายไม่ตรงเป๊ะ ๆ กับ code แรก
แต่ผมต้องการแสดงให้เห็นว่าเราสามารถเลือกเชิงประมาณโดยใช้ wildcard ได้)
4. ต่อมาเราก็จะประกาศ advice เพื่อให้ทำงาน ณ ตำแหน่ง join point ที่เราเลือกมาด้วย pointcut ในข้อ 3 ครับ
ก่อนจะไปต่อ ผมเล่าให้ฟังนิดนึงว่า join point มีสมบัติสำคัญ ๆ คือ
1) เราเข้ามาที่จุด join point ได้
2) เมื่อมาถึงแล้ว เราทำงานที่จุด join point ได้
3) และเมื่อมาถึงแล้ว เราออกจากจุด join point ได้
ซึ่ง advice ก็คือคำแนะนำที่เราบอกกับโปรแกรมว่าควรจะทำอะไรที่จุด join point นี้
ตาม aspect เราตั้งใจว่าจะ "จับเวลา" การทำงานของ 2 method
นั้นคือเราะจะมีการจับเวลา "ก่อน" และ "หลัง" ในแต่ละ join point ที่เลือกไว้ด้วย pointcut ในข้อ 3 ครับ
ตรงนี้เราจะใช้ before() เพื่อนิยามการแนะนำขณะเข้า join point
และ after() เพื่อนิยามการแนะนำขณะออกจาก join point
ดังนั้นเราก็จะได้
before(): <ชื่อ pointcut>() {
// จับเวลาใส่ตัวแปร
}
after(): <ชื่อ pointcut>() {
// จับเวลา แล้วเอาไปลบกับตัวแปรที่ตั้งค่าไว้ในโค้ดของ before
// แล้ว System.out.println(เวลา);
}
แล้วก็สั่งรันโปรแกรม ก็เป็นอันเสร็จพิธีครับ
ในตัวอย่างที่ผมยกมาให้ดูนี้ ผมใช้ join point model แบบ pointcut-advice เพื่่ออธิบาย aspect สำหรับ"จับเวลา" โดยสร้าง pointcut จากการใช้ PCD 2 ชุดมา or กัน เพื่อเลือก (quantify) join point 2 ตำแหน่งใน class Target แล้วก็สร้าง advice เพื่อแนะนำให้โปรแกรมทำการจับเวลา "ก่อน" และ "หลัง" จุดที่เลือกมาด้วย pointcut ผมตั้งใจละ code ไว้ให้ผู้อ่านลองนำไปเขียนเพิ่มเติมเองนะครับ
สำหรับ join point อีก model ที่มีใน AspectJ คือ inter-type declaration หรือเรียกว่า introduction จะกล่าวถึงในโพสต์อื่น ๆ ครับ
หมายเหตู ผมโพสต์ตอบแบบเดียวกันนี้ไว้ในกระดานข่าวของ narisa.com กระทู้นี้ครับ