December 29, 2016

Dependency Injection - Part 3

အရင် Dependency Injection - Part 1 မှာတော့ Dependency Injection ဆိုတာ ဘယ်လိုမျိုးလဲ။ ဘာ့ကြောင့် လိုအပ်တာလဲဆိုတာကို အဓိကထားပြီး ဖေါ်ပြခဲ့တယ်။ ပြီးတော့ ဒုတိယပိုင်း Depencency Injection - Part 2 မှာကတော့ CDI ကို သုံးပြီး Dependency Injection ကို ဘယ်လို ရေးသားရမလဲ ဆိုတာကို ဖေါ်ပြခဲ့ပြီးပါပြီ။ Depencency Injection နဲ့ ပတ်သက်ပြီး ဒီတစ်ခေါက်က နောက်ဆုံးအကြိမ်ဖြစ်ပါမယ်။

ဒီတစ်ခေါက်ကတော့ CDI Bean တွေရဲ့ Lifecycle နဲ့ CDI Bean မဟုတ်တဲ့ Object တွေကို Inject လုပ်ချင်ရင် ဘယ်လို လုပ်မလဲဆိုတာကို ဖေါ်ပြသွားပါမယ်။ ဒါပြီးရင်တော့ CDI Bean တွေရဲ့ Scope တွေ အကြောင်းကို ဆက်လက် ဖေါ်ပြသွားပါမယ်။


Lifcycle of CDI Bean

CDI ကို အသုံးပြုရင် Bean တွေကို ကိုယ်တိုင် Object ဆောက်စရာမလိုဘူး။ Inject လုပ်လိုက်တာနဲ့ လိုအပ်တဲ့ Bean ကို Container ကနေ အလိုအလျောက် လာရေက်ပြီး Inject လုပ်ပေးမယ်ဆိုတာတော့ သိခဲ့ပါပြီ။ ဒီတစ်ကြိမ်မှာတော့ လက်တွေ့ Container ကနေ ဘယ်လို အချိန်အခါမျိုးမှာ လာပြီး Inject လုပ်ပေးသလဲဆိုတာကို သဘောပေါက်အောင် CDI Beans တွေရဲ့ Lifecycle ကို လေ့လာသွားပါမယ်။

ပုံမှန်အားဖြင့် POJO Object တွေရဲ့ Lifecycle တွေဟာ ရိုးရှင်းပါတယ်။ Application ထဲမှာ အသုံးပြုလိုတဲ့အခါမှာ new keyword ကို သုံး Constructor ကို ခေါ်ပြီး Create လုပ်ပါမယ်။ နောက်ဆုံး Reference မရှိတော့တဲ့အခါမှာ Garbage Collector ကနေလာပြီး သိမ်းတဲ့အချိန်မှာ Object တစ်ခုရဲ့ သက်တမ်းဟာ ပြီးဆုံးမှာ ဖြစ်ပါတယ်။

များသောအားဖြင့် ကျွန်တော်တို့တွေဟာ Object တစ်ခုရဲ့ Instance Variable တွေကို Initialize လုပ်တဲ့နေရာမှာ Constructor ထဲမှာ ရေးသားလေ့ရှိပါတယ်။ ဒါပေမဲ့ Container ကနေ Manage လုပ်ပေးတဲ့ CDI လို Bean မျိုးကတော့ new keyword နဲ့ Constructor ကို ခေါ်လို့ရမှာ မဟုတ်ပါဘူး။ Constructor ကို ခေါ်တဲ့အခါမှာ Injection Point မှာရှိတဲ့ Variable တွေကို Inject မလုပ်ရသေးတဲ့အတွက်ဖြစ်ပါတယ်။

အဲ့ဒီအစား Container ကနေ Beans တွေရဲ့ Lifecycle ကို Manage လုပ်တဲ့နေရာမှာ ခေါ်သွားတဲ့ Lifecycle Callback Method တွေရှိပါတယ်။ အဲ့ဒါတွေကို အသုံးပြုသွားရမှာ ဖြစ်ပါတယ်။ အရင်ဆုံး CDI Bean တွေရဲ့ Lifecycle ကို ကြည့်ကြည့်ပါမယ်။



Container ကနေ CDI Beans တစ်ခုကို Inject လုပ်ပေးရတော့မယ်ဆိုရင် new keyword နဲ့ Default Constructor ကို ခေါ်ပြီး တည်ဆောက်ပါတယ်။ အဲ့ဒီနောက်မှာ Bean ထဲမှာ ပါတဲ့ @Inject လို့ရေးထားတဲ့ Dependency တွေကို Inject လုပ်ပါမယ်။ အဲ့ဒါပြီးတော့ @PostConstruct Annotation ရေးထားတဲ့ Method ကို ခေါ်ယူမှာ ဖြစ်ပါတယ်။

ဒါ့ကြောင့် Initialize လုပ်တဲ့ Process တွေကို PostConstruct Method ထဲမှာ ရေးသားရမှာ ဖြစ်ပါတယ်။ အဲ့ဒီ​ PostConstruct ကို ခေါ်ပြီးမှသာ CDI Bean ဟာ အလုပ်လုပ်ဖို့ အသင့် အနေအထားကို ရောက်ရှိသွားမှာ ဖြစ်ပါတယ်။

အဲ့ဒီနောက်မှာ Application ထဲက Method Invocation တွေကို အကြိမ်ကြိမ်ပြုလုပ်မယ်။ နောက်ဆုံး Reference မရှိတော့ဘူး။ ဖျက်ဖို့ လိုအပ်လာပြီဆိုရင် @PreDestroy ရေးထားတဲ့ Method ကို ခေါ်ပြီးမှ Memory ပေါ်ကနေ ဖျက်ထုတ်ပစ်မှာ ဖြစ်ပါတယ်။ ဒါ့ကြောင့် Bean ကို Destroy မလုပ်ခင် ရေးသားချင်တဲ့ Process တွေကို @PreDestroy Method ထဲမှာ ရေးသားရမှာ ဖြစ်ပါတယ်။


Injecting No CDI Objects

CDI ကိုသုံးပြီး Inject လုပ်လို့ရတာကတော့ CDI Bean တွေဖြစ်မှသာ ရပါမယ်။ CDI Bean ဆိုတာ ဘယ်လို Bean တွေကို ခေါ်တာလဲ။ CDI Project ထဲမှာရှိပြီး CDI Annotation တွေကို တပ်ဆင်ရေးသားထားတဲ့ Bean တွေကို CDI Bean တွေလို့ခေါ်ပါတယ်။ CDI ရဲ့ deployment descriptor ဖြစ်တဲ့ beans.xml file ကို ရေးသားထားရပါမယ်။ beans.xml ဖိုင်ရဲ့ Bean-Discovery-Mode ကို all လို့ရေးထားရင်တော့ Java Bean တွေအားလုံးကို CDI Bean တွေ အနေနဲ့ အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။



တဖန် ထည့်သွင်းထားတဲ့ Lib တွေထဲက Java Beans တွေကို Inject လုပ်ချင်တယ်ဆိုရင်တောင် အဲ့ဒီ Beans တွေဟာ CDI Beans တွေ ဖြစ်မှရမှာ ဖြစ်ပါတယ်။ အဲ့ဒီလိုဖြစ်ဖို့ဆိုတာကလဲ Lib အနေနဲ့ Reference လုပ်နေတဲ့ jar တွေထဲမှာလဲ beans.xml ပါနေမှရမှာ ဖြစ်ပါတယ်။

တကယ်လို့ CDI Bean မဟုတ်တဲ့ Beans နမူနာအားဖြင့် Java SE API ထဲက Type တစ်ခုခုကို Inject လုပ်ဖို့ဆိုရင် ဒီအတိုင်းဆိုရင် ရမှာ မဟုတ်ပါဘူး။ @Produces Annotation ကို သုံးပြီး Produce လုပ်ထားမှသာ Inject လုပ်နိုင်မှာ ဖြစ်ပါတယ်။
public class MoakSMSSender implemets Sender {
 
 @Inject
 private String name;

 @Override
 public void send(String address, String message) {
  String dummy = "%s : %s : %s";
  System.out.println(String.format(name, address, message));
 }
}

အထက်ပါ နမူနာထဲမှာလို String name ကို Inject လုပ်ပြီး သုံးလိုတယ်ဆိုရင် အဲ့ဒီအတွက် @Produces လုပ်ထားဖို့လိုအပ်ပါတယ်။ MoakSMSSender ထဲမှာ String name ဆိုတာကို Inject လုပ်ထားတဲ့အတွက် Container ကနေ Inject လုပ်ဖို့ လိုက်ရှာပါမယ်။ Resources Class ထဲမှာ String Object တစ်ခုကို Produce လုပ်ထားတာကို တွေ့ရင် အဲ့ဒီနေရာမှာ Inject လုပ်ပးပါမယ်။
public class Resource {
 
 @Produce
 private String name = "Moak ";
}

String တွေလို Object တွေသာ မကပဲ primitive type တွေကိုလဲ Produce လုပ်ထားရင် Inject လုပ်ပြီး သုံးလို့ရမှာ ဖြစ်ပါတယ်။

တဖန် EntityManager လို Resource တွေကို Produces လုပ်ထားရင် လိုအပ်တဲ့နေရာမှာ Inject လုပ်ပြီး သုံးရုံပါပဲ။ ဒါပေမဲ့ ဒီလို Object တွေဟာ Resource တွေကို သုံးနေတာဖြစ်တဲ့အတွက် အသုံးပြုပြီးရင် close လုပ်ပေးဖို့ လိုအပ်ပါတယ်။ Java EE Server တွေဆိုရင်တော့ Server ကနေ အလို အလျောက်ပိတ်ပေးမှာ ဖြစ်တဲ့အတွက် ပြဿနာမရှိပါဘူး။ ဒါပေမဲ့ Java SE ပတ်ဝန်းကျင်တို့လို Web Container သာပါတဲ့ Tomcat Server ပေါ်မှာဆိုရင် Resource တွေကို အသုံးပြုပြီးရင် Application ထဲကနေ ပြန်ပိတ်ပေးဖို့ လိုအပ်ပါတယ်။

တကယ်လို့ Produce လုပ်ထားတဲ့ Resource Object တွေကို မသုံးတော့ရင် ပြန်ပိတ်ပေးဖို့အတွက် @Dispose Annotation ကို သုံးပြီး ရေးသားနိုင်ပါတယ်။
public class Resources {
 
 @PersistenceContext(unitName="payrollDB")
 private EntityManager em;

 @Produces
 public EntityManager getEm() {
  return this.em;
 }

 public void close(@Dispose EntityManager em) {
  em.close();
 }
}

အထက်ပါ နမူနာထဲမှာတော့ EntityManager Object ကို Produce လုပ်ထားပြီး နောက်ဆုံး မသုံးတော့လို့ရှိရင် Close လုပ်ပေးနိုင်အောင် close method ရဲ့ Argument မှာ @Dispose ဆိုပြီး EntityManager ကို ပေးထားပါတယ်။ CDI Container မှ နောက်ဆုံး Produce လုပ်ထားတဲ့ EntityManager ကို Reference မရှိတော့ဘူးဆိုရင် close method ကို ခေါ်မှာ ဖြစ်တဲ့အတွက် EntityManager ကို close လုပ်ပေးမှာ ဖြစ်ပါတယ်။

ဆက်ပါဦးမယ်
မင်းလွင်


No comments:

Post a Comment