寫在前面
最近,一位讀者出去面試前準備了很久,信心滿滿的去面試。沒想到面試官的一個問題把他難住了。面試官的問題是這樣的:如何使用Spring將Service注入到Servlet中呢?這位讀者平時也是很努力的,看什麼原始碼啊、多執行緒啊、高併發啊、設計模式啊等等。沒想到卻在一個很簡單的問題上栽了跟斗,這就說明學習知識要系統化,要有條理,切忌東學一點,西記一點,否則,到頭來,啥也學不到。
專案工程原始碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
如何實現將Service注入到Servlet中??
這裡,我們列舉兩種解決方法(推薦使用第二種)
方法一:
直接重寫Servlet的Init()方法,程式碼如下:
public void init(ServletConfig servletConfig) throws ServletException {
ServletContext servletContext = servletConfig.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
AutowireCapableBeanFactory autowireCapableBeanFactory = webApplicationContext
.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.configureBean(this, BEAN_NAME);
}
這裡的BEAN_NAME即為我們需要注入到Spring容器中的服務,但這並不是一個好的方法,因為我們需要在每一個Servlet中都進行這樣的操作。
方法二:
我們可以寫一個類似於“org.springframework.web.struts.DelegatingRequestProcessor”的委託的Bean,然後通過配置的方法把我們的服務注入到servlet中,具體方法如下,
Step 1:編寫委託類DelegatingServletProxy
package com.telek.pba.base.util;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* 以下是類似org.springframework.web.struts.DelegatingRequestProcessor的一個委託
* 用於通過配置的方法,在Servlet中注入Service
* @author binghe
* */
public class DelegatingServletProxy extends GenericServlet{
private static final long serialVersionUID = 1L;
private String targetBean;
private Servlet proxy;
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
proxy.service(req, res);
}
/**
* 初始化
*/
public void init() throws ServletException {
this.targetBean = getServletName();
getServletBean();
proxy.init(getServletConfig());
}
/**
* 獲取Bean
*/
private void getServletBean() {
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
this.proxy = (Servlet) wac.getBean(targetBean);
}
}
Step 2:修改Web.xml配置
在純Servlet模式下,我們的配置方式如下(以下由於程式碼高亮外掛的問題,請將程式碼中的#替換成尖括號)
<servlet>
<description>活動發起模組活動查詢分頁Servlet</description>
<display-name>launchActivityQueryServlet</display>
<servlet-name>LaunchActivityQueryServlet</servlet-name>
<servlet-class>com.telek.pba.launch.servlet.LaunchActivityQueryServlet</servlet-class>
<servlet>
<servlet-mapping>
<servlet-name>LaunchActivityQueryServlet</servlet-name>
<url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet>
如果採用我們這種代理的方法,則配置應該修改為:
<servlet>
<description>活動發起模組活動查詢分頁Servlet</description>
<display-name>launchActivityQueryServlet</display>
<servlet-name>launchActivityQueryServlet</servlet-name>
<servlet-class>com.telek.pba.base.util.DelegatingServletProxy</servlet-class>
<servlet>
<servlet-mapping>
<servlet-name>launchActivityQuery</servlet-name>
<url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet>
注意:預設情況下,Servlet的配置中,LaunchActivityQuery的首字母一般為大寫,而我們的標題中已註明,我們採用Spring的註解模式,如果是自動掃描註解的話,預設情況下,註解的value值為首字母小寫,即:launchActivityQuery,因此,在我們新的配置中,要注意將首字母改為小寫,否則會報無法找到Bean的錯誤。
Step 3:至此,我們就可以像SSH的注入方式一樣,注入Servlet了,以下是個小示例:
package com.telek.pba.launch.servlet;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import com.telek.pba.base.model.PbaUserInfo;
import com.telek.pba.launch.dao.IPbaActivityInfoCurrentDAO;
@Component
public class LaunchActivityQueryServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
//注入IPbaActivityInfoCurrentDAO
@Resource
private IPbaActivityInfoCurrentDAO pbaActivityInfoCurrentDAO;
public LaunchActivityQueryServlet() {
super();
}
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//sth to do
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//sth to do
}
public void init() throws ServletException {
// Put your code here
}
}
最後,請留心在Spring配置檔案中,配置上自動掃描包的路徑:
<context:component-scan base-package="com.telek.pba.*.dao.impl,
com.telek.pba.*.service.impl,
com.telek.pba.*.servlet"/>
大功告成!
好了,我們們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!
專案工程原始碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
寫在最後
如果覺得文章對你有點幫助,請微信搜尋並關注「 冰河技術 」微信公眾號,跟冰河學習Spring註解驅動開發。公眾號回覆“spring註解”關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發不再迷茫。