如何在方法调用中实例化新bean?

时间:2015-07-14 22:28:11

标签: java spring instantiation

我有这样的事情:

@Controller
@Scope("session")
public class MyServletController {



    @Autowired
    private QueryRunner queryRunner;

    HashMap<String, Result> resultsMap; 

    @RequestMapping("/submitQuery")
    public ModelAndView submitQuery(HttpServletRequest request)
    {
    String sessionId = request.getParameter("sessionId");
    Result r = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
    resultsMap.put(sessionId, r);
    }



    @RequestMapping("/getResult")
    @ResponseBody
    public void saveTextLinks(HttpServletRequest request,
            HttpServletResponse response) throws IOException
    {
     String sessionId = request.getParameter("sessionId");      
     //return sessionId result from resultsMap
    }

 }


<bean id="queryRunner"
    class="com.myproject.QueryRunner"
    scope="prototype">
    <aop:scoped-proxy />


    <property name="errorMessageA" value="${error.messagea}"></property>
    <property name="errorMessageB" value="${error.messageb}"></property>

</bean>

我想要的是Servlet控制器是会话范围的,但是如果一次发送多个请求,每个请求都需要实例化一个新的QueryRunner,以便没有任何干扰。

如何配置Spring来执行此操作?

诱人的解决方案就是:

    @RequestMapping("/submitQuery")
    public ModelAndView submitQuery(HttpServletRequest request)
    {
    queryRunner = new QueryRunner(); //<-----
    String sessionId = request.getParameter("sessionId");
    Result r = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
    resultsMap.put(sessionId, r);
    }

1 个答案:

答案 0 :(得分:1)

  

[...]但是每个请求都需要实例化一个新的QueryRunner,以便在一次发送多个请求时没有任何干扰

您的设置已经这样做了。您的QueryRunner bean被声明为

<bean id="queryRunner"
    class="com.myproject.QueryRunner"
    scope="prototype">
    <aop:scoped-proxy />

这意味着Spring会在请求这样的bean的地方注入代理,例如

@Autowired
private QueryRunner queryRunner;

并且代理将在内部每次都将所有调用委托给新初始化的bean。请注意,这意味着如果您执行类似

的操作
Result r1 = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
Result r2 = queryRunner.runQuery(sessionId, request.getParameter("evenmoredata"));

每个runQuery次调用都在不同的QueryRunner个实例上调用。

如果您想拥有一个跨越请求的整个生命周期的QueryRunner bean,只需将bean声明为具有请求范围

<bean id="queryRunner"
    class="com.myproject.QueryRunner"
    scope="request">
    <aop:scoped-proxy />

在幕后(假设默认的MVC配置),Spring将在HttpServletRequest上下文中存储对ThreadLocal的引用,该上下文可通过static实用程序类访问。它会将实际的bean存储在HttpServletRequest属性中。

当你最终在代理上调用runQuery(存储在`@Autowired字段中)时,Spring将首先检查现有bean的上下文。如果找到一个,它将使用它来调用你的方法。如果它没有,它将初始化一个新实例,将其存储在上下文中,然后使用它。这样,前面的例子

Result r1 = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
Result r2 = queryRunner.runQuery(sessionId, request.getParameter("evenmoredata"));

实际上是在同一个runQuery实例上调用QueryRunner

由于HttpServletRequest属性在每次请求后被清除,因此请求范围的bean实例也将被清除。