Awal cerita dimulai ketika dahulu kala saat saya membuat sebuah aplikasi berbasis swing dengan koneksi database menggunakan jdbc (purba banget yah…). Sebuah kasus muncul ketika saya harus menginisialisasikan setiap Object DataSource di setiap class yang membutuhkan pasokan koneksi ke database. Sebuah teknik yang sangat buruk baik secara penulisan kode yang berulang-ulang dan membuang banyak waktu, lebih buruk lagi pengaruhnya terhadap performa aplikasi karena koneksi ke database merupakan sebuah operasi yang mahal, tidak terbayangkan berapa banyak koneksi yang terjadi hanya untuk membuat satu buah CRUD saja. Singkat cerita setelah cari-cari (curi-curi), disitulah awal mula saya bertemu dengan sebuah istilah yang dinamakan Dependency Injection (DI) dan Inversion of Control (Ioc), nah loh dua buah istilah ternyata :p yaitu sebuah mekanisme dimana sebuah object diinisialisasikan ‘sekali’ dalam IoC container yang kemudian akan disuntikkan ke setiap class yang membutuhkannya, walaupun saat itu saya masih menggunakan cara manual untuk melakukan injeksi ke setiap class melalui constructor. Akhir cerita masalah selesai hingga saya meneruskan sebuah project bernama BlueOxygen Postila (yang ini sudah pakai hibernate loh :D). Weeiiitt jangan pergi dulu, cerita masih belum selesai. Babak satu tuntas, dan babak selanjutnya pun berjalan, dan memang benar, masalah barupun muncul ketika saya membuat aplikasi berbasis web menggunakan Struts2 sebagai controllernya. Teknik injeksi pada Postila sama sekali tidak berlaku pada aplikasi web. Dan lagi-lagi saya dipertemukan dengan teknologi yang bernama SpringFramework, sebuah IoC Container yang terpopuler saat itu (mungkin juga sampai saat ini :D). “Hoaammmm ngantuk, kepanjangan ceritanya!!!” Wehe saya yakin semua yang baca pasti pada ngantuk… Gak usah panjang lebar (tapi panjang buaaanget :p), saya mau sharing gimana cara melakukan injeksi pada Struts2 dengan menggunakan Spring sebagai IoC containernya. Disini saya mengambil contoh kasus DataSource dimana setiap… @#$@%#$^%$&%!!! Hehehe, kasusnya sama seperti di awal cerita. Pertama saya menggunakan Struts versi 2.2.1 dan SpringFramework versi 3.0.1. Berikut beberapa library yang dibutuhkan (belum pake maven :p) Kemudian tambahkan baris berikut pada web.xml
1: <?xml version="1.0" encoding="UTF-8"?>2: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3: xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"4: xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"5: id="WebApp_ID" version="2.5">6:7: <display-name>Struts2</display-name>8:9: <filter>10: <filter-name>struts2</filter-name>11: <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>12: </filter>13:14: <filter-mapping>15: <filter-name>struts2</filter-name>16: <url-pattern>/*</url-pattern>17: </filter-mapping>18:19: <!-- Spring Configuration -->
20: <context-param>21: <param-name>contextConfigLocation</param-name>22: <param-value>classpath:applicationContext*.xml</param-value>23: </context-param>24:25: <listener>26: <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>27: </listener>28:29: <welcome-file-list>30: <welcome-file>index.jsp</welcome-file>31: </welcome-file-list>32: </web-app>
Berikut konfigurasi jdbc connection pada applicationContext-jdbc yang diletakkan pada classpath. Saya menggunakan MySQL DB.
1: <?xml version="1.0" encoding="UTF-8"?>2: <beans xmlns="http://www.springframework.org/schema/beans"3: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"4: xmlns:p="http://www.springframework.org/schema/p"5: xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd6: http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
7:8: <bean id="dataSource"9: class="org.springframework.jdbc.datasource.DriverManagerDataSource"10: p:driverClassName="com.mysql.jdbc.Driver" p:username="root"11: p:password="admin" p:url="jdbc:mysql://localhost:3306/test" />12:13: </beans>14:
Kemudian untuk memudahkan implementasi method buat sebuah interface untuk menerima datasource dari konfigurasi bean.
1: package com.mervpolis.dwx.struts2spring.datasource;
2:3: import javax.sql.DataSource;
4:5: public interface DataSourceAware {6:7: /**
8: * Action class yang mengimplementasikan method ini akan secara otomatis9: * ter-inject oleh object yang telah diinisialisasi pada10: * applicationContext-jdbc.xml. Nama method harus sama dengan id pada bean11: * (jika id="datasource" maka nama method adalah setDatasource()) dengan12: * parameter yang juga harus disesuaikan dengan class pada bean13: * (org.springframework.jdbc.datasource.DriverManagerDataSource merupakan14: * implementasi dari javax.sql.DataSource)15: */16: void setDataSource(DataSource dataSource);
17:18: }19:
Coding terus, terus coding… Berikut konfigurasi dari struts.xml
1: <?xml version="1.0" encoding="UTF-8" ?>2:3: <!DOCTYPE struts PUBLIC
4: "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"5: "http://struts.apache.org/dtds/struts-2.0.dtd">
6:7: <struts>8: <constant name="struts.enable.DynamicMethodInvocation" value="false" />9: <constant name="struts.devMode" value="false" />10: <constant name="struts.convention.action.suffix" value="Controller" />11: <constant name="struts.convention.default.parent.package" value="struts-default" />12: <constant name="struts.convention.package.locators" value="action" />13: </struts>
Terakhir buat Action Classnya…
1: package com.mervpolis.dwx.struts2spring.action;
2:3: import java.sql.Connection;
4: import java.sql.ResultSet;
5: import java.util.ArrayList;
6: import java.util.HashMap;
7: import java.util.List;
8: import java.util.Map;
9:10: import javax.sql.DataSource;
11:12: import org.apache.struts2.convention.annotation.Action;
13: import org.apache.struts2.convention.annotation.Result;
14: import org.apache.struts2.convention.annotation.Results;
15:16: import com.mervpolis.dwx.struts2spring.datasource.DataSourceAware;
17: import com.opensymphony.xwork2.ActionSupport;
18:19: @Results({ @Result(name = ActionSupport.SUCCESS, type = "velocity", location = "/view/item/item_list.vm") })20: public class ItemController extends ActionSupport implements DataSourceAware {21:22: private DataSource dataSource;
23: private List result = new ArrayList();24:25: @Action("/item/show")
26: public String show() throws Exception {27: if (dataSource == null) {28: addActionError("Gagal menyuntik datasource");
29: } else {
30: Connection connection = dataSource.getConnection();31: ResultSet resultSet = connection.prepareStatement(32: "SELECT * FROM item").executeQuery();
33: while (resultSet.next()) {
34: Map data = new HashMap();
35: data.put("name", resultSet.getString("name"));36: data.put("price", resultSet.getString("price"));37: result.add(data);38: }39: }40:41: return SUCCESS;
42: }43:44: public List getResult() {
45: return result;
46: }47:48: /**
49: * Nah method inilah yang nantinya secara otomatis akan disuntik oleh si spring50: */51: public void setDataSource(DataSource dataSource) {52: this.dataSource = dataSource;
53: }54: }55:
Eits ternya ada satu lagi yang ketinggalan… Jangan lupa buat viewernya juga… (classpath:/vew/item/item_list.vm)
1: #foreach($error in $actionErrors)2: $error3: #end4:5: $!result
Dan akhirnya selesai juga :D coba jalankan, mungkin terkesan ajaib dimana DataSource tiba-tiba telah terinisialisasi dan aplikasipun berjalan seperti pada normalnya dan disinilah menurut saya kecanggihan dari Spring.