แอปพลิเคชัน J2EE ของคุณทำงานช้าหรือไม่? พวกเขาสามารถทนต่อการรับส่งข้อมูลที่เพิ่มขึ้นได้หรือไม่? บทความนี้จะอธิบายเทคโนโลยีการปรับประสิทธิภาพให้เหมาะสมสำหรับการพัฒนาเพจ JSP และ Servlets ประสิทธิภาพสูงและยืดหยุ่นสูง แนวคิดคือการสร้างให้เร็วที่สุดและปรับให้เข้ากับจำนวนผู้ใช้ที่เพิ่มขึ้นและคำขอของพวกเขา ในบทความนี้ ฉันจะนำคุณไปสู่การเรียนรู้เทคนิคการปรับแต่งประสิทธิภาพที่ใช้งานได้จริงและผ่านการพิสูจน์แล้ว ซึ่งจะช่วยปรับปรุงประสิทธิภาพของเซิร์ฟเล็ตและเพจ jsp ของคุณได้อย่างมาก ดังนั้นจึงเป็นการปรับปรุงประสิทธิภาพของ J2EE เทคโนโลยีเหล่านี้บางส่วนใช้ในขั้นตอนการพัฒนา เช่น ขั้นตอนการออกแบบและการเขียนโค้ด อีกส่วนหนึ่งของเทคโนโลยีเกี่ยวข้องกับการกำหนดค่า
เทคนิคที่ 1: การแคชข้อมูลในเมธอด HttpServletinit()
เซิร์ฟเวอร์เรียกเมธอด init() ของเซิร์ฟเล็ตหลังจากสร้างอินสแตนซ์เซิร์ฟเล็ตและก่อนที่เซิร์ฟเล็ตจะจัดการคำขอใดๆ วิธีการนี้ถูกเรียกเพียงครั้งเดียวในวงจรชีวิตของเซิร์ฟเล็ต เพื่อปรับปรุงประสิทธิภาพ ให้แคชข้อมูลคงที่ใน init() หรือดำเนินการที่มีราคาแพงซึ่งต้องทำระหว่างการเริ่มต้น ตัวอย่างเช่น แนวปฏิบัติที่ดีที่สุดประการหนึ่งคือการใช้พูลการเชื่อมต่อ JDBC ที่ใช้อินเทอร์เฟซ javax.sql.DataSource
แหล่งข้อมูลได้มาจากแผนผัง JNDI การใช้ JNDI เพื่อค้นหาแหล่งข้อมูลทุกครั้งที่มีการเรียก SQL มีราคาแพงมาก และจะส่งผลร้ายแรงต่อประสิทธิภาพของแอปพลิเคชัน สามารถใช้เมธอด init() ของ Servlet เพื่อรับ DataSource และแคชเพื่อใช้ซ้ำในภายหลัง:
publicclassControllerServletextendsHttpServlet
-
privatejavax.sql.DataSourcetestDS=null;
publicvoidinit(ServletConfigconfig) พ่นServletException
-
super.init(กำหนดค่า);
บริบทctx=null;
พยายาม
-
ctx=newInitialContext();
testDS=(javax.sql.DataSource)ctx.lookup("jdbc/testDS");
-
จับ (การตั้งชื่อข้อยกเว้น)
-
ne.printStackTrace();
-
จับ (ข้อยกเว้น)
-
e.printStackTrace();
-
}
publicjavax.sql.DataSourcegetTestDS()
-
กลับทดสอบ DS;
-
-
-
}
เทคนิคที่ 2: ปิดใช้งานฟังก์ชันการโหลดอัตโนมัติของเซิร์ฟเล็ตและ JSP
คุณจะต้องรีสตาร์ทเซิร์ฟเวอร์ทุกครั้งที่คุณแก้ไข Servlet/JSP เนื่องจากคุณลักษณะการโหลดอัตโนมัติช่วยลดเวลาในการพัฒนา คุณลักษณะนี้จึงถือว่ามีประโยชน์มากในระหว่างขั้นตอนการพัฒนา อย่างไรก็ตาม มีราคาแพงมากในช่วงรันไทม์ servlet/JSP ทำให้ประสิทธิภาพการทำงานต่ำเนื่องจากการโหลดที่ไม่จำเป็นและเพิ่มภาระให้กับตัวโหลดคลาส อีกครั้ง สิ่งนี้อาจทำให้แอปพลิเคชันของคุณมีข้อขัดแย้งแปลกๆ เนื่องจากคลาสที่โหลดโดยตัวโหลดคลาสบางตัวไม่สามารถทำงานร่วมกับคลาสที่โหลดโดยตัวโหลดคลาสปัจจุบันได้ ดังนั้น เพื่อให้ได้ประสิทธิภาพที่ดีขึ้นในสภาพแวดล้อมการทำงาน ให้ปิดฟังก์ชันการโหลดอัตโนมัติของเซิร์ฟเล็ต/JSP
เทคนิคที่ 3: ควบคุม HttpSession
แอปพลิเคชันจำนวนมากต้องการชุดคำขอของไคลเอ็นต์เพื่อให้สามารถเชื่อมโยงซึ่งกันและกันได้ เนื่องจากโปรโตคอล HTTP ไม่มีสถานะ แอปพลิเคชันบนเว็บจึงต้องรับผิดชอบในการรักษาสถานะที่เรียกว่าเซสชัน เพื่อรองรับแอปพลิเคชันที่ต้องรักษาสถานะ เทคโนโลยี Javaservlet จึงจัดเตรียม API ที่จัดการเซสชันและอนุญาตให้มีกลไกหลายอย่างในการใช้งานเซสชัน วัตถุ HttpSession ทำหน้าที่เป็นเซสชัน แต่มีค่าใช้จ่ายในการใช้งาน เมื่อใดก็ตามที่มีการใช้และแทนที่ HttpSession เซิร์ฟเล็ตจะอ่าน HttpSession คุณสามารถปรับปรุงประสิทธิภาพได้โดยใช้เทคนิคต่อไปนี้:
lอย่าสร้าง HttpSession ดีฟอลต์ในเพจ JSP: โดยดีฟอลต์ เพจ JSP จะสร้าง HttpSession หากคุณไม่ได้ใช้ HttpSession ในเพจ JSP ของคุณ เพื่อประหยัดค่าใช้จ่ายด้านประสิทธิภาพ ให้ใช้คำแนะนำเพจต่อไปนี้เพื่อหลีกเลี่ยงการสร้างอ็อบเจ็กต์ HttpSession โดยอัตโนมัติ:
< %@pagesession="false"% >
1) อย่าจัดเก็บกราฟวัตถุขนาดใหญ่ใน HttpSession: หากคุณเก็บข้อมูลใน HttpSession เป็นกราฟวัตถุขนาดใหญ่ แอปพลิเคชันเซิร์ฟเวอร์จะต้องประมวลผลวัตถุ HttpSession ทั้งหมดในแต่ละครั้ง สิ่งนี้จะบังคับให้มีการซีเรียลไลซ์ Java และเพิ่มค่าใช้จ่ายในการคำนวณ เนื่องจากโอเวอร์เฮดของการทำให้เป็นอนุกรม ปริมาณงานของระบบจะลดลงเมื่อออบเจ็กต์ข้อมูลที่จัดเก็บไว้ในออบเจ็กต์ HttpSession เพิ่มขึ้น
2) ปล่อย HttpSession หลังการใช้งาน: เมื่อ HttpSession ไม่ได้ใช้งานอีกต่อไป ให้ใช้เมธอด HttpSession.invalidate() เพื่อทำให้เซสชันเป็นโมฆะ
3) ตั้งค่าการหมดเวลา: เอ็นจิ้นเซิร์ฟเล็ตมีค่าการหมดเวลาเริ่มต้น หากคุณไม่ลบเซสชันหรือใช้เซสชันต่อไปจนกว่าจะหมดเวลา เอ็นจิ้นเซิร์ฟเล็ตจะลบเซสชันออกจากหน่วยความจำ เนื่องจากโอเวอร์เฮดในหน่วยความจำและการรวบรวมขยะ ยิ่งค่าการหมดเวลาของเซสชันมากขึ้นเท่าใด ผลกระทบต่อความยืดหยุ่นและประสิทธิภาพของระบบก็จะยิ่งมากขึ้นเท่านั้น พยายามตั้งค่าการหมดเวลาเซสชันให้ต่ำที่สุด
เทคนิคที่ 4: ใช้การบีบอัด gzip
การบีบอัดคือแนวทางปฏิบัติในการลบข้อมูลที่ซ้ำซ้อนและอธิบายข้อมูลของคุณในพื้นที่ขนาดเล็กที่สุดเท่าที่จะเป็นไปได้ การใช้ gzip (GNUzip) เพื่อบีบอัดเอกสารสามารถลดเวลาในการดาวน์โหลดไฟล์ HTML ได้อย่างมีประสิทธิภาพ ยิ่งข้อความของคุณเล็กลงเท่าไรก็ยิ่งส่งได้เร็วยิ่งขึ้นเท่านั้น ดังนั้น หากคุณบีบอัดเนื้อหาที่สร้างโดยเว็บแอปพลิเคชันของคุณ ก็จะเข้าถึงผู้ใช้ได้เร็วยิ่งขึ้นและจะปรากฏบนหน้าจอของผู้ใช้ ไม่ใช่ทุกเบราว์เซอร์ที่รองรับการบีบอัด gzip แต่ง่ายต่อการตรวจสอบว่าเบราว์เซอร์รองรับหรือไม่ และส่งเนื้อหาที่บีบอัด gzip ไปยังเบราว์เซอร์ ข้อมูลโค้ดด้านล่างแสดงวิธีการส่งเนื้อหาที่บีบอัด
publicvoiddoGet (คำขอ HttpServletRequest, HttpServletResponse ตอบกลับ)
พ่น IOException, ServletException
{
OutputStreamout=null
//ChecktheAccepting-EncodingheaderfromtheHTTPrequest.
//หากส่วนหัวมี gzip ให้เลือก GZIP
//หากส่วนหัวมีการบีบอัด ให้เลือกZIP
//Otherwisechoosenocompression.Stringencoding=request.getHeader("Accept-Encoding
");
if(encoding!=null&&encoding.indexOf("gzip"!=-1)
-
response.setHeader("การเข้ารหัสเนื้อหา", "gzip");
ออก=ใหม่GZIPOutputStream(response.getOutputStream());
-
elseif(encoding!=null&&encoding.indexOf("compress")!=-1)
-
response.setHeader("การเข้ารหัสเนื้อหา", "บีบอัด");
ออก=newZIPOutputStream(response.getOutputStream());
-
อื่น
-
ออก=response.getOutputStream();
}
-
-
}
เทคนิคที่ 5: อย่าใช้ SingleThreadModel
SingleThreadModel รับประกันว่าเซิร์ฟเล็ตจะจัดการได้ครั้งละหนึ่งคำขอเท่านั้น หากเซิร์ฟเล็ตใช้อินเทอร์เฟซนี้ เอ็นจิ้นเซิร์ฟเล็ตจะสร้างอินสแตนซ์เซิร์ฟเล็ตแยกต่างหากสำหรับคำขอใหม่แต่ละรายการ ซึ่งจะทำให้ระบบมีค่าใช้จ่ายจำนวนมาก หากคุณต้องการแก้ไขปัญหาความปลอดภัยของเธรด โปรดใช้วิธีการอื่นแทนอินเทอร์เฟซนี้ ไม่แนะนำให้ใช้ SingleThreadModel ใน Servlet2.4 อีกต่อไป
เทคนิคที่ 6: ใช้
กลไกเซิร์ฟเล็ตพูลเธรดเพื่อสร้างเธรดแยกต่างหากสำหรับแต่ละคำขอ กำหนดเธรดให้กับเมธอด service() จากนั้นลบเธรดหลังจากดำเนินการเมธอด service() ตามค่าเริ่มต้น เอ็นจิ้นเซิร์ฟเล็ตอาจสร้างเธรดใหม่สำหรับแต่ละคำขอ เนื่องจากการสร้างและการลบเธรดมีราคาแพง ลักษณะการทำงานเริ่มต้นนี้จึงลดประสิทธิภาพของระบบ เราสามารถใช้เธรดพูลเพื่อปรับปรุงประสิทธิภาพได้ ตามจำนวนผู้ใช้พร้อมกันที่คาดไว้ ให้กำหนดค่าเธรดพูลและตั้งค่าจำนวนเธรดขั้นต่ำและสูงสุดในเธรดพูล รวมถึงค่าการเติบโตขั้นต่ำและสูงสุด เริ่มแรก เอ็นจิ้นเซิร์ฟเล็ตสร้างเธรดพูลที่มีจำนวนเธรดเท่ากับจำนวนเธรดขั้นต่ำในคอนฟิกูเรชัน จากนั้นเซิร์ฟเล็ตเอ็นจิ้นจะกำหนดเธรดจากพูลให้กับคำร้องขอ แทนที่จะสร้างเธรดใหม่ทุกครั้ง หลังจากเสร็จสิ้นการดำเนินการ เซิร์ฟเล็ตเอ็นจิ้นจะนำเธรดกลับเข้าไปในพูลเธรด การใช้เธรดพูลทำให้สามารถปรับปรุงประสิทธิภาพได้อย่างมาก หากจำเป็น สามารถสร้างเธรดเพิ่มเติมได้ตามจำนวนเธรดสูงสุดและจำนวนการขยาย
เทคนิค 7: เลือกกลไกการรวมที่ถูกต้อง
ในหน้า JSP มีสองวิธีในการรวมไฟล์: รวมคำแนะนำ (< %@includefile="test.jsp"% >) และรวมการดำเนินการ (<jsp:includepage="test.jsp " ล้าง = "จริง"/>) คำสั่ง include รวมถึงเนื้อหาของไฟล์ที่ระบุในระหว่างขั้นตอนการคอมไพล์ ตัวอย่างเช่น เมื่อเพจถูกคอมไพล์เป็นเซิร์ฟเล็ต การดำเนินการรวมเกี่ยวข้องกับการรวมเนื้อหาไฟล์ในระหว่างขั้นตอนการร้องขอ ตัวอย่างเช่น เมื่อผู้ใช้ร้องขอเพจ การรวมคำแนะนำนั้นเร็วกว่าการรวมการกระทำ ดังนั้น เว้นแต่ไฟล์ที่รวมไว้จะเปลี่ยนแปลงบ่อยครั้ง คุณจะได้รับประสิทธิภาพที่ดีขึ้นโดยใช้คำสั่ง include
เทคนิคที่ 8: ใช้ขอบเขตที่เหมาะสมในการดำเนินการ useBean
หนึ่งในวิธีที่มีประสิทธิภาพมากที่สุดในการใช้เพจ JSP คือการทำงานกับส่วนประกอบ JavaBean JavaBeans สามารถฝังลงในเพจ JSP ได้โดยใช้แท็ก <jsp:useBean> ไวยากรณ์เป็นดังนี้:
<jsp:useBeanid="name"scope="page|request|session|application"class=
"package.className"type="typeName">
</jsp:useBean>
แอตทริบิวต์ขอบเขตอธิบายขอบเขตที่มองเห็นได้ของถั่ว ค่าเริ่มต้นของแอตทริบิวต์ขอบเขตคือหน้า คุณควรเลือกช่วงที่ถูกต้องตามความต้องการของแอปพลิเคชันของคุณ มิฉะนั้นจะส่งผลต่อประสิทธิภาพการทำงานของแอปพลิเคชันของคุณ
ตัวอย่างเช่น หากคุณต้องการออบเจ็กต์เฉพาะสำหรับบางคำขอ แต่คุณตั้งค่าขอบเขตเป็นเซสชัน ออบเจ็กต์นั้นจะยังคงอยู่ในหน่วยความจำหลังจากคำขอสิ้นสุดลง มันจะยังคงอยู่ในหน่วยความจำ เว้นแต่คุณจะลบออกจากหน่วยความจำอย่างชัดเจน ทำให้เซสชันใช้งานไม่ได้ หรือเซสชันหมดเวลา หากคุณไม่เลือกแอตทริบิวต์ขอบเขตที่ถูกต้อง ประสิทธิภาพจะได้รับผลกระทบเนื่องจากหน่วยความจำและค่าใช้จ่ายในการรวบรวมขยะ ดังนั้นให้กำหนดขอบเขตที่เหมาะสมสำหรับออบเจ็กต์และลบออกทันทีที่คุณทำเสร็จแล้ว
เทคนิคเบ็ดเตล็ด
1) หลีกเลี่ยงการต่อสตริง: เนื่องจากออบเจ็กต์ String เป็นออบเจ็กต์ที่ไม่เปลี่ยนรูป การใช้ตัวดำเนินการ "+" จะส่งผลให้เกิดการสร้างออบเจ็กต์ Zero-time จำนวนมาก ยิ่งคุณใช้ "+" มากเท่าใด ออบเจ็กต์ Zero-time ก็จะถูกสร้างขึ้นมากขึ้น ซึ่งจะส่งผลต่อประสิทธิภาพการทำงาน เมื่อคุณต้องการเชื่อมสตริงเข้าด้วยกัน ให้ใช้ StringBuffer แทนการดำเนินการ "+"
2) หลีกเลี่ยงการใช้ System.out.println: System.out.println ประมวลผลอินพุต/เอาต์พุตของดิสก์พร้อมกัน ซึ่งจะช่วยลดปริมาณงานของระบบได้อย่างมาก หลีกเลี่ยงการใช้ System.out.println ทุกครั้งที่เป็นไปได้ แม้ว่าจะมีเครื่องมือตรวจแก้จุดบกพร่องที่พร้อมใช้มากมาย แต่บางครั้ง System.out.println ยังคงมีประโยชน์สำหรับการติดตามหรือตรวจแก้จุดบกพร่อง คุณควรกำหนดค่า System.out.println ให้เปิดเฉพาะในระหว่างขั้นตอนข้อผิดพลาดและการดีบักเท่านั้น การใช้ตัวแปร FinalBoolean เมื่อกำหนดค่าเป็นเท็จ การตรวจสอบการปรับให้เหมาะสมและเอาต์พุตการติดตามการดำเนินการจะเสร็จสมบูรณ์ในระหว่างขั้นตอนการคอมไพล์
3) การเปรียบเทียบ ServletOutputStream และ PrintWriter: เนื่องจากกระแสเอาต์พุตอักขระและการเข้ารหัสข้อมูลเป็นไบต์ การใช้ PrintWriter ทำให้เกิดค่าใช้จ่ายด้านประสิทธิภาพเล็กน้อย ดังนั้นควรใช้ PrintWriter หลังจากการแปลงชุดอักขระทั้งหมดเสร็จสิ้นอย่างถูกต้องแล้ว ในทางกลับกัน เมื่อคุณรู้ว่าเซิร์ฟเล็ตของคุณจะส่งคืนเฉพาะข้อมูลไบนารี่ ให้ใช้ ServletOutputStream เนื่องจากคอนเทนเนอร์เซิร์ฟเล็ตไม่ได้เข้ารหัสข้อมูลไบนารี ดังนั้นคุณจึงกำจัดค่าใช้จ่ายในการแปลงชุดอักขระออก
สรุป
วัตถุประสงค์ของบทความนี้คือเพื่อแสดงให้คุณเห็นเทคนิคการปรับประสิทธิภาพในทางปฏิบัติและผ่านการพิสูจน์แล้วสำหรับการปรับปรุงประสิทธิภาพของเซิร์ฟเล็ตและ JSP ซึ่งจะปรับปรุงประสิทธิภาพโดยรวมของแอปพลิเคชัน J2EE ของคุณ ขั้นตอนต่อไปควรสังเกตการปรับประสิทธิภาพของเทคโนโลยีที่เกี่ยวข้องอื่นๆ เช่น EJB, JMS และ JDBC