Java Spring @Autowired - 实例化新 bean
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18973061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring @Autowired - Instantiate new bean
提问by isyndicate
Need some help with Spring autowiring, and scopes.
在 Spring 自动装配和范围方面需要一些帮助。
Here is the basic app structure:
这是基本的应用程序结构:
I have an CustomHttpClient, annotated as @Component, and also pulling some config-related properties from application.properties file (via @Value annotation).
CustomHttpClient is used by several services in my application. Whenever I'm using the CustomHttpClient, I autowire an instance of that via:
@Autowired private CustomHttpClient httpClient;
I use interceptor to modify some of the variables inside CustomHttpClient, like so:
public class MyInterceptor extends HandlerInterceptorAdapter { @Autowired CustomHttpClient httpClient; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { httpClient.setSomeProperty(newValue); ...
我有一个 CustomHttpClient,注释为 @Component,还从 application.properties 文件中提取了一些与配置相关的属性(通过 @Value 注释)。
CustomHttpClient 被我的应用程序中的几个服务使用。每当我使用 CustomHttpClient 时,我都会通过以下方式自动装配一个实例:
@Autowired private CustomHttpClient httpClient;
我使用拦截器来修改 CustomHttpClient 中的一些变量,如下所示:
public class MyInterceptor extends HandlerInterceptorAdapter { @Autowired CustomHttpClient httpClient; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { httpClient.setSomeProperty(newValue); ...
Now, here is the problem. If I have everything set up as described above, then whenever I change any setting of the CustomHttpClient via interceptor, that new value is persisted for all other clients, as long as VM is running. So when I run httpClient.setSomeProperty() - that setting is now permanently saved. Even if I connect to the application from another client.
现在,问题来了。如果我按照上述方式设置了所有内容,那么每当我通过拦截器更改 CustomHttpClient 的任何设置时,只要 VM 正在运行,该新值就会为所有其他客户端保留。因此,当我运行 httpClient.setSomeProperty() 时 - 该设置现在已永久保存。即使我从另一个客户端连接到应用程序。
Basically what I need to have are two things:
基本上我需要的是两件事:
- Still being able to override default settings of the CustomHttpClient via interceptor (request interceptor, configured via ).
- Make sure a new instance of CustomHttpClient is created for every request (after the interceptor does its' magic).
- 仍然能够通过拦截器(请求拦截器,通过 配置)覆盖 CustomHttpClient 的默认设置。
- 确保为每个请求创建一个新的 CustomHttpClient 实例(在拦截器发挥其作用之后)。
I tried changing the scope of CustomHttpClient to @Scope("prototype"), but that way I can no longer change settings of CustomHttpClient with an interceptor.
我尝试将 CustomHttpClient 的范围更改为 @Scope("prototype"),但这样我就无法再使用拦截器更改 CustomHttpClient 的设置。
采纳答案by Subin Sebastian
By default when you use @Autowired
spring bean scope is singleton. That means spring injects the same singleton object where ever you use @Autowired
. By making scope prototype
you are instructing Spring to create new objects for each @Autowired injection, and so in your interceptor will have its own copy of HttpClient and cant see other HttpClient objects.
默认情况下,当您使用@Autowired
spring bean 时,范围是单例。这意味着 spring 会在您使用的任何地方注入相同的单例对象@Autowired
。通过设置范围,prototype
您正在指示 Spring 为每个 @Autowired 注入创建新对象,因此在您的拦截器中将拥有自己的 HttpClient 副本并且无法看到其他 HttpClient 对象。
So better approach is use the singleton scope, Use request attributes or threadlocal to carry around your custom properties down the request thread. ie instead of modifying HttpClient properties in interceptor, just set some request attributes or threadlocals and handle these custom settings within CustomHttpClient
class methods.
所以更好的方法是使用单例范围,使用请求属性或线程本地在请求线程中携带您的自定义属性。即不是在拦截器中修改 HttpClient 属性,只需设置一些请求属性或线程局部变量并在CustomHttpClient
类方法中处理这些自定义设置。
回答by Vineet Kasat
If your interceptor is only addding some properties then using thread local should be a better option. You can call ThreadLocal.set(custom Map) and use it wherever you want for the running thread and when your program is going to leave your controller you can call ThreadLocal.Unset which will clear the value stored.
如果您的拦截器只是添加一些属性,那么使用线程本地应该是更好的选择。你可以调用 ThreadLocal.set(custom Map) 并在任何你想要运行的线程使用它,当你的程序要离开你的控制器时,你可以调用 ThreadLocal.Unset 这将清除存储的值。
This way you wont need a new instance of HttpcLient everytime, also a new instance every time would be a serious flaw. And you will be able to use your custom map anywhere you want in the running thread.
这样你就不会每次都需要一个 HttpcClient 的新实例,而且每次都需要一个新实例,这将是一个严重的缺陷。您将能够在运行线程中的任何位置使用您的自定义地图。
回答by Khush
All beans declared in the Spring container enther by XML or by annotation support are by default singletons. If you inject a bean with scope set to prototype into a singleton e.g. a controller it will inject it only once. There is a way to achieve this goal. This is how you should declare a bean scoped as a prototype. This means that the container will always give you a new instance each time this bean is called upon from the container.
在 Spring 容器中通过 XML 或注解支持声明的所有 bean 默认情况下都是单例。如果您将范围设置为原型的 bean 注入到单例中,例如控制器,它只会注入一次。有一种方法可以实现这一目标。这就是你应该如何声明一个范围为原型的 bean。这意味着每次从容器调用此 bean 时,容器将始终为您提供一个新实例。
<bean id="shoppingCart" class="example.ShoppingCart" scope="request">
<aop:scoped-proxy />
</bean>