ในการเขียน Managed bean หรือ Controller ของ JSF (JavaServer Faces) นั้น จะต้องใช้ annotation @ManagedBean และ annotation Scoped ของ faces อย่างใดอย่างหนึ่งกำหนดไว้เสมอ ได้แก่
- @ApplicationScoped
- @SessionScoped
- @ViewScoped
- @RequestScoped
ซึ่งเป็นตัวที่บ่งบอกวงจรชีวิตของ managed bean นั้นๆ ว่าจะมีชีวิตอยู่ได้นานเท่าใด
ต่อมา ผมต้องการเปลี่ยน managed bean ของ jsf ทั้งหมดที่ใช้ @ManagedBean ไปใช้ @Component ของ SpringFramework จากที่แต่ก่อน instance ของ managed bean ถูกสร้างขึ้นโดย jsf engine ก็ delegate ไปให้เป็นหน้าที่ของ spring เป็นคนสร้างให้แทน เนื่องจากต้องการให้สามารถ inject service และ component ต่างๆ ได้ง่ายขึ้น เพราะเป็น spring ด้วยกัน
ปัญหา
ปัญหาที่ผมเจอคือ การสร้าง controller ที่เป็น jsf ของ spring จะต้องควบคู่กับ annotation @Scope ซึ่งมี scope ไม่ครบตาม scope เดิมของ jsf คือยังขาด scope ที่เป็น view แล้วเราจะทำยังไงล่ะ เพราะส่วนใหญ่แล้วเราต้องการ scope ที่เป็น view ซ่ะด้วย?
วิธีการ
1. สร้าง scope ที่เป็น view ของ jsf ให้ @Scope
ในที่นี้ เราจะ custom view scope ขึ้นมาเอง โดยผนวกมันเข้ากับ FacesContext
ในที่นี้ เราจะ custom view scope ขึ้นมาเอง โดยผนวกมันเข้ากับ FacesContext
package com.blogspot.na5cent.spring; import java.util.Map; import javax.faces.context.FacesContext; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; /** * @author redcrow */ public class ViewScope implements Scope { private Map<String, Object> getViewMap() { return FacesContext.getCurrentInstance() .getViewRoot() .getViewMap(); } @Override public Object get(String name, ObjectFactory objectFactory) { Map<String, Object> viewMap = getViewMap(); if (viewMap.containsKey(name)) { return viewMap.get(name); } else { Object object = objectFactory.getObject(); viewMap.put(name, object); return object; } } @Override public Object remove(String name) { return getViewMap().remove(name); } @Override public String getConversationId() { return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { //Not supported } @Override public Object resolveContextualObject(String key) { return null; } }2. ที่ file applicationContext.xml (ของ spring framework) ให้ add scope เข้าไปใน component
... ... ... <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="view"> <bean class="com.blogspot.na5cent.spring.ViewScope"/> <!-- ***** --> </entry> </map> </property> </bean> ... ... ...3. ใช้งาน
... ... ... @Component @Scope("view") //***** public class TopicIncomeCtrl { private static final Logger LOG = LoggerFactory.getLogger(TopicIncomeCtrl.class); @Autowired private TopicIncomeService service; private TopicIncomeLazy lazy; private TopicIncome topic; @PostConstruct public void postContruct() { lazy = new TopicIncomeLazy(); } public TopicIncomeLazy getLazy() { return lazy; } public void onCreateTopic() { topic = new TopicIncome(); } public TopicIncome getTopic() { return topic; } public void setTopic(TopicIncome topic) { this.topic = topic; } public void onAddTopic(){ service.saveTopic(topic); } }ก่อนที่จะทำตรงนี้ได้ แนะนำให้อ่าน 2 บทความนี้ก่อนครับ
http://na5cent.blogspot.com/2013/07/jsf-managedbean-can-autowire-spring.html http://na5cent.blogspot.com/2013/09/spring-session-scope.html
ที่มาของภาพ http://www.coyotecanada.ca/view_through_scope_I.jpg
ไม่มีความคิดเห็น:
แสดงความคิดเห็น