1. 程式人生 > >SSH的亂七八糟【過濾器+攔截器+監聽器】

SSH的亂七八糟【過濾器+攔截器+監聽器】

一些面試的知識點:

今天想著隨便寫點,為日後回憶做點準備:

=======================過濾器和攔截器===================================================

過濾器<filter>:

攔截器<inteceptor>

過濾器【還沒有進入業務裡面】是在java web中,你傳入的request,response提前過濾掉一些資訊,或者提前設定一些引數,

所以過濾器是攔截在業務請求之前

然後再傳入servlet或者struts的 action進行業務邏輯,

比如:

1:過濾掉非法url(不是login.do的地址請求,如果使用者沒有登陸都過濾掉),

2:在傳入servlet或者 struts的action前統一設定字符集,或者去除掉一些非法字元

攔截器【已結進入到了業務裡面】是在面向切面程式設計的

1:在你的service或者一個方法前呼叫一個方法,preHandle(){xxxxx}

2:在你的service或者一個方法後呼叫一個方法比如動態代理就是攔截器的簡單實現,在你呼叫方法前打印出字串(或者做其它業務邏輯的操作),也可以在你呼叫方法後打印出字串,甚至在你丟擲異常的時候做業務邏輯的操作


攔截器與過濾器的區別 :

  1. 攔截器是基於java的反射機制的【因為他用的是動態代理,裡面實現使用的是java反射】,而過濾器是基於函式回撥。
  2. 攔截器不依賴與servlet容器,過濾器依賴與servlet容器。【因為他的引數是HttpServletrequest,HttpServletresponse】
  3. 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。(下面提到,可以過濾html,指定資料夾等)
  4. 攔截器可以訪問action上下文、值棧裡的物件【因為他的引數是ActionInvocation】,而過濾器不能訪問。
  5. 在action的生命週期中,攔截器可以多次被呼叫,而過濾器只能在容器初始化時被呼叫一次

執行順序 :過濾前 - 攔截前 - Action處理 - 攔截後 - 過濾後。個人認為過濾是一個橫向的過程,首先把客戶端提交的內容進行過濾(例如未登入使用者不能訪問內部頁面的處理);過濾通過後,

攔截器將檢查使用者提交資料的驗證,做一些前期的資料處理,接著把處理後的資料發給對應的Action;Action處理完成返回後,攔截器還可以做其他過程(還沒想到要做啥),再向上返回到過濾器的後續操作。

面向切面程式設計(AOP是Aspect Oriented Program的首字母縮寫) ,我們知道,面向物件的特點是繼承、多型和封裝。而封裝就要求將功能分散到不同的物件中去,這在軟體設計中往往稱為職責分配。實際上也就是說,讓不同的類設計不同的方法。這樣程式碼就分散到一個個的類中去了。這樣做的好處是降低了程式碼的複雜程度,使類可重用。
      但是人們也發現,在分散程式碼的同時,也增加了程式碼的重複性。什麼意思呢?比如說,我們在兩個類中,可能都需要在每個方法中做日誌。按面向物件的設計方法,我們就必須在兩個類的方法中都加入日誌的內容。也許他們是完全相同的,但就是因為面向物件的設計讓類與類之間無法聯絡,而不能將這些重複的程式碼統一起來。

 也許有人會說,那好辦啊,我們可以將這段程式碼寫在一個獨立的類獨立的方法裡,然後再在這兩個類中呼叫。但是,這樣一來,這兩個類跟我們上面提到的獨立的類就有耦合了,它的改變會影響這兩個類。那麼,有沒有什麼辦法,能讓我們在需要的時候,隨意地加入程式碼呢?這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式設計。 
      一般而言,我們管切入到指定類指定方法的程式碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點。
有了AOP,我們就可以把幾個類共有的程式碼,抽取到一個切片中,等到需要時再切入物件中去,從而改變其原有的行為。
這樣看來,AOP其實只是OOP的補充而已OOP從橫向上區分出一個個的類來,而AOP則從縱向上向物件中加入特定的程式碼。有了AOP,OOP變得立體了。如果加上時間維度,AOP使OOP由原來的二維變為三維了,由平面變成立體了。從技術上來說,AOP基本上是通過代理機制實現的。 
     AOP在程式設計歷史上可以說是里程碑式的,對OOP程式設計是一種十分有益的補充。
大家 一直在說spring aop,關於具體如何aop的,請檢視這篇文章:http://zywang.iteye.com/blog/974226

下面看看靜態代理例項

二者的配置都在web.xml中:

Filter過濾器一個Web應用元件,和Servlet類似,也需要在Web應用配置檔案中進行配置:首先是過濾器的Web應用定義包含在<filter>…</filer>元素中,其次是Web應用的過濾器對映配置檔案<filter-mapping>…</filter-mapping> 

過濾器的應用很廣泛,在這裡介紹利用過濾器進行中文轉碼

一般在JavaWeb應用中,當利用request.getParameter(String str)方法獲取從表單或是頁面傳過來的中文引數都會是一個亂碼。

通常的做法是:會採用如下的轉碼方式在Servlet或是JSP中進行轉碼設定: 
(1)request.setCharacterEncoding("gb2312"); 
(2)String username = request.getParameter("username"); 
username = new String(username.getBytes("ISO-8859-1"), "GB2312"); 
這樣做的缺點是:
假設:一個表單有多資料傳到Servlet或是JSP,那麼就可能在這些Servlet或是JSP中寫下多個request.setCharacterEncoding("gb2312")或是多個類似於String username = request.getParameter("username"); 
username = new String(username.getBytes("ISO-8859-1"), "GB2312");這樣子肯定加大程式碼工作量

解決辦法是:
針對上面的一些常見的問題,下面利用過濾器進行中文轉碼就可以迎刃而解。配置Filter的步驟如下: 

過濾器配置步驟:

1.配置web.xml


2.開發過濾器:比如類CharactsetConversion【該類必須實現filter介面】,同時實現Filter介面提供的三個方法:

(1)void doFilter(ServletRequest req,ServletResponse res,FilterChain filterChain) 
(2)void init(FilterConfig filterConfig) 
(3)void destroy() 


對於配置的提升:
1。如果要對映過濾應用程式中所有資源:

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.過濾指定的型別檔案資源

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

可以一下寫多個過來型別,其中<url-pattern>注意沒有“/”斜槓

3.過濾指定的目錄

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
    <url-pattern>/folder_name/*</url-pattern>
</filter-mapping>

4.過濾指定的servlet

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
   <servlet-name>loggerservlet</servlet-name>//注意這裡是servlet
</filter-mapping>

5.過濾指定檔案

<filter-mapping>
    <filter-name>loggerfilter</filter-name>
    <url-pattern>/simplefilter.html</url-pattern>
</filter-mapping>

下面總結三種經常用到的過濾器:

一、使瀏覽器不快取頁面的過濾器     
public class ForceNoCacheFilter implements Filter {    
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException    
{    
    ((HttpServletResponse) response).setHeader("Cache-Control","no-cache");    
    ((HttpServletResponse) response).setHeader("Pragma","no-cache");    
    ((HttpServletResponse) response).setDateHeader ("Expires", -1);    
    filterChain.doFilter(request, response);    
}    
public void destroy()    
{    
}  
public void init(FilterConfig filterConfig) throws ServletException    
{    
}    
}    

二、檢測使用者是否登陸的過濾器    

/**   
* 用於檢測使用者是否登陸的過濾器,如果未登入,則重定向到指的登入頁面    
* filter中配置引數    
* checkSessionKey 需檢查的在 Session 中儲存的關鍵字   

* redirectURL 如果使用者未登入,則重定向到指定的頁面,URL不包括 ContextPath   

* notCheckURLList 不做檢查的URL列表,以分號分開,並且 URL 中不包括 ContextPath   
*/   
public class CheckLoginFilter    
implements Filter    
{    
      protected FilterConfig filterConfig = null;    
      private String redirectURL = null;    
      private List notCheckURLList = new ArrayList();    
      private String sessionKey = null;    

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException    
{    
    HttpServletRequest request = (HttpServletRequest) servletRequest;    
    HttpServletResponse response = (HttpServletResponse) servletResponse;    

     HttpSession session = request.getSession();    
    if(sessionKey == null)    
    {    
     filterChain.doFilter(request, response);    
     return;    
    }    
    if((!checkRequestURIIntNotFilterList(request)) && session.getAttribute(sessionKey) == null)    
    {    
     response.sendRedirect(request.getContextPath() + redirectURL);    
     return;    
    }    
    filterChain.doFilter(servletRequest, servletResponse);    
}    

public void destroy()    
{    
    notCheckURLList.clear();    
}    

private boolean checkRequestURIIntNotFilterList(HttpServletRequest request)    
{    
    String uri = request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo());    
    return notCheckURLList.contains(uri);    
}    

public void init(FilterConfig filterConfig) throws ServletException    
{    
    this.filterConfig = filterConfig;    
    redirectURL = filterConfig.getInitParameter("redirectURL");    
    sessionKey = filterConfig.getInitParameter("checkSessionKey");    

    String notCheckURLListStr = filterConfig.getInitParameter("notCheckURLList");    

    if(notCheckURLListStr != null)    
    {    
     StringTokenizer st = new StringTokenizer(notCheckURLListStr, ";");    
     notCheckURLList.clear();    
     while(st.hasMoreTokens())    
     {    
      notCheckURLList.add(st.nextToken());    
     }    
    }    
}    
}    

三、字元編碼的過濾器   (上面的例項程式碼)     
四、資源保護過濾器    


import org.apache.commons.logging.Log;    
import org.apache.commons.logging.LogFactory;    
   
/**   
* This Filter class handle the security of the application.   
* It should be configured inside the web.xml.   
*/   
public class SecurityFilter implements Filter {    
//the login page uri    
private static final String LOGIN_PAGE_URI = "login.jsp";    
     
//the logger object    
private Log logger = LogFactory.getLog(this.getClass());    
     
//a set of restricted resources    
private Set restrictedResources;    
     
/**   
   * Initializes the Filter.   
   */   
public void init(FilterConfig filterConfig) throws ServletException {    
   this.restrictedResources = new HashSet();    
   this.restrictedResources.add("/createProduct.jsf");    
   this.restrictedResources.add("/editProduct.jsf");    
   this.restrictedResources.add("/productList.jsf");    
}    
     
/**   
   * Standard doFilter object.   
   */   
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)    
    throws IOException, ServletException {    
   this.logger.debug("doFilter");    
      
   String contextPath = ((HttpServletRequest)req).getContextPath();    
   String requestUri = ((HttpServletRequest)req).getRequestURI();    
      
   this.logger.debug("contextPath = " + contextPath);    
   this.logger.debug("requestUri = " + requestUri);    
      
   if (this.contains(requestUri, contextPath) && !this.authorize((HttpServletRequest)req)) {    
    this.logger.debug("authorization failed");    
    ((HttpServletRequest)req).getRequestDispatcher(LOGIN_PAGE_URI).forward(req, res);    
   }    
   else {    
    this.logger.debug("authorization succeeded");    
    chain.doFilter(req, res);    
   }    
}    
     
public void destroy() {}     
     
private boolean contains(String value, String contextPath) {    
   Iterator ite = this.restrictedResources.iterator();    
      
   while (ite.hasNext()) {    
    String restrictedResource = (String)ite.next();    
       
    if ((contextPath + restrictedResource).equalsIgnoreCase(value)) {    
     return true;    
    }    
   }    
      
   return false;    
}    
     
private boolean authorize(HttpServletRequest req) {    
   
               //處理使用者登入    
        /* UserBean user = (UserBean)req.getSession().getAttribute(BeanNames.USER_BEAN);   
     
   if (user != null && user.getLoggedIn()) {   
    //user logged in   
    return true;   
   }   
   else {   
    return false;   
   }*/   
}    
}    

==========================================================================

接下來看看攔截器:


=============================================================================

struts1基本被拋棄了,下面主要討論struts2

核心包:

struts2-core-2.0.11.1.jar

xwork-2.0.4.jar

commons-logging-1.0.4.jar

freemarker-2.3.8.jar

Struts2入口是過濾器:

下面是web.xml檔案中struts的配置:


注意下這裡的dispatcher

<dispatcher>元素,這個元素有四個可能的值:即

1.REQUEST,預設是這個【其實就是redirect】

2.FORWARD,

3.INCLUDE

4.ERROR,

使得filter將會作用於直接從客戶端過來的request,通過forward過來的request,通過include過來的request和通過<error-page>過來的request。如果沒有指定任何<dispatcher>元素,預設值是REQUEST

struts.xml中的配置點:

1.struts2的攔截器intercepter:

 首先攔截器是配置在struts.xml檔案中:

其次看結構


從上面的呼叫過程我們可以總結出來:過濾器和攔截器在struts2中呼叫順序:

過濾前 - 攔截前 - Action處理 - 攔截後 - 過濾後。個人認為過濾是一個橫向的過程,首先把客戶端提交的內容進行過濾(例如未登入使用者不能訪問內部頁面的處理);過濾通過後,攔截器將檢查使用者提交資料的驗證,做一些前期的資料處理,接著把處理後的資料發給對應的Action;Action處理完成返回後,攔截器還可以做其他過程(還沒想到要做啥),再向上返回到過濾器的後續操作。

我想說的是:這裡的interceptor-stak,攔截器棧,並且這種寫法是舊的寫法,

JDK5.0以後有了標註,struts2提供了標註寫法支援,不用像上圖中這麼寫了。下面的截圖那樣在action中直接寫

InterceptorRefs({

InterceptorRef("aaaa"),

InterceptorRef("bbbbb"),

})

裡面的多個攔截器interceptor-ref是遞迴呼叫,腫麼解釋呢:

1.aaa攔截器invoke()之前的程式碼,

2.bbb攔截器invoke()之前的程式碼

3.bbb攔截器invoke()之後的程式碼

4.aaa攔截器invoke()之後的程式碼

再次看呼叫[也即是寫Action]

區別在於:

Struts1.x中的動作類必須從Action類中繼承,而Struts2.x的動作類需要從com.opensymphony.xwork2.ActionSupport類繼承


===========   監聽器[spring用的就是contextLoaderlistener監聽]=============================

監聽器概述

1.Listener是Servlet的監聽器
2.可以監聽客戶端的請求、服務端的操作等。
3.通過監聽器,可以自動激發一些操作,如監聽線上使用者數量,當增加一個HttpSession時,給線上人數加1。
4.編寫監聽器需要實現相應的介面
5.編寫完成後在web.xml檔案中配置一下,就可以起作用了
6.可以在不修改現有系統基礎上,增加web應用程式生命週期事件的跟蹤


常用的監聽介面

1.ServletContextAttributeListener
監聽對ServletContext屬性的操作,比如增加/刪除/修改
2.ServletContextListener
監聽ServletContext,當建立ServletContext時,激發 contextInitialized(ServletContextEvent sce)方法;當銷燬ServletContext時,激發contextDestroyed(ServletContextEvent sce)方法。
3.HttpSessionListener
監聽HttpSession的操作。當建立一個 Session時,激發session Created(SessionEvent se)方法;當銷燬一個Session時,激發sessionDestroyed (HttpSessionEvent se)方法。
4.HttpSessionAttributeListener
監聽HttpSession中的屬性的操作。當在Session增加一個屬性時,激發 attributeAdded(HttpSessionBindingEvent se) 方法;當在Session刪除一個屬性時,激發attributeRemoved(HttpSessionBindingEvent se)方法;當在Session屬性被重新設定時,激發attributeReplaced(HttpSessionBindingEvent se) 方法。

使用範例:
由監聽器管理共享資料庫連線

生命週期事件的一個實際應用由context監聽器管理共享資料庫連線。在web.xml中如下定義監聽器:
<listener>
<listener-class>XXX.MyConnectionManager</listener-class>
</listener> ?server建立監聽器的例項,接受事件並自動判斷實現監聽器介面的型別。要記住的是由於監聽器是配置在部署描述符web.xml中,所以不需要改變任何程式碼就可以新增新的監聽器。

public class MyConnectionManager implements ServletContextListener{
public void contextInitialized(ServletContextEvent e) {
Connection con = // create connection
e.getServletContext().setAttribute("con", con);
}
public void contextDestroyed(ServletContextEvent e) {
Connection con = (Connection) e.getServletContext().getAttribute("con");
try {
con.close();
}
catch (SQLException ignored) { } // close connection
}
}
監聽器保證每新生成一個servlet context都會有一個可用的資料庫連線,並且所有的連線對會在context關閉的時候隨之關閉。

在web.xml中加入:
<listener><listener-class>servletlistener111111.SecondListener</listener-class> </listener>

==================================================

關於使用者超時的例子:

public class OnlineUserListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
}
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
ServletContext application = session.getServletContext();
// 取得登入的使用者名稱
String username = (String) session.getAttribute("username");
// 從線上列表中刪除使用者名稱
List onlineUserList = (List) application.getAttribute("onlineUserList");
onlineUserList.remove(username);
System.out.println(username + "超時退出。");
}
}

以下兩種情況下就會發生sessionDestoryed(會話銷燬)事件:

1.執行session.invalidate()方法時。例如:request.getSession().invalidate();

2.如果使用者長時間沒有訪問伺服器,超過了會話最大超時時間,伺服器就會自動銷燬超時的session。會話超時時間可以在web.xml中進行設定。

========================================

使用HttpSessionBindingListener

HttpSessionBindingListener雖然叫做監聽器,但使用方法與HttpSessionListener完全不同。我們實際看一下它是如何使用的。

我們的OnlineUserBindingListener實現了HttpSessionBindingListener介面,介面中共定義了兩個方法:valueBound()和valueUnbound(),分別對應資料繫結,和取消繫結兩個事件。

所謂對session進行資料繫結,就是呼叫session.setAttribute()把HttpSessionBindingListener儲存進session中。我們在LoginServlet.java中進行這一步。

// 把使用者名稱放入線上列表
session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));

這就是HttpSessionBindingListener和HttpSessionListener之間的最大區別:HttpSessionListener只需要設定到web.xml中就可以監聽整個應用中的所有session。 HttpSessionBindingListener必須例項化後放入某一個session中,才可以進行監聽。

從監聽範圍上比較,HttpSessionListener設定一次就可以監聽所有session,HttpSessionBindingListener通常都是一對一的。

正是這種區別成就了HttpSessionBindingListener的優勢,我們可以讓每個listener對應一個username,這樣就不需要每次再去session中讀取username,進一步可以將所有操作線上列表的程式碼都移入listener,更容易維護。

valueBound()方法的程式碼如下:

public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ServletContext application = session.getServletContext();

// 把使用者名稱放入線上列表
List onlineUserList = (List) application.getAttribute("onlineUserList");
// 第一次使用前,需要初始化
if (onlineUserList == null) {
onlineUserList = new ArrayList();
application.setAttribute("onlineUserList", onlineUserList);
}
onlineUserList.add(this.username);
}

username已經通過構造方法傳遞給listener,在資料繫結時,可以直接把它放入使用者列表。

與之對應的valueUnbound()方法,程式碼如下:

public void valueUnbound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ServletContext application = session.getServletContext();

// 從線上列表中刪除使用者名稱
List onlineUserList = (List) application.getAttribute("onlineUserList");
onlineUserList.remove(this.username);

System.out.println(this.username + "退出。");
}

這裡可以直接使用listener的username操作線上列表,不必再去擔心session中是否存在username。

valueUnbound的觸發條件是以下三種情況:

1.執行session.invalidate()時。

2.session超時,自動銷燬時。

3.執行session.setAttribute("onlineUserListener", "其他物件");或

session.removeAttribute("onlineUserListener");將listener從session中刪除時。

因此,只要不將listener從session中刪除,就可以監聽到session的銷燬


======================================下面看看配置================================================

action的配置:Struts1.x的動作一般都以.do結尾,而Struts2是以.action結尾。

這一步struts1.x和struts2.x都是必須的,只是

在struts1.x中的配置檔案一般叫struts-config.xml(當然也可以是其他的檔名),而且一般放到WEB-INF目錄中。

而在truts2.x中的配置檔案一般為struts.xml


這裡的type可以取:

dispatcher:(其實就是forward),轉發可以儲存request中的值

redirect:

stream:

用標註的新寫法:


還要注意一點:

<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEstrutsPUBLIC
"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>
<package  name="struts2"   namespace="/mystruts"  extends="struts-default">
   

     <action name="sum"   class="action.FirstAction">
       

        <result  name="positive">/positive.jsp</result> 

       <result  name="negative">/negative.jsp</result>

   </action>

</package>

</struts>
在<struts>標籤中可以有多個<package>,第一個<package>可以指定一個Servlet訪問路徑(不包括動作名),如“/mystruts”

不能這樣寫

===============================================

jsp頁面中設計的struts2內容

Struts2自帶的tag:struts2

Struts2

中已經將

Struts1.x

的好幾個標籤庫都統一了,

Struts2

中只有一個標籤庫

/struts-tags

================================分割線=============================

下面看看struts的執行緒安全問題

sruts1.x是單例模式,所以執行緒不安全

strut2.本身是執行緒安全的,因為他為每一個請求都產生一個新例項,從根源上杜絕了這個問題

但是使用spring來管理Action後,IOC容器中管理的bean都是單例的,所以問題又出來了,和struts1一樣,

解決的辦法是:在spring的bean配置中,設定scope="prototype"

======================================================

spring IOC容器物件的呼叫


如果要想在普通的java程式碼中使用IoC容器中的bean實體:

則這樣寫:

1.例項化spring容器 和 從容器獲取Bean物件

例項化Spring容器常用的兩種方式:

方法一:

在類路徑下尋找配置檔案來例項化容器 [推薦使用]

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});

方法二:

在檔案系統路徑下尋找配置檔案來例項化容器 [這種方式可以在開發階段使用]

ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});

Spring的配置檔案可以指定多個,可以通過String陣列傳入。

當spring容器啟動後,因為spring容器可以管理bean物件的建立,銷燬等生命週期,

所以我們只需從容器直接獲取Bean物件就行,而不用編寫一句程式碼來建立bean物件。

從容器獲取bean物件的程式碼如下:

ApplicationContext ctx = new ClassPathXmlApplicationContext(“beans.xml”);

OrderService service = (OrderService)ctx.getBean("personService");

 檢視文章:http://www.blogjava.net/stevenjohn/archive/2012/08/20/385846.html

============================有關標籤================================


=============================spring 相關===============================

IoC

直觀地講,就是容器控制程式之間的關係,而非傳統實現中,由程式程式碼直接操控。這也就是所謂“控制反轉”的概念所在。控制權由應用程式碼中轉到了外部容器,控制權的轉移是所謂反轉。IoC還有另外一個名字——“依賴注入(Dependency Injection)”。從名字上理解,所謂依賴注入,即元件之間的依賴關係由容器在執行期決定,形象地說,即由容器動態地將某種依賴關係注入到元件之中。

spring依賴注入的三種方式:

1.通過介面注射--類必須實現容器給定的一個介面,然後容器會利用這個介面給我們這個類注射它所依賴的類。 

2.通過setter方法注射,這種方式也是Spring推薦的方式

public class Girl {
private Kissable kissable;
public void setKissable(Kissable kissable) {
this.kissable = kissable;
}
public void kissYourKissable() {
kissable.kiss();
}
}
<beans>
<bean id="boy" class="Boy"/>
<bean id="girl" class="Girl">
<property name="kissable">
<ref bean="boy"/>
</property>
</bean>
</beans>  

3.通過構造方法注射類,這種方式Spring同樣給予了實現,它和通過setter方式一樣,都在類裡無任何侵入性,但是,不是沒有侵入性,只是把侵入性轉移了,顯然第1種方式要求實現特定的介面,侵入性非常強,不方便以後移植。  

public class Girl {
private Kissable kissable;
public Girl(Kissable kissable) {
this.kissable = kissable;
}
public void kissYourKissable() {
kissable.kiss();
}
}
PicoContainer container = new DefaultPicoContainer();
container.registerComponentImplementation(Boy.class);
container.registerComponentImplementation(Girl.class);
Girl girl = (Girl) container.getComponentInstance(Girl.class);
girl.kissYourKissable();

下面看一個特別的類:OpenSessionInview


=================================三個框架整合===========================================



===================全域性事務與本地事務的區別==========

全域性事務:

資源管理器管理和協調的事務,

可以跨越多個數據庫和程序。

資源管理器一般使用

全域性事務:資源管理器管理和協調的事務,可以跨越多個數據庫和程序。資源管理器一般使用 XA 二階段提交協議與“企業資訊系統”(EIS) 或資料庫進行互動。  
本地事務:在單個 EIS 或資料庫的本地並且限制在單個程序內的事務。本地事務不涉及多個數據來源

在Hibernate配置檔案中有這麼兩種配置方式: 1.如果使用的是本地事務(jdbc事務) 
<property name="hibernate.current_session_context_class">thread</property>,這個是我們常用的選項,只針對一個數據庫進行操作,也就是說只針對一個事務性資源進行操作. 2. 如果使用的是全域性事務(jta事務) 
<property name="hibernate.current_session_context_class">jta</property>     
    以前我們學習的事務型別都屬於本地事務。 JTA(全域性事務)和thread(本地事務)有什麼區別呢?在某些應用場合,只能使用全域性事務,比如: 

有兩個資料庫:  
1.mysql 2.oracle  現在有個業務需求--轉賬  
step 1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql資料庫扣錢的。  
step 2> update oracle_table set amount=amount+xx where id=bbb 加錢,假設是在oracle資料庫扣錢的。  
現在怎麼確保兩個語句在同一個事務裡執行呢?   
以前在JDBC裡是這樣做  connection = mysql 連線mysql  
connection.setAutoCommit(false);  不自動提交  
1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql資料庫扣錢的。  
2> update oracle_table set amount=amount+xx where id=bbb  發生在oracle資料庫  connection.commit();  
執行這兩條語句,然後通過connection物件提交事務.我們這樣子做只能確保這兩個語句在同一個資料庫mysql裡面實現在同一個事務裡執行。 但是問題是我們現在是要連線到oracle資料庫,是不是需要connection2啊?   
connection = mysql 連線mysql  connection2 = oracle 連線oracle  
connection.setAutoCommit(false);  不自動提交  
1> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql資料庫扣錢的。

2> update oracle_table set amount=amount+xx where id=bbb  發生在oracle資料庫  connection.commit();  
connection2.setAutoCommit(false)

connection2.commit();  
事務只能在一個connection裡開啟,並且確保兩條語句都在該connection裡執行,這樣才能讓兩條語句在同一事務裡執行,現在問題就在於connection2是連線到oracle資料庫的,那麼connection2再開事務有意義嗎?它能確保嗎?不能,所以在這種情況下就只能使用全域性事務了。  
這種情況下用普通JDBC操作是滿足不了這個業務需求的,這種業務需求只能使用全域性事務,本地事務是無法支援我們的操作的,因為這時候,事務的生命週期不應該侷限於connection物件的生命週期範圍   
全域性事務怎麼做呢?  
JPA.getUserTransaction().begin();      首先要全域性事務的API,不需要我們編寫,通常容器已經提供給我們了,我們只需要begin一下  connection = mysql 連線mysql  connection2 = oracle 連線oracle  
connection--> update mysql_table set amount=amount-xx where id=aaa 發生扣錢,假設是在mysql資料庫扣錢的。  
connection2--> update oracle_table set amount=amount+xx where id=bbb 發生在oracle資料庫  JPA.getUserTransaction().commit(); 

那麼它是怎麼知道事務該提交還是回滾呢?  
這時候它使用了二次提交協議。二次提交協議簡單說就這樣:如果你先執行第一條語句,執行的結果先預提交到資料庫,預提交到資料庫了,資料庫會執行這條語句,然後返回一個執行的結果,這個結果假如我們用布林值表示的話,成功就是true,失敗就是false.然後把執行的結果放入一個(假設是List)物件裡面去,接下來再執行第二條語句,執行完第二條語句之後(也是預處理,資料庫不會真正實現資料的提交,只是說這條語句送到資料庫裡面,它模擬下執行,給你返回個執行的結果),假如這兩條語句的執行結果在List裡面都是true的話,那麼這個事務就認為語句是成功的,這時候全域性事務就會提交。二次提交協議,資料庫在第一次提交這個語句時,只會做預處理,不會發生真正的資料改變,當我們在全域性事務提交的時候,這時候發生了第二次提交,那麼第二次提交的時候才會真正的發生資料的改動。  
   如果說在執行這兩條語句中,有一個出錯了,那麼List集合裡就有個元素為false,那麼全域性事務就認為你這個事務是失敗的,它就會進行回滾,回滾的時候,哪怕你的第二條語句在第一次提交的時候是成功的,它在第二次提交的時候也會回滾,那麼第一次的更改也會恢復到之前的狀態,這就是二次提交協議。(可以檢視一下資料庫方面的文件來了解二次提交協議

===========================getCurrentSession()  和openSession()=======================

1、getCurrentSession()與openSession()的區別?

* 採用getCurrentSession()建立的session會繫結到當前執行緒中,而採用openSession(),建立的session則不會 * 採用getCurrentSession()建立的session在commit或rollback時會自動關閉,而採用openSession(),建立的session必須手動關閉 2、使用getCurrentSession()需要在hibernate.cfg.xml檔案中加入如下配置: * 如果使用的是本地事務(jdbc事務) <property name="hibernate.current_session_context_class">thread</property> * 如果使用的是全域性事務(jta事務)

<property name="hibernate.current_session_context_class">jta</property>

openSession() 與 getCurrentSession() 有何不同和關聯呢?

在 SessionFactory 啟動的時候, Hibernate 會根據配置建立相應的 CurrentSessionContext ,在getCurrentSession() 被呼叫的時候,實際被執行的方法是 CurrentSessionContext.currentSession() 。在currentSession() 執行時,如果當前 Session 為空, currentSession 會呼叫 SessionFactory 的 openSession 。所以 getCurrentSession() 對於 Java EE 來說是更好的獲取 Session 的方法。

相關推薦

SSH亂七八糟過濾器+攔截+監聽器

一些面試的知識點: 今天想著隨便寫點,為日後回憶做點準備: =======================過濾器和攔截器=================================================== 過濾器<filter>: 攔截器

過濾器/攔截/監聽器 —— Filter、Interceptor、Listener

在服務器 jsp ext resp 應用 改變 每次 常用 fff 一、Filter的功能 filter功能,它使用戶可以改變一個 request和修改一個response. Filter 不是一個servlet,它不能產生一個response,它能夠在一個request到

springboot(5)-- 過濾器 攔截 監聽器

一、過濾器 servlet3.0提供的註解 @WebFilter  @ServletComponentScan //註冊器名稱為customFilter,攔截的url為所有 @WebFilter(filterName="customFilter",urlPattern

SpringBoot 過濾器, 攔截, 監聽器 對比及使用場景

開發十年,就只剩下這套架構體系了! >>>   

web.xml 中的過濾器(攔截)Filter與監聽器Listener的作用和區別?

Servlet中的過濾器Filter是實現了javax.servlet.Filter介面的伺服器端程式,主要的用途是過濾字元編碼、做一些業務邏輯判斷等。其工作原理是,只要你在web.xml檔案配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(Re

廣州服務回收服務維護過程中,你需要了解的5個小常識

windows ron 就是 圖片 渲染 天都 驚人的 領域 其他人 大多數人認為,服務器僅僅是升級後的臺式機。但任何在數據中心工作過的人都知道,它們的差別挺大的。 盡管web服務器每天都要承擔數百萬訪問者的負載,但對於普通用戶來說,它們仍然神秘莫測。以下是關於服務器你可能

廣州服務租賃還在用虛擬主機?你的企業該在什麽時候該升級到專用服務呢?

ip地址 ces 優勢 現在 增加 升級服務器 com 解決 引擎 大多數小型企業通常都是從公有雲、虛擬主機這些常見的共享托管計劃開始的。因為相對來說,它是最經濟實惠的,而且需要較少的技術知識。 隨著業務的不斷拓展,網站流量越來愈大,對所需的服務器要求就越來越高。這時候就需

Spring 過濾器 攔截 AOP區別

簡介 這幾天在回顧Spring的AOP時,對過濾器,攔截器,AOP的關係有點好奇,故記錄做以備份。在實現一些公共邏輯的時候,很多功能通過過濾器,攔截器,AOP都能實現,但是不同的方式有不同的效率。具體有什麼區別,看下文描述。 前後端互動基本邏輯 過濾器 過濾器攔截

迭代模式—— 資料的遍歷

迭代器模式,提供了介面訪問容器中的元素,而不需要暴露容器的內部表現。 一、關鍵點 1)先看下這個模式點關鍵點: 遍歷:該模式的最大特點就是提供了遍歷內部集合資料的介面,從而達到訪問集合資料的目

閘道產品VPN防火牆技術原理

VPN產品中的PKI技術用於CA證書獲取,本地實體資訊配置及VPN證書的生成,目前主流產品有IPSecVPN和SSLVPN。 1、PKI技術是一套Internet安全解決方案,PKI體系結構採用證書管理公鑰,通過第三方的可信機構CA,把使用者的公鑰和使用者的其他標識資訊捆綁

unity編輯拓展使用指令碼新增Prefab到場景中

 有時候想自動將預製新增到場景中,但是又不想破壞預製的連結關係,這時候可以使用PrefabUtility類進行操作。 1、使用AssetDatabase.GetAssetPath獲取預製路徑 fore

過濾器+攔截+controller執行順序

專案啟動時初始化載入  Filter-initFilter--doFilter=====filterChain.dofilter();方法之前的程式執行 Interceptor--preHandle執行springMVC---Controller執行Interceptor--

責任鏈設計模式(過濾器/攔截)

       責任鏈設計模式(Chain of Responsibility)的應用有:Java Web中的過濾器鏈、springmvc中的攔截器鏈,Struts2中的攔截器棧等等。        先看如下一個問題:        給定一個字串“被就業了:),敏感資訊,&l

過濾器+攔截+vue的生命週期

目錄 1過濾器 全域性過濾器 區域性過濾器 2攔截器 3生命週期 建立 1過濾器 全域性過濾器         格式:第一個引數是過濾器名字,第二個是具體執行方法,方法的引數是即將載入渲染的資料         注意點:全

過濾器 攔截 controller 頁面 的執行順序

經過本人的最後測試得出的結論是 由於最近做的專案中有一部分是介面遠端呼叫,用到了接入許可權和業務許可權的鑑定,需要採用SpringMVC的攔截器,以前用Struts2的時候用過攔截器,而SpringMVC的攔截器功能之前沒研究過,所以這次來稍微研究一下,得出的結論是

過濾器,攔截適用場合

 過濾器,是在java web中,你傳入的request,response提前過濾掉一些資訊,或者提前設定一些引數,然後再傳入servlet或者struts的 action進行業務邏輯,比如過濾掉非法url(不是login.do的地址請求,如果使用者沒有登陸都過濾掉),

自動回帖/原理自動回帖的原理與實現(一)原理篇

自動回帖技術 前言:2012.9月,由於某些原因,我開始編寫一個基於Discuz論壇的自動回帖器,這次的小工作讓我對Cookie有了進一步的認識,充分認識到,利用它實在可以做太多的事了~啊哈哈~話不多說~進入主題吧! 0.驗證碼識別 3年前想做的驗證碼識別已經ok了,參

攔截過濾器實現單使用者登入

1、攔截器 package com.wkrj.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.sp

SpringBootRESTful API攔截-過濾器攔截、切片

前言 這裡瞭解一下restful api的攔截,文字主要介紹三種方式來對api進行攔截,參考本文可實現攔截api,進行一些附加操作,比如列印攔截到的方法所在類名,獲取原始的request,攔截到api

SpringSpringMVC之攔截

https javax request orm bin 支持 exceptio 賬號 intern Spring的HandlerMapping處理器支持攔截器應用。當需要為某些請求提供特殊功能時,例如實現對用戶進行身份認證、登錄檢查等功能。 攔截器必須實現HandlerI