Spring singleton@autowired服务和共享状态
我有一个控制器和一个过滤器,我在其中注入了一个特定的服务。 在该服务中,我有一个Hashmap,我试图在其中存储某些信息。我遇到的问题是,尽管似乎创建了该服务的一个实例并将其注入到我的控制器和过滤器中,但映射似乎有两个实例。我不知道为什么。无论我如何尝试实例化映射(或注入它),行为都是一样的 问题是创建并注入了两个服务实例,一个在控制器中,一个在过滤器中。我不清楚为什么会发生这种情况以及如何解决它 以下是代码的摘录:Spring singleton@autowired服务和共享状态,spring,applicationcontext,Spring,Applicationcontext,我有一个控制器和一个过滤器,我在其中注入了一个特定的服务。 在该服务中,我有一个Hashmap,我试图在其中存储某些信息。我遇到的问题是,尽管似乎创建了该服务的一个实例并将其注入到我的控制器和过滤器中,但映射似乎有两个实例。我不知道为什么。无论我如何尝试实例化映射(或注入它),行为都是一样的 问题是创建并注入了两个服务实例,一个在控制器中,一个在过滤器中。我不清楚为什么会发生这种情况以及如何解决它 以下是代码的摘录: @Controller public MyController {
@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);
}
}
@控制器
公共MyController{
@自动连线
私人MyService-MyService;
someEndpoint(){
....
putData(键、值);
.....
}
}
公共类MyFilter扩展了GenericFilterBean{
@自动连线
私人MyService-MyService;
公共过滤器(…){
//这就是我的问题所在。
//引用myService.myMap似乎指向另一个实例
//而不是控制器中的service.myMap,这对我来说没有任何意义
//过滤器显然会截取所有请求,因此我希望在这之后
//访问端点时,数据将在那里用于后续请求
myService.getData(…);
}
.....
}
@服务
公共类MyService{
私有映射myMap=newhashmap();
公共字符串getData(字符串键){
返回myMap.get(key);
}
公共数据(字符串键、字符串值){
myMap.put(键、值);
}
}
下面是app-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"/>
.......
GenericFilterBean不在应用程序上下文中。我希望上面的代码中包含java.lang.InstanceionException。您可以通过过滤器的ServletContext获取bean。任何其他实例化技巧都会导致映射重复。您确定只创建了一个MyService类实例吗?检查这一点的最简单方法是提供默认构造函数实现并在其中打印一些文本。请检查一下,让我知道,因为我有一些怀疑
如果这是真的,并且MyService类有两个实例,那么当您将一些数据放入map时,您可能使用MyService的实例A,当您从map获取数据时,您使用MyService的实例B。。。我将等待您的响应以继续/停止这种思考。在您的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
org.springframework.web.servlet.DispatcherServlet
上下文配置位置
/WEB-INF/app-config.xml
1.
它创建一个由servlet启动的web应用程序上下文
那么你还有:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
上下文配置位置
/WEB-INF/app-config.xml
它还创建了一个父根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>
调度器Servlet
org.springframework.web.servlet.DispatcherServlet
上下文配置位置
1.
小心点。不要忽略该参数。Spring会根据您的servlet推断出一些默认配置文件名,如果它不存在,它会抱怨。这是我的第一个想法,但正如我在上面的问题中提到的,MyService的同一个实例被注入。所以这不是问题的根源。你能详细解释一下“GenericFilter不在应用程序上下文中”是什么意思吗?我确实在我的应用程序上下文中定义了MyFilter,而且我没有得到任何实例化异常……因此,这意味着您有两个不同的上下文。这就是为什么有两个实例。在您的代码中,服务和控制器都有注释,但过滤器没有注释。根据GenericFilter的思想,它不应该在应用程序上下文中。那个么为什么/如何创建两个上下文呢?我没有注释过滤器,因为我在我的应用程序配置中定义了它(参见上面的编辑)。我必须在应用程序上下文中定义它,因为它被其他元素引用。您有多少上下文?你能发布你的web.xml吗?还有上下文配置?谢谢。你的评论为我指明了正确的方向。我无法按照您上面的建议解决问题,因为这会破坏控制器中的映射,因此我创建了两个单独的配置文件,并将其中一个传递给DispatcherServlet。