简体   繁体   中英

How do I instantiate a new bean in a method call?

I have something like this:

@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>

What I want is that the Servlet Controller is session scoped, but each request needs to instantiate a new QueryRunner as to not have any interference if multiple requests are sent at once.

How do I configure Spring to do this?

The tempting solution is to just go:

    @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

Your setup already does that. Your QueryRunner bean is declared as

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

This means that Spring will inject a proxy wherever such a bean is requested, for example

@Autowired
private QueryRunner queryRunner;

and the proxy will, internally, delegate all calls to newly initialized beans every time. Note that this means that if you do something like

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

each of those runQuery calls are, underneath it all, invoked on different QueryRunner instances.

If you want to have a single QueryRunner bean that spans the entire lifecycle of a request, just declare the bean to have the request scope

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

Behind the scenes (assuming the default MVC configuration), Spring will store a reference to the HttpServletRequest in a ThreadLocal context accessible through a static utility class. It will store the actual bean in the HttpServletRequest attributes.

When you eventually invoke runQuery on the proxy (which is stored in the `@Autowired field), Spring will first check the context for a existing bean. If it finds one, it will use it to invoke your method. If it doesn't, it will initialize a new instance, store it in the context, then use it. This way, the previous example

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

is actually invoking runQuery on the same QueryRunner instance.

Since HttpServletRequest attributes are cleared after each request, so will your request-scoped bean instances.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM