Java Spring@Autowired-实例化新bean

Java Spring@Autowired-实例化新bean,java,spring,spring-mvc,autowired,Java,Spring,Spring Mvc,Autowired,需要一些关于Spring自动布线和范围的帮助 以下是应用程序的基本结构: 我有一个CustomHttpClient,注释为@Component,还从application.properties文件(通过@Value注释)中提取一些与配置相关的属性 CustomHttpClient由我的应用程序中的多个服务使用。每当我使用CustomHttpClient时,我都会通过以下方式自动连接该客户端的实例: @Autowired private CustomHttpClient httpClient;

需要一些关于Spring自动布线和范围的帮助

以下是应用程序的基本结构:

  • 我有一个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);
    ...
    
  • 现在,问题来了。若我已按上述方式设置了所有内容,那个么每当我通过拦截器更改CustomHttpClient的任何设置时,只要VM正在运行,那个新值就会为所有其他客户端保留。因此,当我运行httpClient.setSomeProperty()时,该设置现在被永久保存。即使我从另一个客户端连接到应用程序

    基本上我需要有两样东西:

  • 仍然能够通过拦截器(请求拦截器,通过配置)覆盖CustomHttpClient的默认设置
  • 确保为每个请求创建CustomHttpClient的新实例(在拦截器执行其“魔术”之后)

  • 我尝试将CustomHttpClient的作用域更改为@scope(“prototype”),但这样我就无法再使用拦截器更改CustomHttpClient的设置。

    如果拦截器只是添加一些属性,那么使用线程本地应该是更好的选择。您可以调用ThreadLocal.set(自定义映射)并在运行线程的任何地方使用它,当程序将离开控制器时,您可以调用ThreadLocal.Unset,这将清除存储的值


    这样,您就不需要每次都需要一个新的HttpcLient实例,而且每次都需要一个新实例也是一个严重的缺陷。您可以在运行线程中的任何位置使用自定义映射。

    默认情况下,当您使用
    @Autowired
    时,Springbean的作用域为singleton。这意味着spring将在您使用
    @Autowired
    时注入相同的单例对象。通过制作scope
    prototype
    ,您指示Spring为每个@Autowired注入创建新对象,因此在您的拦截器中将有自己的HttpClient副本,并且看不到其他HttpClient对象


    所以更好的方法是使用singleton作用域,使用请求属性或threadlocal在请求线程中携带自定义属性。ie没有在拦截器中修改HttpClient属性,只需设置一些请求属性或threadlocals,并在
    CustomHttpClient
    类方法中处理这些自定义设置。

    Spring容器中通过XML或注释支持声明的所有bean默认为单例。如果将作用域设置为prototype的bean注入到单例(例如控制器)中,它将只注入一次。有一种方法可以实现这一目标。这就是您应该如何声明范围为原型的bean。这意味着每次从容器调用这个bean时,容器都会给您一个新实例

    <bean id="shoppingCart" class="example.ShoppingCart" scope="request">
         <aop:scoped-proxy />
    </bean>
    
    
    
    我可能错了,但我认为如果您需要为这个原型可重用组件进行注入,则设计可能存在缺陷,您需要根据请求修改其属性。如果您手动控制创建和销毁,可能是最好的。毕竟,并不是所有的对象都应该被注入。嗯,这可能是一个很好的观点。但是如果我不自动连线并注入组件,我还能用拦截器调整它的属性吗?假设我无法控制使用该组件的实际服务,只能通过HTTP头和/或查询字符串参数调整某些属性。这就是我使用自动连线的主要原因。如果您只需要调整标题和/或参数,为什么不修改
    HttpServletRequest
    /
    HttpServletResponse
    ?这就是为什么它们可以在拦截器中使用的原因。修改请求将是理想的,但我认为如果不先自动连接,就无法进入CustomHttpClient的请求范围。如果我将新的头设置为HttpServletRequest对象,那么它就是这样做的,但是我需要对底层组件进行更多的处理,因为CustomHttpClient所在的位置。@isyndicate我已经为您提供了答案。请在审阅后提供一些反馈。让我知道这是否对您有效。
    ThreadLocal
    似乎是解决此问题的一种非常严厉的方法。如果您要使用线程局部变量,您必须确保取消设置它们(我指的是必须非常小心并考虑使用finally块)。@Aurand Ya您需要确保取消设置线程局部变量的值,这可以通过创建一个自定义的会话保持器来轻松确保,该会话保持器可以在进入和退出时调用。但这在易访问性方面提供了优势。正如我在问题中提到的,我尝试使用prototype scope,但这与通过拦截器自动连接和注入属性的目的背道而驰。因为,作为一个原型,每次都会创建一个新的实例,因此不会对拦截器进行任何更改。