2014-10-31 56 views
1

我有一個控制器和一個過濾器,我在其中注入一個特定的服務。 在那個服務中我有一個Hashmap,我嘗試存儲某些信息。我遇到的問題是,雖然看起來該服務的單個實例已創建並注入到我的控制器和我的過濾器中,但似乎有兩個Map實例。我爲什麼不知所措。無論我如何嘗試實例化地圖(或注入地圖),行爲仍然是相同的。Spring singleton @autowired服務和共享狀態

事實證明,問題是創建了兩個服務實例,並在控制器中注入了一個實例,在過濾器中注入了一個實例。我不清楚爲什麼會發生這種情況,以及如何解決它。

以下是代碼的提取物:

@Controller 
public MyController { 



    @Autowired 
    private MyService myService; 


    someEndpoint() { 
    .... 
    myService.putData(key, value); 
    ..... 
    } 


} 


public class MyFilter extends GenericFilterBean { 


    @Autowired 
    private MyService myService; 


    public void doFilter(...) { 

    //this is where I have a problem. 
    // the reference myService.myMap seems to be pointing to a different instance 
    // than the service.myMap in the controller which doesn't make any sense to me 
    // the filter obviously intercepts all requests so I would expect that after that particular 
    // endpoint is accessed the data will be there for subsequent requests 
    myService.getData(..); 

    } 

    ..... 
} 


@Service 
public class MyService { 


    private Map <String,String> myMap = new HashMap <String,String>(); 


    public String getData(String key) { 
    return myMap.get(key); 
    } 

    public void putData(String key, String value){ 
    myMap.put(key,value); 
    } 


} 

這裏是應用程序-config.xml中

<?xml version="1.0" encoding="utf-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xmlns:security="http://www.springframework.org/schema/security" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
          http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> 

    <context:component-scan base-package="com.mycompany.myPackage"/> 
    <context:annotation-config /> 


    ....... 

    <security:http 
    ........ 
    ........ 
    <security:custom-filter ref="myFilter" position="FORM_LOGIN_FILTER" /> 
    .... 


    ........... 

    <bean class="com.mycompany.filters.MyFilter" id="myFilter"/> 

和web.xml中的提取物

<context-param> 
 
     <param-name>contextConfigLocation</param-name> 
 
     <param-value>/WEB-INF/app-config.xml</param-value> 
 
    </context-param> 
 
    <listener> 
 
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
 
    </listener> 
 

 

 
    <servlet> 
 
     <servlet-name>Dispatcher Servlet</servlet-name> 
 
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
 
     <init-param> 
 
      <param-name>contextConfigLocation</param-name> 
 
      <param-value>/WEB-INF/app-config.xml</param-value> 
 
     </init-param> 
 
     <load-on-startup>1</load-on-startup> 
 
    </servlet> 
 

 

 
    <servlet-mapping> 
 
     <servlet-name>Dispatcher Servlet</servlet-name> 
 
     <url-pattern>/webservice/*</url-pattern> 
 
    </servlet-mapping> 
 

 
<filter> 
 
    <filter-name>springSecurityFilterChain</filter-name> 
 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
 
</filter> 
 
<filter-mapping> 
 
    <filter-name>springSecurityFilterChain</filter-name> 
 
    <url-pattern>/*</url-pattern> 
 
</filter-mapping>

任何幫助,非常感謝。

+0

你有多少上下文?你可以發佈你的web.xml嗎?還有上下文配置? – grid 2014-11-01 09:45:25

回答

0

GenericFilterBean不在應用程序上下文中。我希望在上面的代碼java.lang.InstantiationException。您可以通過過濾器的ServletContext獲得您的bean。任何其他實例化技巧都會導致地圖重複。

+0

您能否詳細說明您的意思是「GenericFilter不在應用程序上下文中」?我在我的應用程序上下文中定義了MyFilter,並且沒有得到任何實例化例外...... – 2014-10-31 23:01:48

+0

所以,這意味着您有兩個不同的上下文。這就是爲什麼你有兩個實例。在你的代碼中,服務和控制器是註釋的,但過濾器不是。通過** GenericFilter **的想法,它不應該在應用程序上下文中。 – Dmytro 2014-11-01 12:56:44

+0

那麼爲什麼/如何創建兩個上下文?我沒有註釋過濾器,因爲我在我的app-config中定義了它(參見上面的編輯)。我必須在應用程序上下文中定義它,因爲它被其他元素引用。 – 2014-11-02 22:41:23

0

你確定只有一個MyService類的實例被創建嗎?檢查這個最簡單的方法是提供默認的構造函數實現並在其中打印一些文本。請檢查一下,讓我知道,因爲我有一些懷疑。

如果這是真的,有的MyService類的兩個實例,有可能當你把一些數據映射,您使用的MyService的實例的,當你從地圖上獲取數據使用實例B我的服務 ...我會等待你的迴應繼續/停止這種想法。

+0

這是我的第一個想法,但正如我在上面提到的問題中提到的同一個MyService實例注入。所以這不是問題的根源。 – 2014-10-31 22:19:31

1

在你的web.xml設置:

<servlet> 
    <servlet-name>Dispatcher Servlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/app-config.xml</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

這會創建你的servlet發起一個Web應用程序上下文。

那麼你也有:

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>/WEB-INF/app-config.xml</param-value> 
</context-param> 

這也創造了一個父根Web應用程序上下文,你的情況重複一個。 正確使用此方案有利於您可能擁有更多servlet的情況,每個servlet都定義了它自己的獨立上下文,但是從通用根上下文(服務,數據源等)繼承了bean定義。它還爲創建分層上下文提供了一個很好的實踐路線圖,即防止您的服務bean依賴於您的mvc層。

除非你有一個以上的配置文件,您應該空值分配給你的servlet配置的contextConfigLocation的是:

<servlet> 
    <servlet-name>Dispatcher Servlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value></param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

要小心。不要忽略參數。 Spring會根據你的servlet推斷出一些默認的配置文件名,如果它不存在就會投訴。

+0

謝謝。您的評論指出了我的正確方向。我無法解決上述問題,因爲這會破壞控制器中的映射,所以我創建了兩個單獨的配置文件,將一個配置文件傳遞給DispatcherServlet。 – 2014-11-03 18:29:28