การใช้งาน JMS ใน Grails Application :: Part 1 => ใช้งานร่วมกับ Spring Framework
การใช้งาน JMS ในการพัฒนา Grails Application นั้นจะแบ่งออกเป็นของส่วนคือ
Part 1 : ใช้งานร่วมกับ Spring Framework
Part 2 : ใช้งานผ่าน plug-in
Software Requirement
- Grails 1.1 ( required )
- Apache ActiveMQ 5.2.0 ( required )
- Maven 2.10 ( optional )
ขั้นตอนการพัฒนา
1. ติดตั้ง Grails 1.1
2. ติดตั้ง Apache ActiveMQ 5.2.0 โดยการ extract file ออกมาเท่านั้นจบครับ
เช่น extract ไว้ที่ c:\apache-activemq-5.2.0\
ทดสอบ start ActiveMQ service ที่ c:\apache-activemq-5.2.0\bin\activemq.bat
จะแสดงผลดังรูป

ลองเข้าไปตรวจสอบผ่าน Admin Console ของ ActiveMQ ได้ที่ http://localhost:8161/admin/ดังรูป
ต่อมาสร้าง queue ชื่อ userSubscriptions จาก Admin Console เลย ได้ดังรูป [ จะนำมาใช้ต่อไปครับ ]

3. เริ่มพัฒนา Grails Application
โดยผมจะนำ maven มาช่วยจัดการเกี่ยวกับ Library ต่างๆ โดยสามารถสร้าง Grails Application ตามนี้ Grails and Maven
หรือถ้าใครไม่ถนัดก็ใช้ grails command เหมือนเดิมได้
>grails create-app test-jms
สำหรับผู้ที่ใช้ maven จะต้องเพิ่ม dependecy นี้ใน file pom.xml
<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-core</artifactId> <version>5.2.0</version> </dependency>
ส่วนผู้ใข้ grails command จะต้องเพิ่ม library ต่อไปนี้ใน folder lib ของ Grails Application
- activemq-core-5.2.0.jar
- geronimo-j2ee-management_1.0_spec-1.0.jar
- geronimo-jms_1.1_spec-1.1.1.jar
4. ทำการ configuration ต่างๆ ที่เกี่ยวกับการใช้งาน JMS
ทำการ configuration ใน file /grails-app/conf/spring/resources.groovy ดังนี้
ปล. ใน file /grails-app/conf/spring/resources.groovy จะใช้ Spring BeanBuilder เป็นตัวจัดการเกี่ยวกับ Parser
4.1 สร้าง JMS Connection Factory Bean สำหรับ ActiveMQ โดยจะติดต่อที่ localhost ผ่าน port 61616 ซึ่งเป็น default port ดังนี้
beans = {
jmsFactory(org.apache.activemq.ActiveMQConnectionFactory) { bean ->
bean.destroyMethod = "stop"
brokerURL = "tcp://localhost:61616"
}
}
4.2 ทำการส่ง message ไปยัง ActiveMQ โดยถ้าใครใช้งานผ่าน Spring Framework จะต้องรู้จักหรือใช้งาน
org.springframework.jms.core.JmsTemplate แน่นอน จะมี Helper methods สำหรับการส่ง message
ใน Grails ก็ใช้เช่นกัน โดยเพิ่มใน file /grails-app/conf/spring/resources.groovy ดังนี้
beans = {
jmsFactory(org.apache.activemq.ActiveMQConnectionFactory) { bean ->
bean.destroyMethod = "stop"
brokerURL = "tcp://localhost:61616"
}
jmsTemplate(org.springframework.jms.core.JmsTemplate) {
connectionFactory = jmsFactory
}
}
4.3 แล้วจะส่ง message กันยังไงล่ะ ??
ใน domail class ของ Grails นั้นสามารถ autowiring ไปยัง Spring Beans ที่ configuration ไว้ใน
file /grails-app/conf/spring/resources.groovy ได้ ดังนั้นสามารถ inject จาก domain class ได้เลย
ดังนี้
เริ่มจากสร้าง domain class ชื่อ user ก่อน
>grails create-domain-class User
หรือ
>mvn grails:create-domain-class แล้วใส่ User ไป
ทำการแก้ไข file /grails-app/domain/User.groovy ดังนี้ [ Object ที่ทำการส่งข้าม network จะต้อง implements Serializable เสมอ]
class User implements Serializable {
transient jmsTemplate
}
4.4 แต่มันก็ยังไม่สามารถส่ง message ได้นะครับ
ผมขอกำหนดว่า จะส่ง message ก็ต่อเมื่อทำการ สร้างผู้ใช้งาน หรือ User ขึ้นมา
เราสามารถใช้ interceptor method มาช่วยได้ดังนี้
class User {
transient jmsTemplate
transient afterInsert = {
try {
jmsTemplate.convertAndSend("userSubscriptions", this)
}catch(e) {
log.error "Error sending JMS message: ${e.message}",e
}
}
}
ใน code นั้นทำการส่ง message ไปยัง queue ชื่อ userSubscriptions ที่เราทำการสร้างตั้งแต่ต้น สามารถทดสอบได้ดังนี้
> grails console
หรือ
>mvn grails:console
แล้วทำการสร้าง User ดังนี้ และ execute ซะ
def user = new User() user.save()
ไปดู message ที่ส่งไปยัง queue ได้ที่ Admin Console ของ ActiveMQ ดังรูป เป็นการแสดง message จำนวน 2 messages ใน queue
เท่านี้ก้อสามารถส่ง message ไปยัง JMS ได้แล้วครับ แต่ยังไม่ได้นำไปใช้งานนะครับ เพียงแค่ส่งไปเก็บใน queue เท่านั้น
5. ส่วนที่ยังขาดอยู่ก็คือ
จะนำ message ที่อยู่ใน queue ชื่อ userSubscriptions มาใช้หรือทำงานยังไงกันล่ะ ??
ถ้าเป็นที่ office ผมก็สร้าง bot ขึ้นมา แล้วตั้ง scheduler ไว้เพื่อปลุก bot ให้ทำงานในเวลาที่กำหนด เช่น นาทีละครั้ง, ชั่วโมงล่ะครั้ง เป็นต้น ซึ่งเป็นเหตุผลเรื่องความเสถียรของ Queue หรือ Task
แต่ในตัวอย่างนี้ผมจะใช้ Listener เพื่อคอยดักฟังว่า มี message เข้ามายัง queue ชื่อ userSubscriptions เมื่อไรแล้ว
จะนำ message นั้นมาทำงานทันที โดยจะเรียกว่า เป็นการสร้าง Consumer นั่นเอง
ดังนั้นเรามาเริ่มต้นสร้าง Message Consumer กัน ….
โดยแนวคิดเป็นดังนี้
- Spring Framework มี org.springframework.jms.listener.adapter.MessageListenerAdapter ให้ใช้สำหรับการดักฟัง message ที่เข้ามายัง queue
- Grails ก็ใช้เหมือนกัน แถม Grails ยังสามารถ delegate ไปยัง Grails Service class ได้ด้วย เพื่อให้ทำงานตามที่ต้องการ
มา coding กันดีกว่า
5.1 ทำการสร้าง Grails Service Class ชื่อ User ดังนี้
>grails create-service user
หรือ
>mvn grails:create-service แล้วใส่ชื่อ user
ทำการสร้าง method ชื่อ onNewUser ใน file /grails-app/services/UserService.groovy ดังนี้
class UserService {
boolean transactional = true
void onNewUser( User user ) {
println "User ID : $user.id"
/** to do something **/
}
}
5.2 ทำการเพิ่ม configuration ใน file /grails-app/conf/spring/resources.groovy ดังนี้
beans = {
...
...
jmsMessageListener( org.springframework.jms.listener.adapter.MessageListenerAdapter, ref("userService") ) {
defaultListenerMethod = "onNewUser"
}
jmsContainer(org.springframework.jms.listener.DefaultMessageListenerContainer) {
connectionFactory = jmsFactory
destinationName = "userSubscriptions"
messageListener = jmsMessageListener
transactionManager = ref("transactionManager")
autoStartup = false
}
}
เป็นการเพิ่ม JMSMessageListener ไป เพื่อจะ delegate การทำงานไปยัง method onNewUser ของ Service class ชื่อ userService [ UserService.groovy นั่นเอง ]
จะสังเกตเห็นได้ว่ามี jmsContainer ด้วยซึ่งจะเป็นตัว monitor message ต่างๆ ที่เข้ามายัง Queue ใน destinationName ที่กำหนด จะส่งไปทำงานตามที่กำหนดไว้เช่นกัน
และเราทำการกำหนด autoStartup = false หมายความว่าจะไม่ทำงาน เมื่อมีการ start app ขึ้นมา เนื่องจากต้องการทำให้แน่ใจว่า JMS Container จะไม่ทำงานก่อนที่ Grails Application จะ load เสร็จเรียบร้อย ดังนั้น ถ้าต้องการให้ JMS Container เริ่มต้นทำงานหลังจากที่ Grails Application ทำการ load เสร็จ จะต้องไป start JMS Container ที่ file /grails-app/conf/BootStrap.groovy ดังนี้
class BootStrap {
def jmsContainer
def init = { servletContext ->
log.info "Starting JMS Container"
jmsContainer.start()
}
def destroy = {
}
}
6. หลังจากทุกอย่างเรียบร้อยก็พร้อม ทดสอบระบบว่าทำงานตามที่เราต้องการได้หรือเปล่า ??
การทดสอบผมสร้าง controller มา 1 ตัวชื่อ UserController.groovy ขึ้นมา เป็นดังนี้
class UserController {
def index = {
User user = new User()
user.save()
}
}
เมื่อเรียกใช้งานผ่าน url http://localhost:8080/test-jms/user/index จะแสดงค่า ดังนี้ใน console
User ID : XXXX
และเข้าไปตรวจสอบใน Queue จะพบว่า message ถูกดึงออกไปทำงานแล้ว [ Received Message ]
รวมทั้งจะเห็น Number Of Consumers = 1 นั่นก็คือ consumer ที่เราสร้างขึ้นมาครับ
รูปแสดง Consumer Message จะมี 1 ตัว ซึ่งเป้นตัวที่เราทำการสร้างขึ้นมานั่นเอง

รูปแสดง message ที่ส่งเข้ามา และถูกส่งออกไปหรือถูก consumer ดึงออกมาจาก queue เพื่อนำไปทำงาน

เท่านี้ก็จบการใช้งาน JMS ใน Grails Application แล้วครับ
ใน part นี้อาจจะยาวและใช้พลังเยอะหน่อยครับ เดี๋ยว part ที่ 2 จะพาใช้ JMS Plug-in ครับ …..
รวมทั้ง Demo การนำไปใช้งานจริงๆ ครับ
ที่มา
- หนังสือ The Definitive Guide to Grails
- การสร้าง Twitter ด้วย Grails ภายใน 40 นาที


Leave a Reply