如何在方法调用中实例化一个新 bean?
How do I instantiate a new bean in a method call?
我有这样的东西:
@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 Controller 是会话范围的,但是每个请求都需要实例化一个新的 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);
}
[...] but each request needs to instantiate a new QueryRunner as to not have any interference if multiple requests are sent at once
您的设置已经做到了。您的 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 将在 ThreadLocal
上下文中存储对 HttpServletRequest
的引用,可通过 static
实用程序访问 class。它将实际的 bean 存储在 HttpServletRequest
属性中。
当您最终在代理(存储在 `@Autowired 字段中)上调用 runQuery
时,Spring 将首先检查现有 bean 的上下文。如果找到一个,它将使用它来调用您的方法。如果没有,它将初始化一个新实例,将其存储在上下文中,然后使用它。这样,前面的例子
Result r1 = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
Result r2 = queryRunner.runQuery(sessionId, request.getParameter("evenmoredata"));
实际上是在同一个 QueryRunner
实例上调用 runQuery
。
由于 HttpServletRequest
属性在每次请求后都会被清除,因此您的请求范围的 bean 实例也会被清除。
我有这样的东西:
@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 Controller 是会话范围的,但是每个请求都需要实例化一个新的 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);
}
[...] but each request needs to instantiate a new QueryRunner as to not have any interference if multiple requests are sent at once
您的设置已经做到了。您的 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 将在 ThreadLocal
上下文中存储对 HttpServletRequest
的引用,可通过 static
实用程序访问 class。它将实际的 bean 存储在 HttpServletRequest
属性中。
当您最终在代理(存储在 `@Autowired 字段中)上调用 runQuery
时,Spring 将首先检查现有 bean 的上下文。如果找到一个,它将使用它来调用您的方法。如果没有,它将初始化一个新实例,将其存储在上下文中,然后使用它。这样,前面的例子
Result r1 = queryRunner.runQuery(sessionId, request.getParameter("otherdata"));
Result r2 = queryRunner.runQuery(sessionId, request.getParameter("evenmoredata"));
实际上是在同一个 QueryRunner
实例上调用 runQuery
。
由于 HttpServletRequest
属性在每次请求后都会被清除,因此您的请求范围的 bean 实例也会被清除。